Good programmers write code that humans can understand
The Integration Problem
When combining units into a product (after testing each unit individually), problems occur with integration:
- Conflicting dependencies
- Badly-defined or -specified APIs
Diagnosis gets harder as more units are combined.
Continuous Integration
Working software is the primary measure of progress
Agile Manifesto, 7th Principle
Integrate as you develop; when a story or unit is ready, integrate it immediately with master.
The smaller a chunk of code is, the easier it is to test and the easier it is to integrate.
Fowler’s Principles
- Single source repository
- Automate the build process
- Make the build self-testing
- Everyone commits to master/main every day
- Every commit trigger a build on an integration machine
- Broken builds should be fixed immediately
- Keep the build fast
- Test in a clone of the production environment
- Make it easy for everyone to get the latest executable
- Ensure everyone can see what is happening
- Automate the deployment phase
Single Source Repository
All code and resources should be in a single place:
- Team may be decentralized
- Centralizes traceability of changes
Version Control:
- Centralized; one master repository e.g. subversion
- One main trunk, branches available
- Distributed; two levels of commit e.g. git
Driessen’s Branching and Merging Strategy
- Master: production-ready branch
- Development: branch for in-progress work
- Implementation: branches for each story/feature
- Once feature done, merge dev to feature branch
- Peer review, then merge to dev
- Hotfix: branch for a particular bug fix. Merge to master, dev and release
- Release: branch for a particular release
- Run smoke tests etc.
Everyday Commits
- Commit any meaningful progress
- Your machine may die; don’t lose valuable work
- Make commit messages meaningful
- Allows the team to see your progress
- If your code does not build
- Push partial implementations
- Evaluate if the task was under-estimated
Merge Requests and Code Review
Ensure:
- Code is readable
- Proper naming, documentation
- Meets expected quality
- Has unit/acceptance tests
- Has configuration/migration scripts
- Won’t cause security/compatibility problems
- Code does what it is expected to do
- Commit message makes sense and describes what it does
Merge requests increases cross-functional knowledge and helps with onboarding.
When leaving feedback, be open-minded:
- Reviewer’s logic is different from author’s logic
- If you’re confrontational, nothing will happen (or bad things will happen)
- Give suggestions to make it better, not just criticism
- Look for abstractions that can be added or removed
- Look for duplications with the existing code base
- Be critical when new dependencies are added
- Check unit/acceptance tests!
As a reviewee, remember that comments are made against the code, not you.
Be constructive and positive in giving feedback; point out what they have done right.
Managing Builds
Build after every commit. To reduce the burden of manual configuration, create automation scripts and use an integration server accessible to the team.
Self-testing: automate the build with upfront tests.
To make builds faster:
- Run only a subset of tests
- Use fake stubs to mock external services/resources
- Run tests asynchronously
Make a snapshot of the latest stable build accessible to the team.
Automated Deployments
Requires the deployment to be scripted.
Requires rollback scripts too:
- Unexpected error - even if it is tested on a clone, errors can occur
- Users can inadvertently trigger edge cases and bugs