Continuous Integration
Definition
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.
CI is not just about tooling—it’s fundamentally about team workflow and working agreements.
The minimum activities required for CI
- Trunk-based development - all work integrates to trunk
- Work integrates to trunk at a minimum daily (each developer, every day)
- Work has automated testing before merge to trunk
- Work is tested with other work automatically on merge
- All feature work stops when the build is red
- New work does not break delivered work
Why This Matters
Without CI, Teams Experience
- Integration hell: Weeks or months of painful merge conflicts
- Late defect detection: Bugs found after they’re expensive to fix
- Reduced collaboration: Developers work in isolation, losing context
- Deployment fear: Large batches of untested changes create risk
- Slower delivery: Time wasted on merge conflicts and rework
- Quality erosion: Without rapid feedback, technical debt accumulates
With CI, Teams Achieve
- Rapid feedback: Know within minutes if changes broke something
- Smaller changes: Daily integration forces better work breakdown
- Better collaboration: Team shares ownership of the codebase
- Lower risk: Small, tested changes are easier to diagnose and fix
- Faster delivery: No integration delays blocking deployment
- Higher quality: Continuous testing catches issues early
Team Working Agreements
While CI depends on tooling, the team workflow and working agreement are more important:
- Define testable work: Work includes testable acceptance criteria that drive testing efforts
- Tests accompany commits: No work committed to version control without required tests
- Incremental progress: Committed work may not be “feature complete”, but must not break existing work
- Trunk-based workflow: All work begins from trunk and integrates to trunk at least daily
- Team commitment: If CI detects an error, the team stops feature work and collaborates to fix the build
Example Implementations
Anti-Pattern: Feature Branch Workflow Without CI
Problems:
- Long-lived branches accumulate merge conflicts
- Integration issues discovered late
- No early feedback on compatibility
- Large batches of untested changes
- Team blocked while resolving conflicts
Good Pattern: Continuous Integration to Trunk
Benefits:
- Changes tested within minutes
- Team gets immediate feedback
- Small changes are easy to debug
- Integration is never a surprise
- Quality maintained continuously
Evolutionary Coding Practices
To integrate code daily while building large features, use these patterns:
Branch by Abstraction
Gradually replace existing behavior while continuously integrating:
Feature Flags
Feature flags control feature visibility without blocking integration. However, they’re often overused—many scenarios have better alternatives.
When to use feature flags:
- Large or high-risk changes needing gradual rollout
- Testing in production before full release (dark launch, beta testing)
- A/B testing and experimentation
- Customer-specific behavior or toggles
- Cross-team coordination requiring independent deployment
When NOT to use feature flags:
- New features that can connect to tests only, integrate in final commit
- Behavior changes (use branch by abstraction instead)
- New API routes (build route, expose as last change)
- Bug fixes or hotfixes (deploy immediately)
- Simple changes (standard deployment sufficient)
Example usage:
For detailed decision guidance and implementation approaches, see Feature Flags.
Connect Last
Build complete features, connect them in final commit:
For detailed guidance on when to use each pattern, see Feature Flags.
What Tests Should Run
Pre-Merge (Fast Feedback)
Run before code merges to trunk:
- Unit tests: Test individual components in isolation
- Linting: Code style and quality checks
- Static security scans: SAST tools checking for vulnerabilities
- Dependency audits: Known vulnerabilities in dependencies
Goal: Complete in < 10 minutes
Post-Merge (Comprehensive Validation)
Run after code merges to trunk:
- Integration tests: Test component interactions
- Functional tests: Test user-facing behavior
- Performance tests: Ensure no regressions
- Security tests: Dynamic security analysis
Goal: Complete in < 30 minutes
What About Deployment Testing?
Tests requiring deployment (end-to-end, smoke tests) are part of the deployment pipeline, not CI.
What is Improved
Teamwork
CI requires strong teamwork to function correctly. Key improvements:
- Pull workflow: Team picks next important work instead of working from assignments
- Code review cadence: Quick reviews (< 4 hours) keep work flowing
- Pair programming: Real-time collaboration eliminates review delays
- Shared ownership: Everyone maintains the codebase together
- Team goals over individual tasks: Focus shifts from “my work” to “our progress”
Anti-pattern: “Push” workflow where work is assigned creates silos and delays.
Work Breakdown
CI forces better work decomposition:
- Definition of Ready: Every story has testable acceptance criteria before work starts
- Small batches: If the team can complete work in < 2 days, it’s refined enough
- Vertical slicing: Each change delivers a thin, tested slice of functionality
- Incremental delivery: Features built incrementally, each step integrated daily
See Work Breakdown for detailed guidance.
Testing
CI requires a shift in testing approach:
From: Writing tests after code is “complete” To: Writing tests before/during coding (TDD/BDD)
From: Testing implementation details To: Testing behavior and outcomes
From: Manual testing before deployment To: Automated testing on every commit
From: Separate QA phase To: Quality built into development
CI teams build a comprehensive test suite with the goal of detecting issues as close to creation as possible. See Behavior-Driven Development.
Common Challenges
“What are the main problems to overcome?”
- Poor teamwork: Usually driven by assigning work instead of using a pull system
- Lack of testable acceptance criteria: Made worse by individual assignments instead of team goals. BDD provides declarative functional tests everyone understands
- 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
“How do I complete a large feature in less than a day?”
You probably don’t complete it in a day, but you integrate progress every day. See Evolutionary Coding Practices for detailed patterns and code examples.
“What code coverage level is needed before we can do CI?”
You don’t need tests in existing code to begin CI. You need to test new code without exception.
Starting point: “We will not go lower than the current level of code coverage.”
“What code coverage percentage should we have?”
“I’m confident.” Are you confident you’ve covered enough positive and negative cases?
Better question: “Do we trust our tests?” Test coverage percentage doesn’t indicate test quality.
“Should we set a code coverage standard for all teams?”
No. 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.
Instead: Focus on test quality, behavior coverage, and team discipline. See Code Coverage for detailed guidance.
Health Metrics
Commits per Day per Developer
What: How frequently the team integrates code to trunk Good: 1 or more per developer per day (team average) Important: Never compare individuals—this is a team metric
Development Cycle Time
What: Time from when work begins to completion Good: Less than 2 days on average Indicates: Effective work breakdown and CI practice
Build Success Rate
What: Percentage of trunk builds that pass Good: > 95% Indicates: Quality of pre-merge testing and team discipline
Time to Fix Broken Build
What: How quickly team resolves build failures Good: < 1 hour Indicates: Team commitment to “stop and fix”
Defect Rate
What: Critical guardrail metric to ensure speed doesn’t overtake quality Good: Stable or decreasing as CI improves Indicates: CI is improving quality, not just speed
Additional Resources
- Continuous Integration on Martin Fowler’s site
- Accelerate: Technical Practices - Nicole Forsgren, Jez Humble, Gene Kim
- The Practical Test Pyramid - Martin Fowler
- Branch By Abstraction
- Feature Toggles - Martin Fowler
- Behavior-Driven Development - DevOps Dojo Consortium