- Pragmatic Craftsmanship (see The Pragmatic Programmer, Code Complete)
- The #1 primary mandate of the software engineer is managing complexity
- Simple, small, consistent tools
- Small languages that foster consistency such as Python, jade
- One and preferably only one good way to do it
- Significant white space fosters consistency, so I am in favor of it
- Small core library plus good package management such as node.js with npm
- Big, complex, heterogeneous languages like Perl and Ruby aren't compatible with my general orientation (but I will code in Ruby when appropriate)
- Correctness and clarity are king
- readability and maintainability are more important than brevity
- Clever is bad. Period.
- Remove all magic (see Django Pony)
- Libraries over frameworks
- My code invokes library methods
- No "your code goes here" boilerplate
- Right tool for the right job
- Slow, calm, and correct
- I build working software that is well-crafted
- Components Should Be Focused, Independent, Reusable, Small & Testable (FIRST)
See also my code conventions
- Default attitude is traditional referential integrity with transactions and strict expectations of data consistency and durability
- Sacrifice consistency, integrity or durability to get performance or convenience when warranted
- Properly coding for collections of data where individual records can vary greatly is difficult. Stick with consistent records.
- Disciplined data migrations should be part of the normal development process
- Each field and record has perpetual maintainance cost
- Only add more data when clearly driven by current features
- Prune stale data as early as possible
- Conform to common system model in end-user terms
- Avoid abstractions
- Keep naming clear and consistent with the system model and user interface
- Model collections based on semantics as opposed to raw data similarity
- Multi-paradigm taking the best elements of functional, procedural, object oriented
- Functional programming is the dominant paradigm in my mind these days
- Pure functional with no side effects has great testability
- I think more about data and functions being separate these days as opposed to Object Oriented coupling of the two
- Use built-in data structures (lists, maps) for simple cases, but go to objects as soon as it is non-trivial
- Encapsulation and composition as opposed to complex inheritence hierarchy
- Prefer basic procedural conditions and loops when they are clearer than complex functional or object oriented patterns
- Lots of thorough pure unit tests. Fast (no I/O). High code coverage.
- Modular code. Judicious use of mock objects. Dependency injection.
- Factories as opposed to fixtures
- Test only the first-party code written for this application
- A small handful of end to end system tests
- If running tests gets slow, it's probably time to split the project into smaller modules
- I don't subscribe entirely to any specific methodology
- There are good ideas and practices in Agile, Scrum, KanBan, Lean, etc
- Most of my projects don't lend themselves to a formal methodology
- Key things I focus on
- Working, deployed software as the core deliverable
- Small sprints (usually weekly)
- Some reasonable project management tool other than email
- Stakeholder prioritizes the work to be done in conversation with developers
- Modern Async
- Read The Async Manifesto
- Note in this context the word "asnyc" means something very different from "async" in terms of node.js non-blocking programming.
- Avoid them as much as possible
- Build trust based on past performance instead
- When unavoidable, keep it simple: small, medium, large
- Work items must be decomposed until they fit in a single sprint (there is no extra large)
- Lean Startup/Minimum Viable Product. Launch and learn. Rinse and repeat.
Deployment and Operations
- Clear and fully independent development, QA, stage, production environments from day one
- Should be able to rebuild entire app infrastructure with code and docs in the main source code repository
- Semantic Versioning
- Modified 12-Factor principles
Definition and purpose of a stage environment
- Reduce risk that new releases will disrupt production
- In order to deliver this, stage must be entirely separate from production. No sharing of any resources whatsoever with production.
- Create high confidence that new releases will deploy and function correctly
- If it deploys and runs OK on stage, we have very high confidence that it will deploy and run OK on prod.
- In order to deliver this, stage must be nearly-identical to production
- Provide safe environment to reproduce and troubleshoot production issues
- Ideally this would be a third environment dedicated to troubleshooting, but in practice resolving production issues takes priority over testing new releases thus both are conducted in a single stage environment.
- Need to be able to reproduce issues to have hope of resolving them. However, attempting to reproduce in production creates wreckless risk of further issues.
- In order to deliver high probability of reproducing issue off production, stage must be nearly-identical to production
- Want to know if it happens in production, it can be reproduced in staging, and if a change fixes an issue in stage, that same change will fix the issue in production.
- In order to deliver this, staging must nearly-always be available in a state exactly matching production. Thus stage must not be used for functional testing or QA of releases. Stage should only be used as a final quick verification that the release is deployed to stage and the new features are passing quick smoke tests. Thorough testing and QA should be done in a dedicated enironment distinct from stage.