CI: Merge Frequently, Verify Automatically
Continuous Integration (CI) is the practice of merging everyone’s changes into the shared main branch frequently and running automated checks on every merge. The mechanism is a pipeline: a series of automated stages triggered by the version control system. Its purpose is to make integration cheap — the moment something breaks, you know within minutes, not weeks.
The CI loop:
- A developer pushes a branch / opens a PR.
- CI runs: lint → unit tests → build (and type checks, and any static analysis).
- Green = mergeable. Red = the branch owner fixes it immediately.
The discipline is “keep the main branch green.” The longer a branch lives unmerged, the more expensive the eventual integration — CI is the economic argument for small, frequent merges.
Build, Test, Stage, Deploy
A mature pipeline’s stages, in order:
| Stage | Purpose | Failure = |
|---|---|---|
| Lint / format | enforce style, catch obvious bugs | developer fix |
| Unit tests | verify logic in isolation | developer fix |
| Build | produce the artifact (binary, image) | build config fix |
| Integration / e2e tests | verify the assembled system | environment/contract fix |
| Publish | store the artifact in a repository | publish config fix |
| Stage deploy | deploy to a production-like environment | deploy config fix |
| Prod deploy | roll out to production | release decision |
Two different meanings of CD live in that table:
- Continuous Delivery — every change that passes the pipeline is deployable; actually shipping to production is a human (or gated) decision.
- Continuous Deployment — every change that passes the pipeline is automatically deployed to production.
Continuous Deployment removes the human bottleneck but demands high test confidence and fast rollback — you’re automating the moment you used to say “hmm, should this go out?”
Artifacts: The Binary, Not the Source
The build stage produces an artifact — a versioned binary or image — published to an artifact repository (Docker registry, Nexus, Artifactory, cloud artifact registries). Deployments reference published artifacts by immutable version/tag, never re-built from source at deploy time. build@sha256:abc123 is your “exactly what shipped” record — the difference between “works in prod” and “should be reproducible.”
Deployment Strategies
The stage→prod transition has its own playbook:
- Rolling — update instances in waves; capacity never drops to zero. Default, simple.
- Blue/green — run the new version alongside the old (blue), flip the router/lB traffic, and keep the old (green) ready to flip back instantly. Zero downtime, cost = double capacity during the cutover.
- Canary — route a small % of traffic (5%) to the new version, watch metrics, then ramp 25% → 100%. The safest for behavioral changes (metrics, not just uptime, decide the ramp).
Rollback and Recovery
Every deploy must answer “what if this is bad?” before it ships:
- Rollback — redeploy the previous good artifact. Fast, but state migrations (database schema changes) may not be reversible — the reason DB migrations are their own gated, rehearsed stage.
- Roll-forward — fix forward: deploy a new version that corrects the bug. Sometimes the only option when the old version can’t talk to the new schema.
The rule: deploys are reversible; schema changes are not. Treat database migrations as forward-only, versioned, and tested against the previous code version (expand-contract / the outbox-adjacent discipline from Distributed Transactions).
Pipeline as Code
Modern pipelines are code — declarative YAML in the repo (GitHub Actions, GitLab CI, CircleCI, Jenkins Pipelines) — versioned, reviewed, and testable exactly like application code. The pipeline itself gets the same review discipline as the code it ships: a broken pipeline is a prod incident in waiting.
The Visualizer
Use the CI/CD pipeline visualizer above to step through three scenarios and watch the pipeline gates fire:
- Green pipeline — commit
8f3a2c1runslint → unit → build → deploy-staging → approval → deploy-prod; v124 publishes to the artifact registry, then the approval gate opens and v124 ships to prod. Everything goes green. - Test failure — commit
9b1c7d4trips the unit-test stage; CI aborts, the remaining stages are skipped, and nothing is promoted — the main branch stays green because the merge never happened. - Rollback — v125 is deployed to prod, the error-spike metric goes red, and the ops gate triggers a rollback to the last good artifact v124 while the canary is pulled.
Watch the stage cards (pending → running → success/failed/skipped), the environment badges (staging/prod healthy vs degraded), and the pipeline log to see the same event sequence a real CI system prints.
Practice Trajectory
- Define a CI pipeline (lint → unit → build) for a small repo and break the main branch; observe the red.
- Add a publish stage that pushes an immutable-tagged image/artifact.
- Stage-deploy to an environment, then set up blue/green or canary for prod.
- Roll back a bad deploy and time it; then rehearse a roll-forward with a migration.
- Turn the pipeline into code in the repo and review it in a PR like application code.
When It’s the Right Tool
| Situation | Takeaway |
|---|---|
| Team velocity and confidence | CI on every PR |
| Fast, safe production shipping | CD with canary + instant rollback |
| “What exactly is running?” | Immutable artifacts + registry |
| Database changes with the deploy | Migrations as gated, forward-only stages |
| Risky behavior change | Canary ramp + metric-based promotion |