- Initial thoughts
- 1. Why best practices matter? The outcomes
- 2. Non-technical practices β the baseline
-
3. Technical practices β the baseline
- Version control for everything that ships
- Peer code review
- CI per feature branch
- Modern testing strategy (trophy, test data, TDD)
- Environment per feature branch
- Documentation-as-code per branch
- Continuous delivery (always releasable + automated deploy)
- Monitoring and observability
- Security shifted left
- Simple design, refactoring, and managed debt
- 4. Non-technical practices β elite
- 5. Technical practices β elite
- 6. Where to start (solo vs team)
- Wrapping up
- Further reading
Continuous deployment is not a Netflix cosplay. It is a stack of practices that make shipping to production so routine it becomes boring. We map that stack along two axes: non-technical vs technical, and baseline vs elite β product habits first, elite last, because elite is not a universal target.
Initial thoughts
Most teams do not fail because they lack a manifesto on the wall. They fail because the advice arrives unsorted: microservices before CI is green, trunk-based theatre before anyone trusts the test suite, a "DevOps transformation" that is mostly a Slack channel named #ops-please-help.
We organize practices the way high-performing delivery research does β product / lean / culture on one side, technical capabilities on the other β and we present them non-technical first, then technical, each split into baseline (what makes frequent deploys reachable) vs elite (what removes the remaining friction). Non-technical habits prevail: a perfect pipeline shipping the wrong thing is still waste. Elite practices come last because they are not a universal target β most teams get more from a boring baseline than from canary theatre on a flaky suite.
A team of one (AI made that shape ordinary) can skip pairing, generative collaboration, and most of elite. It does not skip small batches, user feedback, WIP, or the technical baseline. Peer review without a peer means the pipeline is the other reviewer β the model does not join the on-call rotation.
Evidence (DORA, craft, agile) supports the stack; it is not the pitch. The pitch is boring production: short lead time, frequent deploys, failures that are rare and recoverable, without heroics on Friday night.
Each practice below: a short why, then concrete moves.
1. Why best practices matter? The outcomes
You do not need elite labels on a slide. You need outcomes that speak to two audiences at once β the team doing the work, and the people holding the budget. The DORA research frames this as a win/win: the same practices that make delivery faster also make it calmer and cheaper. "Boring production" is the shorthand β short lead time, frequent deploys, failures that are rare and recoverable, without heroics on Friday night.
Concretely, four outcomes describe that picture:
- Changes reach production in hours or days, not months.
- Deploys are routine β pipeline or one click, same artifact across environments.
- Failures are uncommon and recovery is practiced, not invented under adrenaline.
- Deploy (technical) and release (product) can be decoupled when needed.
For the business, those four translate into the language decision-makers actually use:
- Time-to-market: shorter lead time means ideas reach users faster β competitive advantage, not a quarterly slide.
- Financial savings: fewer failed changes and faster recovery mean less rework, less incident cost, less overtime billed to a budget line someone watches.
- Wellbeing: a generative, blameless culture with sustainable pace is not a perk β it is a delivery lever. Hero cultures are leading indicators of outages and resignations.
Those outcomes are exactly what throughput and stability metrics try to capture. If you want numbers on a GitLab project, we once published GitLab: A Python Script Calculating DORA Metrics β useful as a mirror, not as a religion.
Practices are inputs, and management does not buy inputs. A slide about trunk-based development will not move a CFO; "we cut lead time from three weeks to two days, halved our change-failure rate, and the on-call rotation stopped being a resignation letter" might. The whole stack below exists to make those outcomes move β and to keep them moving after the next reorg, not just for the one-quarter spike that earns a LinkedIn post.
2. Non-technical practices β the baseline
Technical excellence ships the wrong thing beautifully if product and team habits are absent. These baseline habits do not require a VP of Transformation β and they come first for a reason.
Small batches
Slice work so feedback arrives while memory is fresh. Working in small batches is a product/process discipline as much as a git habit.
Concrete:
- Prefer MRs reviewable in under an hour.
- Split stories by user-visible outcome, not by layer ("all the SQL this sprint").
- If a change needs a three-page risk essay, it was already too big last Tuesday.
- Ship thin vertical slices; thicken later.
Stakeholder and user feedback
Early feedback tops almost every agile success list for a reason: without users in the loop, CD accelerates waste.
Concrete:
- Demo or expose something to a real user every iteration β even internal users count.
- Keep a product owner / domain expert reachable within the sprint, not "next quarter."
- Write backlog items as outcomes, not as technical chores in disguise.
- Kill features nobody uses β the backlog is not a museum.
Continuous improvement and WIP limits
Retros without experiments are group therapy. WIP limits make queues visible.
Concrete:
- One process experiment per sprint, with a success check.
- Cap WIP on the board; stop starting, start finishing.
- Time-box spikes so research does not drift.
- Track aging work items; anything older than a sprint deserves a decision: finish, cut, or kill.
Generative collaboration
High-trust, high-information-flow culture β Westrum's generative type β predicts delivery performance better than tool brand loyalty.
Concrete:
- Blameless postmortems; fix the system, not the person who typed the command.
- Shared responsibility for quality and production of what you build.
- Make asking for help cheaper than hiding (pairing budget, public channels).
- Leaders say "I was wrong" in public. Culture is what happens after the slide deck leaves the room.
Pairing and knowledge transfer
Pairing is a social practice with technical side effects: fewer bus factors, faster onboarding, better reviews.
Concrete:
- Pair on unfamiliar or high-risk areas.
- Rotate ownership so no module is a single-human crypt.
- Write short ADRs when the why would otherwise leave with someone's badge.
- Budget pairing time explicitly β "when we have time" means never.
3. Technical practices β the baseline
This is where a solo developer (or a small team) gets the most impact per hour invested β once small batches and feedback are not actively sabotaging the loop.
Version control for everything that ships
If it can break production, it belongs in version control: app code, pipelines, infra-as-code, config that is not a secret, release notes next to the code they describe.
Concrete:
- Ban direct pushes to the default branch.
- Put pipeline definitions in the repo; review them like product code.
- Tag or record every production deploy so "what is live?" is a
gitquestion. - Secrets stay in a vault β version references, not the passwords themselves. (Dave's USB stick is not a HA strategy.)
Peer code review
The cheapest early defect filter we still have, and a knowledge pump. Seniors should not be the only reviewers β we argued that at length in Every Developer Should Review Code β Not Just Seniors.
Concrete:
- Every change to the default branch goes through a merge request.
- Same-day review SLA; large MRs are a process failure, not a badge of honor.
- Review for behavior, risk, and clarity β not semicolon theology.
- Require at least one human approval; bots are assistants, not scapegoats.
CI per feature branch
Integrating only on main means the whole team pays for one person's surprise. A pipeline on every feature branch keeps the shared line green and leaves breakage with the author.
Concrete:
- Run build + tests on every MR / branch push.
- Aim for feedback in minutes, not hours.
- Fix red pipelines before starting new work.
- Keep the default branch protected and green β broken
mainis a team-wide tax.
Modern testing strategy (trophy, test data, TDD)
"Automated tests" is too vague. Prefer a modern testing strategy: a testing trophy bias (static checks + many integration tests + fewer brittle E2E), managed test data, and TDD where design benefits.
Concrete:
- Agree the trophy shape for your stack; write mostly tests that give confidence without a flaky UI circus.
- Gate merge on fast, trusted suites; keep E2E thin and stable.
- Quarantine flaky tests within 48 hours β mute-and-forget turns green into fiction.
- Provide disposable, seeded test data; never depend on a shared "QA database" that three teams mutate like a commons pasture.
- Use TDD for new behavior and tricky logic: failing test β minimal code β refactor. Skip TDD on throwaway spikes.
Environment per feature branch
A green unit suite is not the same as "this feature works in a real stack." A green pipeline on main tells you the code integrates; it tells you nothing about whether the new endpoint actually answers in a real browser, against a real database, next to the other half-merged features of the sprint. An environment per branch (or ephemeral preview) closes that gap before merge β it turns "works on my machine" into "works on a machine that looks like prod," without a calendar invite.
Concrete:
- Deploy each long-lived feature branch to an isolated URL / namespace.
- Use it for manual checks and a few targeted E2E runs.
- Tear environments down automatically β zombie previews are how cloud bills invent folklore.
- Prefer the same deploy path as production, with smaller sizing.
Documentation-as-code per branch
Docs that live only on main lag reality. Build and publish documentation from the same branch as the change β preview sites, generated API refs, runbooks in the repo. We explored why this pattern wins in Documentation-as-Code Has Silently Won For Tech Content, and the same per-branch preview trick we used for GitLab Pages per Branch: The No-Compromise Hack to Serve Preview Pages is what makes the docs preview real on every MR.
Concrete:
- Keep docs in the repo next to the code they describe.
- Pipeline job: build docs on every branch; publish a per-branch preview (Pages, Storybook, OpenAPI UIβ¦).
- Review doc diffs in the same MR as behavior changes.
- Link the preview URL in the MR description β reviewers should not need a sΓ©ance to find the new endpoint.
Continuous delivery (always releasable + automated deploy)
Here we merge what tool vendors often split: continuous delivery means the software is always in a releasable state and the path to production is automated. Manual SSH snowflakes are not "careful"; they are unpaid drama. Continuous deployment (every green commit goes to prod) is optional once CD is real β a policy choice on top of the same machinery.
Concrete:
- One artifact promoted across environments; no "rebuild for prod."
- Deploy via pipeline or one approved click β identical steps every time.
- Keep
maindeployable; fixing releasability beats starting the next epic. - Separate deploy from release with flags when the product is not ready for all users β this deploy/release decoupling use of flags is baseline; using flags to hide incomplete work behind trunk-based development is the elite form covered in section 5.
- Rehearse rollback / roll-forward on a boring Tuesday. (Friday deploys are fine when Tuesday already proved you can undo them.)
A pipeline you dare not touch is folklore, not automation β feed it continuously, as we argued in Keep Feeding Your CI/CD β Or Watch It Die.
Monitoring and observability
Daily deploys without eyes on production is SchrΓΆdinger's release: simultaneously fine and on fire until someone opens the dashboard.
Concrete:
- Track golden signals: latency, traffic, errors, saturation.
- Structured logs with correlation IDs across services.
- Alert on actionable symptoms; paging for disk at 71% trains people to ignore the building on fire.
- Attach a runbook link to every alert that can wake a human.
Security shifted left
Security bolted on at the release CAB is how you discover CVEs during the demo. The cost of a finding grows roughly with the distance between where it was introduced and where it was caught β a vulnerable dependency caught in the MR is a version bump; the same dependency caught at the CAB is a release slip, and caught in production is an incident report. Shifting left is mostly an economic argument, not a moral one.
Concrete:
- Dependency and container scanning in CI.
- Secret detection on push.
- Threat-model new surfaces in the MR that introduces them.
- Fix criticals on a clock, not on vibes.
Simple design, refactoring, and managed debt
Craft is not a separate religion; it is how the baseline stays cheap over years.
Concrete:
- Boy-scout rule on touched files.
- Prefer delete over another abstract factory of abstract factories.
- Keep a visible debt list with cost-of-delay; budget a fixed capacity slice for structural work.
- Upgrade dependencies on a cadence before they become a liability.
4. Non-technical practices β elite
Elite culture and product habits turn a working pipeline into a learning system β the baseline ships reliably, these practices decide what gets shipped and whether the team survives shipping it. Skip them until the non-technical baseline is real; they are not a participation trophy.
Team experimentation and product hypotheses
Elite product management: try ideas without a twelve-signature approval pilgrimage.
Concrete:
- Frame work as hypotheses with kill criteria.
- Use flags and analytics to validate before scaling.
- Empower the team to run small experiments without leaving the team for permission.
- Celebrate killed experiments β they bought information cheaper than a full build.
Value-stream visibility
See the path from idea to production; attack waits, not only busy coding.
Concrete:
- Map the flow once; find the longest queue.
- Make blocked states visible on the board.
- Measure lead time by stage (code, review, QA, change board, prod).
- Optimize the bottleneck you measured, not the one that feels dramatic in standup.
Transformational leadership and wellbeing
Tools cannot compensate for a meat grinder. Leadership that enables learning, clarity, and sustainable pace shows up in delivery performance.
Concrete:
- Protect improvement time the same way you protect feature time.
- Remove approval steps that add delay without reducing risk.
- Watch burnout signals; hero culture is a leading indicator of outages.
- Hire and promote for teaching and collaboration, not only for lone-genius throughput.
5. Technical practices β elite
Baseline makes continuous delivery reachable. These practices remove remaining drag β adopt them when the baseline is already boringly reliable. Most teams should stay on the baseline longer than their slide deck suggests.
Trunk-based development and feature flags
Short-lived branches, frequent integration to trunk, incomplete work hidden behind flags. Powerful β and a mess if CI and tests are not trusted yet. The elite move here is TBD-driven flag usage: flags not just to decouple deploy from release (that is baseline), but to keep trunk always green while half-built features ship dark. See trunk-based development.
Concrete:
- Branch lifetime in hours/days, not weeks.
- Integrate to trunk at least daily.
- Feature flags for incomplete or risky exposure; product can toggle without a redeploy.
- Delete flags after rollout β flag archaeology is a special kind of haunted house.
Database change management
Schema changes are where "always releasable" goes to die if nobody owns the migration path.
Concrete:
- Migrations in version control, applied by the pipeline.
- Expand/contract for breaking changes; no dual-write hacks without a plan.
- Forward-only in production; rehearse rollback strategy when truly needed.
- Never "run this SQL from an email" as a release step.
Loosely coupled deployability
A team (or module) can deploy without a twelve-team release train. Note: a well-factored modular monolith is often the prerequisite that makes this decoupling reachable β splitting a tangled monolith into fashion microservices before you can deploy the monolith cleanly is a category error.
Concrete:
- Clear API contracts; version or expand carefully.
- Prefer a modular monolith before fashion microservices if you still have more services than users.
- Independent deploy pipelines per deployable unit.
- Contract tests between consumers and providers.
Advanced deployment strategies
When downtime or blast radius matters: blue/green, canary, dark launch. Feature flags often cover a surprising amount before you need full traffic-shifting machinery.
Concrete:
- Canary a percentage of traffic; watch error budgets before full rollout.
- Blue/green when you need instant cutover and easy revert.
- Dark launch: code live, users unaware β validate load before the marketing email.
- Automate the promotion criteria; humans confirm policy, not click fifty servers.
Internal platform and flexible infrastructure
Golden paths beat ticket queues β when the platform is a product, not a new bottleneck. Containers and IaC help reproducibility; they do not replace a green CI.
Concrete:
- Self-service: create preview env, run pipeline, deploy β without a week-long ticket.
- Infra-as-code for environments that matter.
- Autoscale runners and app capacity so branch previews do not block everyone else.
- Measure platform adoption and time-to-first-deploy for a new service.
6. Where to start (solo vs team)
Start with the non-technical baseline: small batches, stakeholder and user feedback, WIP. Pairing and generative collaboration when there is a second human. Without that loop, faster deploys just accelerate waste.
Solo β then the technical baseline, in roughly this order:
- Version control + CI on every branch (self-merged MRs are fine if CI is the gate).
- Modern testing strategy until the suite is trusted.
- Automated deploy path + monitoring (CD).
- Env + docs per branch when feedback before merge still hurts.
- Design / debt hygiene as a continuous tax.
Skip most of elite until this is dull.
Team with mandate β run non-technical and technical baselines in parallel. A collaborative team without CI is still slow; a perfect pipeline shipping the wrong thing is still waste.
Elite practices (product experimentation, value-stream mapping, TBD + flags, advanced deploys, platform) come after both baselines are dull. Trying trunk-based theatre on a flaky suite is how you invent new genres of merge conflict.
Wrapping up
Boring production is a stack, not a slogan. Split practices non-technical / technical, then baseline / elite β non-tech first because it prevails, elite last because it is not for everyone. Small batches, feedback, and WIP keep the loop pointed at value; pairing joins when there is a second human. A developer alone should then lean on the technical baseline: version, CI per branch, modern tests, CD with eyes on prod, docs and previews on the branch, craft that keeps the loop cheap β the pipeline is the other reviewer. Elite moves amplify a system that already works.
If you need one retro question: Which baseline practice β non-technical or technical β made boringly reliable, would shorten our path to valuable production most in the next ninety days? Fund that. Leave the Netflix costume in the closet.
Illustrations generated locally by Draw Things using Flux.1 [Schnell] model
Further reading
This article was enhanced with the assistance of an AI language model to ensure clarity and accuracy in the content, as English is not my native language.



Top comments (0)