|
1 | 1 | --- |
2 | 2 | title: Continuous Integration |
3 | | -description: Start here |
| 3 | +description: Integrate work to trunk at least daily with automated testing |
4 | 4 | weight: 2 |
5 | 5 | type: docs |
6 | 6 | --- |
7 | 7 |
|
8 | 8 | ## Definition |
9 | 9 |
|
10 | | -While CI depends on tooling, the team workflow and working agreement are more important. |
| 10 | +Continuous Integration (CI) is the activity of each developer integrating work to the trunk of version control at least daily and verifying that the work is, to the best of our knowledge, releasable. |
11 | 11 |
|
12 | | -1. We will work as a team to define work with [testable acceptance criteria](https://dojoconsortium.org/docs/work-decomposition/behavior-driven-development/). Those acceptance criteria will drive our testing efforts. |
13 | | -2. No work will be committed to version control unless accompanied by all required tests. |
14 | | -3. Work committed to version control may not be "feature complete", but it must not break existing work. |
15 | | -4. All work begins from the trunk and integrates into the trunk at least daily. |
16 | | -5. If the CI server detects an error, the team stops feature work and collaborates to fix the build. We should not create more unverified changes without the ability to receive quality feedback from the CI server. |
| 12 | +CI is not just about tooling—it's fundamentally about team workflow and working agreements. |
17 | 13 |
|
18 | | -## Recommended practices |
| 14 | +### The minimum activities required for CI |
19 | 15 |
|
20 | | -Evolutionary coding methods: |
| 16 | +1. [Trunk-based development](/minimumcd/tbd/) - all work integrates to trunk |
| 17 | +2. Work integrates to trunk at a minimum daily (each developer, every day) |
| 18 | +3. Work has automated testing before merge to trunk |
| 19 | +4. Work is tested with other work automatically on merge |
| 20 | +5. All feature work stops when the build is red |
| 21 | +6. New work does not break delivered work |
21 | 22 |
|
22 | | -- [Branch by abstraction](https://www.branchbyabstraction.com/) is a good process for replacing existing new behaviors or frameworks with something new while constantly delivering. Also, a good pattern to use for A/B testing |
23 | | -- [Feature flags](https://martinfowler.com/articles/feature-toggles.html) can be temporary tools for feature release management or permanent tools for enabling behaviors for different personas. They can also be controlled with application configuration or dynamically with logic. |
| 23 | +## Why This Matters |
| 24 | + |
| 25 | +### Without CI, Teams Experience |
| 26 | + |
| 27 | +- **Integration hell**: Weeks or months of painful merge conflicts |
| 28 | +- **Late defect detection**: Bugs found after they're expensive to fix |
| 29 | +- **Reduced collaboration**: Developers work in isolation, losing context |
| 30 | +- **Deployment fear**: Large batches of untested changes create risk |
| 31 | +- **Slower delivery**: Time wasted on merge conflicts and rework |
| 32 | +- **Quality erosion**: Without rapid feedback, technical debt accumulates |
| 33 | + |
| 34 | +### With CI, Teams Achieve |
| 35 | + |
| 36 | +- **Rapid feedback**: Know within minutes if changes broke something |
| 37 | +- **Smaller changes**: Daily integration forces better work breakdown |
| 38 | +- **Better collaboration**: Team shares ownership of the codebase |
| 39 | +- **Lower risk**: Small, tested changes are easier to diagnose and fix |
| 40 | +- **Faster delivery**: No integration delays blocking deployment |
| 41 | +- **Higher quality**: Continuous testing catches issues early |
| 42 | + |
| 43 | +## Team Working Agreements |
| 44 | + |
| 45 | +While CI depends on tooling, the team workflow and working agreement are more important: |
| 46 | + |
| 47 | +1. **Define testable work**: Work includes [testable acceptance criteria](https://dojoconsortium.org/docs/work-decomposition/behavior-driven-development/) that drive testing efforts |
| 48 | +2. **Tests accompany commits**: No work committed to version control without required tests |
| 49 | +3. **Incremental progress**: Committed work may not be "feature complete", but must not break existing work |
| 50 | +4. **Trunk-based workflow**: All work begins from trunk and integrates to trunk at least daily |
| 51 | +5. **Team commitment**: If CI detects an error, the team stops feature work and collaborates to fix the build |
| 52 | + |
| 53 | +## Example Implementations |
| 54 | + |
| 55 | +### Anti-Pattern: Feature Branch Workflow Without CI |
| 56 | + |
| 57 | +```text |
| 58 | +Developer A: feature-branch-1 (3 weeks of work) |
| 59 | +Developer B: feature-branch-2 (2 weeks of work) |
| 60 | +Developer C: feature-branch-3 (4 weeks of work) |
| 61 | +
|
| 62 | +Week 4: Merge conflicts, integration issues, broken tests |
| 63 | +Week 5: Still fixing integration problems |
| 64 | +Week 6: Finally stabilized, but lost 2 weeks to integration |
| 65 | +``` |
| 66 | + |
| 67 | +**Problems:** |
| 68 | + |
| 69 | +- Long-lived branches accumulate merge conflicts |
| 70 | +- Integration issues discovered late |
| 71 | +- No early feedback on compatibility |
| 72 | +- Large batches of untested changes |
| 73 | +- Team blocked while resolving conflicts |
| 74 | + |
| 75 | +### Good Pattern: Continuous Integration to Trunk |
| 76 | + |
| 77 | +```yaml |
| 78 | +# .github/workflows/ci.yml |
| 79 | +name: Continuous Integration |
| 80 | + |
| 81 | +on: |
| 82 | + push: |
| 83 | + branches: [main] |
| 84 | + pull_request: |
| 85 | + branches: [main] |
| 86 | + |
| 87 | +jobs: |
| 88 | + test: |
| 89 | + runs-on: ubuntu-latest |
| 90 | + steps: |
| 91 | + - uses: actions/checkout@v3 |
| 92 | + |
| 93 | + - name: Install dependencies |
| 94 | + run: npm ci |
| 95 | + |
| 96 | + - name: Run unit tests |
| 97 | + run: npm test |
| 98 | + |
| 99 | + - name: Run integration tests |
| 100 | + run: npm run test:integration |
| 101 | + |
| 102 | + - name: Code quality checks |
| 103 | + run: npm run lint |
| 104 | + |
| 105 | + - name: Security scan |
| 106 | + run: npm audit |
| 107 | + |
| 108 | + - name: Build application |
| 109 | + run: npm run build |
| 110 | + |
| 111 | + notify-on-failure: |
| 112 | + needs: test |
| 113 | + if: failure() |
| 114 | + runs-on: ubuntu-latest |
| 115 | + steps: |
| 116 | + - name: Notify team |
| 117 | + run: | |
| 118 | + echo "Build failed - stop feature work and fix!" |
| 119 | + # Send Slack/email notification |
| 120 | +``` |
| 121 | +
|
| 122 | +**Benefits:** |
| 123 | +
|
| 124 | +- Changes tested within minutes |
| 125 | +- Team gets immediate feedback |
| 126 | +- Small changes are easy to debug |
| 127 | +- Integration is never a surprise |
| 128 | +- Quality maintained continuously |
| 129 | +
|
| 130 | +## Evolutionary Coding Practices |
| 131 | +
|
| 132 | +To integrate code daily while building large features, use these patterns: |
| 133 | +
|
| 134 | +### Branch by Abstraction |
| 135 | +
|
| 136 | +Gradually replace existing behavior while continuously integrating: |
| 137 | +
|
| 138 | +```javascript |
| 139 | +// Step 1: Create abstraction (integrate to trunk) |
| 140 | +class PaymentProcessor { |
| 141 | + process(payment) { |
| 142 | + return this.implementation.process(payment) |
| 143 | + } |
| 144 | +} |
| 145 | + |
| 146 | +// Step 2: Add new implementation alongside old (integrate to trunk) |
| 147 | +class StripePaymentProcessor { |
| 148 | + process(payment) { |
| 149 | + // New Stripe implementation |
| 150 | + } |
| 151 | +} |
| 152 | + |
| 153 | +// Step 3: Switch implementations (integrate to trunk) |
| 154 | +const processor = useNewStripe |
| 155 | + ? new StripePaymentProcessor() |
| 156 | + : new LegacyProcessor() |
| 157 | + |
| 158 | +// Step 4: Remove old implementation (integrate to trunk) |
| 159 | +``` |
| 160 | +
|
| 161 | +### Feature Flags |
| 162 | +
|
| 163 | +Control feature visibility without blocking integration: |
| 164 | +
|
| 165 | +```javascript |
| 166 | +// Incomplete feature integrated to trunk, hidden behind flag |
| 167 | +if (featureFlags.newCheckout) { |
| 168 | + return renderNewCheckout() // Work in progress |
| 169 | +} |
| 170 | +return renderOldCheckout() // Stable existing feature |
| 171 | + |
| 172 | +// Team can continue integrating newCheckout code daily |
| 173 | +// Feature revealed when complete by toggling flag |
| 174 | +``` |
| 175 | + |
| 176 | +### Connect Last |
| 177 | + |
| 178 | +Build complete features, connect them in final commit: |
| 179 | + |
| 180 | +```javascript |
| 181 | +// Commits 1-10: Build new checkout components (all tested, all integrated) |
| 182 | +function CheckoutStep1() { /* tested, working */ } |
| 183 | +function CheckoutStep2() { /* tested, working */ } |
| 184 | +function CheckoutStep3() { /* tested, working */ } |
| 185 | + |
| 186 | +// Commit 11: Wire up to UI (final integration) |
| 187 | +<Route path="/checkout" component={CheckoutStep1} /> |
| 188 | +``` |
| 189 | + |
| 190 | +For detailed guidance on when to use each pattern, see [Feature Flags](/recommendations/featureflags/). |
| 191 | + |
| 192 | +## What Tests Should Run |
| 193 | + |
| 194 | +### Pre-Merge (Fast Feedback) |
| 195 | + |
| 196 | +Run before code merges to trunk: |
| 197 | + |
| 198 | +- **Unit tests**: Test individual components in isolation |
| 199 | +- **Linting**: Code style and quality checks |
| 200 | +- **Static security scans**: SAST tools checking for vulnerabilities |
| 201 | +- **Dependency audits**: Known vulnerabilities in dependencies |
| 202 | + |
| 203 | +**Goal**: Complete in < 10 minutes |
| 204 | + |
| 205 | +### Post-Merge (Comprehensive Validation) |
| 206 | + |
| 207 | +Run after code merges to trunk: |
| 208 | + |
| 209 | +- **Integration tests**: Test component interactions |
| 210 | +- **Functional tests**: Test user-facing behavior |
| 211 | +- **Performance tests**: Ensure no regressions |
| 212 | +- **Security tests**: Dynamic security analysis |
| 213 | + |
| 214 | +**Goal**: Complete in < 30 minutes |
| 215 | + |
| 216 | +### What About Deployment Testing? |
| 217 | + |
| 218 | +Tests requiring deployment (end-to-end, smoke tests) are part of the [deployment pipeline](/minimumcd/singlepath/), not CI. |
24 | 219 |
|
25 | 220 | ## What is Improved |
26 | 221 |
|
27 | | -- **Teamwork:** CI requires a lot of teamwork to function correctly. If the team currently uses a "push" workflow where work is assigned instead of a "pull" workflow where the next most important work is picked up by the next available teammate, then CI will be very difficult. Teamwork suffers because everyone is focused on their individual "assignments" rather than team goals. Long delays in code review, large changesets, and excessive process hurt outcomes. Find a cadence for code review to process them quickly and set some team norms on changeset size and collaboration. Pair programming is a good way to help address these problems quickly. |
28 | | -- **Work Breakdown:** We need to [break down work better](https://dojoconsortium.org/docs/work-decomposition/work-breakdown/). We should have a "Definition of Ready" that requires every story and task has a testable description of "done" before any work starts. A good rule of thumb is that if everyone agrees the team can complete that item in less than 2 days, it's refined enough for CI. |
29 | | -- **Testing:** This is a common struggle. It's common that teams either do not test or know little about basic unit testing. Testing implementation instead of behavior is another common issue. Teams will need to improve the efficiency and effectiveness of their tests and build a suite of various types of tests with the goal of moving detection as close to creation as possible. CI requires falling passionately in love with testing, but that should be true of software engineering anyway. |
| 222 | +### Teamwork |
30 | 223 |
|
31 | | -## Health Metrics |
| 224 | +CI requires strong teamwork to function correctly. Key improvements: |
| 225 | + |
| 226 | +- **Pull workflow**: Team picks next important work instead of working from assignments |
| 227 | +- **Code review cadence**: Quick reviews (< 4 hours) keep work flowing |
| 228 | +- **Pair programming**: Real-time collaboration eliminates review delays |
| 229 | +- **Shared ownership**: Everyone maintains the codebase together |
| 230 | +- **Team goals over individual tasks**: Focus shifts from "my work" to "our progress" |
| 231 | + |
| 232 | +**Anti-pattern**: "Push" workflow where work is assigned creates silos and delays. |
| 233 | + |
| 234 | +### Work Breakdown |
| 235 | + |
| 236 | +CI forces better work decomposition: |
| 237 | + |
| 238 | +- **Definition of Ready**: Every story has testable acceptance criteria before work starts |
| 239 | +- **Small batches**: If the team can complete work in < 2 days, it's refined enough |
| 240 | +- **Vertical slicing**: Each change delivers a thin, tested slice of functionality |
| 241 | +- **Incremental delivery**: Features built incrementally, each step integrated daily |
32 | 242 |
|
33 | | -- **Commits/Day/Developer**: How frequently are we as a team integrating code to the trunk each day? "Good" is 1 or more per day per dev. Never compare individuals. this is a team average. |
34 | | -- **Development cycle time**: The time from when work begins to being completed. "Good" is less than 2 days on average. |
35 | | -- **Defect rate**: A critical guardrail metric to ensure speed does not overtake quality and vice versa. |
| 243 | +See [Work Breakdown](https://dojoconsortium.org/docs/work-decomposition/work-breakdown/) for detailed guidance. |
36 | 244 |
|
37 | | -## FAQ |
| 245 | +### Testing |
| 246 | + |
| 247 | +CI requires a shift in testing approach: |
| 248 | + |
| 249 | +**From**: Writing tests after code is "complete" |
| 250 | +**To**: Writing tests before/during coding (TDD/BDD) |
| 251 | + |
| 252 | +**From**: Testing implementation details |
| 253 | +**To**: Testing behavior and outcomes |
| 254 | + |
| 255 | +**From**: Manual testing before deployment |
| 256 | +**To**: Automated testing on every commit |
| 257 | + |
| 258 | +**From**: Separate QA phase |
| 259 | +**To**: Quality built into development |
| 260 | + |
| 261 | +CI teams build a comprehensive test suite with the goal of detecting issues as close to creation as possible. See [Behavior-Driven Development](https://dojoconsortium.org/docs/work-decomposition/behavior-driven-development/). |
| 262 | + |
| 263 | +## Common Challenges |
38 | 264 |
|
39 | 265 | ### "What are the main problems to overcome?" |
40 | 266 |
|
41 | | -1. Poor teamwork, usually driven by assigning work instead of using a pull system. |
42 | | -2. Lack of proper testable acceptance criteria. This is made worse by #1 because everyone will be focused on their individual assignments instead of the team's goals. [BDD](https://dojoconsortium.org/docs/work-decomposition/behavior-driven-development/) is the best way to get to true, declarative functional tests that everyone understands. Coding should be driven by those tests. |
43 | | -3. Lack of knowledge of evolutionary coding practices. "I can't commit until the feature is complete!" We need to break those changes down to the level where we can commit a passing unit test. Branch by abstraction, feature flags, or just planning changes so that the last change integrates the feature with the rest of the application. |
| 267 | +1. **Poor teamwork**: Usually driven by assigning work instead of using a pull system |
| 268 | +2. **Lack of testable acceptance criteria**: Made worse by individual assignments instead of team goals. [BDD](https://dojoconsortium.org/docs/work-decomposition/behavior-driven-development/) provides declarative functional tests everyone understands |
| 269 | +3. **Lack of evolutionary coding knowledge**: "I can't commit until the feature is complete!" Use branch by abstraction, feature flags, or plan changes so the last change integrates the feature |
44 | 270 |
|
45 | 271 | ### "How do I complete a large feature in less than a day?" |
46 | 272 |
|
47 | | -You probably don't. However, there are several strategies available for making evolutionary changes that build toward the complete feature. See [Recommended practices](#recommended-practices). |
| 273 | +You probably don't complete it in a day, but you integrate progress every day. See [Evolutionary Coding Practices](#evolutionary-coding-practices) for detailed patterns and code examples. |
| 274 | + |
| 275 | +### "What code coverage level is needed before we can do CI?" |
| 276 | + |
| 277 | +You don't need tests in existing code to begin CI. You need to test **new code without exception**. |
| 278 | + |
| 279 | +**Starting point**: "We will not go lower than the current level of code coverage." |
| 280 | + |
| 281 | +### "What code coverage percentage should we have?" |
| 282 | + |
| 283 | +"I'm confident." Are you confident you've covered enough positive and negative cases? |
| 284 | + |
| 285 | +**Better question**: "Do we trust our tests?" Test coverage percentage doesn't indicate test quality. |
| 286 | + |
| 287 | +### "Should we set a code coverage standard for all teams?" |
| 288 | + |
| 289 | +No. Code coverage mandates incentivize meaningless tests that hide the fact that code is not tested. |
| 290 | + |
| 291 | +**It is better to have no tests than to have tests you do not trust.** |
| 292 | + |
| 293 | +Instead: Focus on test quality, behavior coverage, and team discipline. See [Code Coverage](https://dojoconsortium.org/docs/metrics/code-coverage/) for detailed guidance. |
| 294 | + |
| 295 | +## Health Metrics |
| 296 | + |
| 297 | +### Commits per Day per Developer |
48 | 298 |
|
49 | | -### "What tests should run during CI?" |
| 299 | +**What**: How frequently the team integrates code to trunk |
| 300 | +**Good**: 1 or more per developer per day (team average) |
| 301 | +**Important**: Never compare individuals—this is a team metric |
50 | 302 |
|
51 | | -Our goal is to detect issues as early as possible. Any functional tests that can be executed without deploying the application should be run. This includes, but is not limited to: |
| 303 | +### Development Cycle Time |
52 | 304 |
|
53 | | -- Static code quality |
54 | | -- Static security scans |
55 | | -- [Functional tests](https://martinfowler.com/articles/practical-test-pyramid.html) that do not require external services. |
| 305 | +**What**: Time from when work begins to completion |
| 306 | +**Good**: Less than 2 days on average |
| 307 | +**Indicates**: Effective work breakdown and CI practice |
56 | 308 |
|
57 | | -### What code coverage level is needed before we can do CI? |
| 309 | +### Build Success Rate |
58 | 310 |
|
59 | | -You don't need tests in the existing code to begin. You need to test new code without exception. |
| 311 | +**What**: Percentage of trunk builds that pass |
| 312 | +**Good**: > 95% |
| 313 | +**Indicates**: Quality of pre-merge testing and team discipline |
60 | 314 |
|
61 | | -### What code coverage percentage should we have? |
| 315 | +### Time to Fix Broken Build |
62 | 316 |
|
63 | | -"I'm confident". Are you confident you've covered enough positive and negative cases to make you confident? |
| 317 | +**What**: How quickly team resolves build failures |
| 318 | +**Good**: < 1 hour |
| 319 | +**Indicates**: Team commitment to "stop and fix" |
64 | 320 |
|
65 | | -### What code coverage percentage should we set as a standard for our team? |
| 321 | +### Defect Rate |
66 | 322 |
|
67 | | -"We will not go lower than the current level of code coverage." However, if the team is not committed to a disciplined quality process to the extent that delivery dates are never seen as an excuse, this could incentivize fake tests to meet the coverage minimum. |
| 323 | +**What**: Critical guardrail metric to ensure speed doesn't overtake quality |
| 324 | +**Good**: Stable or decreasing as CI improves |
| 325 | +**Indicates**: CI is improving quality, not just speed |
68 | 326 |
|
69 | | -### What code coverage percentage should we set as a standard for all teams? |
| 327 | +## Additional Resources |
70 | 328 |
|
71 | | -We shouldn't. Code coverage mandates incentivize meaningless tests that hide the fact that code is not tested. It is better to have no tests than to have tests you do not trust. See the [Dojo Consortium's info](https://dojoconsortium.org/docs/metrics/code-coverage/) on this metric. |
| 329 | +- [Continuous Integration on Martin Fowler's site](https://martinfowler.com/articles/continuousIntegration.html) |
| 330 | +- [Accelerate: Technical Practices](https://itrevolution.com/articles/accelerate-book/) - Nicole Forsgren, Jez Humble, Gene Kim |
| 331 | +- [The Practical Test Pyramid](https://martinfowler.com/articles/practical-test-pyramid.html) - Martin Fowler |
| 332 | +- [Branch By Abstraction](https://www.branchbyabstraction.com/) |
| 333 | +- [Feature Toggles](https://martinfowler.com/articles/feature-toggles.html) - Martin Fowler |
| 334 | +- [Behavior-Driven Development](https://dojoconsortium.org/docs/work-decomposition/behavior-driven-development/) - DevOps Dojo Consortium |
0 commit comments