01It is a loop, not a line
The old picture of software development was a waterfall: requirements, then design, then build, then test, then release, each phase finishing before the next began. It is a tidy diagram and a poor description of reality, because it assumes the hardest question — what should this actually do? — is answered correctly at the start and never revisited.
What teams do instead is go round. A small change is described, built, checked, released, and watched; what is learned from watching it changes what gets described next. The park behind this page is drawn as a circuit for exactly that reason: the track leaves the backlog plaza and comes back to it.
The one idea to keep
Every stage after "write the code" exists to answer one question: is it safe to let people use this? Version control, review, CI, tests, security scanning, staging, canaries and monitoring are all different-priced answers to that single question. A team's process is really just its choice of which answers to buy.
The unit that travels round the loop matters more than the diagram. If it is a six-month project, every stage is slow, risky and hard to reverse. If it is a change of forty lines, every stage is quick, cheap and easy to undo. Almost everything good about modern delivery comes from making that unit smaller.
02Discovery: turning a need into a slice
Work starts as something vague — a complaint, a support ticket, a strategy slide, a thing a competitor shipped. The job of discovery is to turn that into a statement specific enough to be built and, crucially, specific enough that you could tell afterwards whether it worked.
Two artefacts do most of the work. The problem statement says who is affected, what they are trying to do, and what currently goes wrong. The acceptance criteria say what must be observably true for the work to count as done. Neither mentions an implementation. Both are testable.
Vertical slices
A slice should be thin but complete — a working path from interface to storage — not "the database part", which cannot be released or judged on its own.
Definition of done
Written down once, applied every time: tested, reviewed, documented, observable, and actually running in production.
Work in progress limits
Starting is easy and finishing is not. Capping how many things may be in flight is what makes them finish.
Estimates
Useful as a conversation about risk and unknowns. Treated as a promise, they quietly become a deadline nobody agreed to.
Where AI helps first
This is one of the least glamorous and most effective places to use a language model: clustering hundreds of support tickets into recurring themes, drafting acceptance criteria from a rough note, listing the edge cases a description forgot. The output is a draft for a person to argue with, which is exactly the right shape.
03Version control: one true history
Everything the team builds lives in a repository under version control, almost always Git. It stores not the current state of the code but the entire sequence of changes that produced it: who changed what, when, and — if the commit message is any good — why.
That history is not bookkeeping. It is the mechanism that lets several people change the same system at once without overwriting each other, lets you find the exact change that introduced a bug, and lets you undo it without undoing anything else.
| Term | What it is | Why it matters |
|---|---|---|
| Commit | A snapshot plus a message and a parent | The smallest unit you can revert, review or bisect |
| Branch | A movable pointer to a line of commits | Lets unfinished work exist without disturbing anyone |
| Merge | Joining two lines of history | Where conflicting edits get resolved, by a human |
| Tag | A fixed name for one commit | What "version 4.2.0" actually points at |
| Main | The branch everyone agrees is the truth | What gets built, tested and released |
The long-running argument about branching strategy is really an argument about batch size. Branches that live for weeks accumulate conflicts and hide risk; trunk-based development — short-lived branches merged into main within a day or two, with unfinished features hidden behind flags — keeps the difference between what is written and what is integrated small enough to reason about.
04Writing the code — now with a machine at the desk
For most of the industry's history this was the bottleneck. Producing correct code was slow, skilled work, and everything around it was organised to protect that scarce capacity. That assumption is the one currently being renegotiated.
A modern coding agent is not autocomplete. It is a language model in a loop with tools: it can read files, search the codebase, write edits, run the test suite, read the failures and try again — repeating until some stopping condition is met. Give it a goal and a working environment, and it will take many steps without being asked for each one.
Completion
Suggests the next few lines as you type. You stay in the loop continuously; the blast radius is one keystroke.
Chat
Answers questions and drafts snippets in a side panel. You paste, adapt, and remain the one editing.
Agent
Takes a task, edits many files, runs commands, iterates against the tests, and hands back a diff for review.
Background agent
The same thing running on its own machine against a ticket, arriving as a pull request you did not watch being written.
The interesting consequence is not that typing gets faster. It is that the constraint moves. When producing a plausible diff is cheap, the expensive parts become deciding what should be built, and establishing that what was built is correct. The rest of this page is mostly about that second thing — which is why it was already the majority of the lifecycle before any of this arrived.
Plausible is not correct
A model is optimised to produce output that looks like the right answer. Most of the time, in well-trodden territory, that coincides with being the right answer. In the remaining cases you get code that reads beautifully, uses a function that does not exist, and handles the empty case by pretending it cannot happen. Nothing downstream of here cares who wrote the change — which is precisely why the pipeline is the safeguard.
05Review: the last place a human reads it
A pull request proposes a change and invites objection before it becomes part of the truth. Reviewers read the diff, ask questions, request changes, and eventually approve. It is the cheapest available moment to catch a misunderstanding, because nothing has been released and nobody is affected yet.
Reviews catch fewer pure bugs than people assume — tests are better at that — and far more of everything else: a misread requirement, a name that will confuse the next reader, an edge case nobody considered, a change that works but makes the next change harder. Good review is mostly about intent.
Small diffs
Attention falls off a cliff after a few hundred lines. A big pull request does not get reviewed harder; it gets approved faster.
One purpose
A refactor mixed with a behaviour change hides the behaviour change. Separate them, even when it costs a second pull request.
Machines first
Formatting, lint and style should be settled by tools before a person looks. Humans are for judgement, not whitespace.
Fast turnaround
A review that waits a day costs far more than its own duration, because the author has moved on and must page it all back in.
AI reviewers are genuinely useful here as a first pass — they never get bored, they read the whole diff, and they are good at spotting the mechanical classes of mistake: an unchecked error, a resource left open, a test that asserts nothing. They are also confidently wrong often enough that treating their comments as a gate rather than a suggestion trains everyone to ignore them.
The load problem
If agents write more changes and humans still review all of them, review becomes the new queue — and a reviewer who feels behind approves rather than reads. Teams that handle this well shrink what needs human attention: smaller diffs, stronger automated checks, and an honest split between changes that need judgement and changes where a green pipeline genuinely is the evidence.
06Continuous integration: build it once, for everyone
Continuous integration is the practice of merging everyone's work into the shared branch frequently — at least daily — and having a machine build and check the result every single time. The server is not the point; the frequency is. CI is what stops "it works on my machine" from being a meaningful sentence.
A typical run, in order, cheapest checks first so failures come back fast:
Two properties make the difference between a pipeline people trust and one they route around. It must be fast — beyond about ten minutes, developers stop waiting and start context-switching, and the feedback loop breaks. And it must be deterministic: a suite that fails one run in twenty teaches everyone to press retry, which is the same as having no suite at all.
CI is what makes agents workable
An agent needs a fast, honest signal to iterate against, and a green pipeline is the best one available. It is also the boundary that contains the damage: whatever the agent believed about its own work, the same checks run, on the same machines, before anything merges. Teams that adopt agents successfully almost always invest in CI first.
07Testing: buying confidence at different prices
Tests are executable claims about behaviour. Their value is not that they prove the system correct — they cannot — but that they let you change it without being afraid, which is the difference between a codebase that stays alive and one that ossifies.
| Kind | Scope | Speed | Catches |
|---|---|---|---|
| Unit | One function or module, isolated | Milliseconds | Logic errors, edge cases, regressions |
| Integration | Several parts together, real database | Seconds | Wrong assumptions between components |
| End-to-end | The whole system, as a user | Minutes | Broken journeys, wiring and config faults |
| Contract | The agreement between two services | Seconds | One team breaking another team's client |
| Property | Invariants over generated inputs | Seconds | The cases nobody thought to write down |
The conventional advice is a pyramid: many fast, narrow tests underneath, fewer slow, broad ones on top. The reasoning is economic. Broad tests are more convincing and much more expensive — slower to run, harder to write, and prone to failing for reasons that have nothing to do with your change.
A failure caught by a unit test costs seconds. The same defect caught in review costs an hour of someone else's attention. In production it costs an incident, and possibly a user who does not come back. That gradient is the entire justification for everything on the left of the map.
Tests as the contract with an agent
Agents are strikingly good at writing tests, and this is a trap as well as a gift. A test written after the fact by the same process that wrote the code tends to encode what the code does, not what it should do — and it will pass forever while being wrong. The useful discipline is to make the expected behaviour the input: write or review the assertions yourself, then let the agent make them pass.
08Security: checks in the road, not a gate at the end
Security review used to happen once, near release, performed by a separate team with the power to say no and no time to say it usefully. Moving those checks into the pipeline — "shift left" — makes them boring and constant instead of rare and dramatic.
- Dependency scanning. Most code in a modern application was written by strangers. Scanners compare your locked dependency tree against known vulnerability databases on every build.
- Static analysis. Pattern-matching the source for injection, unsafe deserialisation, weak randomness and the other recurring shapes of mistake.
- Secret scanning. Catching the API key that was pasted into a config file, ideally before the commit ever reaches the server — because once pushed, it must be rotated, not deleted.
- Provenance. Signed commits and signed artefacts, plus a software bill of materials listing exactly what went into a build, so that when a component turns out to be compromised you can answer "were we affected?" in minutes.
- Least privilege. Build systems hold the credentials that can deploy. Treat the pipeline as production infrastructure, because to an attacker it is the most valuable machine you own.
Two risks that arrived with agents
Prompt injection. An agent that reads issue comments, web pages, dependency documentation or logs is reading text an attacker may control — text that can carry instructions. Treat everything an agent ingests as untrusted input, and never let the ability to read something imply the authority to act on it.
Plausible dependencies. Models occasionally suggest packages that do not exist, and attackers publish those names on purpose. Every dependency an agent adds deserves the same look you would give one a stranger added — because that is what happened.
09Release: small steps you can walk back
Deployment used to be an event: a date, a checklist, a room of people, a rollback plan nobody had rehearsed. The modern version is deliberately anticlimactic. Ship small changes often, and make each one easy to reverse.
That requires separating two things that sound identical. Deployment is putting new code on the servers. Release is letting users reach it. Feature flags split them apart, so code can ship dark for weeks and be switched on for 1% of traffic on a Tuesday morning — and switched off again in seconds, without a deploy.
Blue-green
Two identical environments. Deploy to the idle one, verify, switch traffic across. Rolling back is switching back.
Canary
Send a small slice of real traffic to the new version and compare its error and latency against the old before widening.
Rolling
Replace instances a few at a time, so a bad version never accounts for all capacity at once.
Feature flags
Release as a runtime decision. Powerful, and quietly expensive: every flag is a branch in production that someone must delete.
Staging exists to rehearse this. It is a replica of production — same shape, less traffic, fake data — and it catches configuration and wiring faults that no unit test will. It also lies, reliably, about anything involving scale, real data, or the odd things real users do. Treat a green staging run as evidence, not proof.
The rollback rule
When something breaks after a release, restore service first and understand it afterwards. Debugging in front of affected users is a choice to extend the outage. The corollary is that rollback has to be a routine, tested path — a plan nobody has ever executed is not a plan.
10Running it: the part that never ends
Software is not finished when it is released; it starts being used, which is when most of the truth about it appears. Observability is the ability to answer questions about a running system that you did not think to ask in advance.
Metrics
Cheap numbers over time — request rate, error rate, latency percentiles, saturation. Good at telling you something is wrong.
Logs
Discrete records of what happened. Structured, they are searchable evidence; unstructured, they are an expensive diary.
Traces
The path of one request across every service it touched, with timings. Usually the fastest way to find where it is wrong.
Alerts
Rules that wake a human. Should fire on symptoms users feel, not on every twitch a dashboard makes.
Teams write down a service level objective — say, 99.9% of requests succeed within 300 ms over 30 days — which converts an argument about whether things feel slow into arithmetic. The amount of failure the objective permits is an error budget; spend it on shipping while there is budget left, and stop shipping to spend it on reliability when there is not.
Blameless, and precise about it
After an incident, write down what happened, in what order, and what made the failure possible. "Blameless" does not mean vague: it means the question is which safeguard was missing, not which person typed the command. Engineers who expect to be punished report less, later — and the second failure is always more expensive than the first.
11Feedback: how the loop closes
The last stage is the first stage. Usage data, error rates, support conversations and the things people say out loud all become the input to the next round of discovery. A lifecycle without this arrow is not a lifecycle; it is a factory producing features nobody asked to keep.
Four measurements have proved unusually durable for describing how well the loop turns. They are worth knowing because they are hard to game individually — pushing on one alone breaks another.
| Measure | Question it answers |
|---|---|
| Deployment frequency | How often do changes reach users? |
| Lead time for changes | How long from commit to running in production? |
| Change failure rate | What share of releases cause a problem? |
| Time to restore service | When something breaks, how fast is it back? |
The counter-intuitive finding, repeated across years of research, is that speed and stability rise together. Teams that release frequently are not being reckless — releasing small changes often is precisely what makes each one safe, easy to diagnose and cheap to reverse. The slow, careful, quarterly release is the risky one.
Beware measuring individuals with any of this. Counting commits or lines per person reliably produces more commits and more lines, and nothing else.
12Where agents actually fit
An agent is not a stage of the lifecycle. It is a new kind of worker that can be plugged into most of the existing stages — which is why, on the map, the agent depot sits in the middle of the circuit with cables running out to the workshop, the repository, the review gate and the observability tower, rather than occupying a station of its own.
| Stage | What an agent does well | What stays human |
|---|---|---|
| Discovery | Clustering feedback, drafting criteria, listing edge cases | Deciding what is worth building, and for whom |
| Writing code | Scaffolding, mechanical refactors, wide migrations, tests | Architecture, trade-offs, saying "not like this" |
| Review | First-pass triage, checklists, spotting mechanical faults | Judgement about intent, and accountability |
| CI | Diagnosing failures, unpicking flakes, fixing the build | Deciding what the pipeline must guarantee |
| Testing | Filling in coverage, generating cases, reproducing bugs | Choosing what correct means |
| Operations | Summarising incidents, correlating signals, drafting timelines | The call to roll back, and telling users the truth |
A pattern runs down that table. Agents are strong wherever the work is bounded, verifiable and tedious — where there is a clear signal saying whether the attempt succeeded. They are weak wherever the work is deciding what "succeeded" means. That boundary is not about model capability; it is about who is answerable to the people affected.
Multiple agents
The obvious next move is to run several at once — one per ticket, or a planner directing workers. It works, and it moves the bottleneck again: to merge conflicts between changes written in parallel, to CI capacity, and above all to the humans who must still understand what shipped. Parallelism multiplies output; it does not multiply attention.
13Working with agents, in practice
The teams getting real value out of this are not doing anything exotic. They are applying the lifecycle they already had, with a few adjustments that follow from one observation: the agent is a fast, capable, literal-minded colleague with no memory of yesterday and no stake in the outcome.
- Make the pipeline the contract. An agent's work arrives as a pull request and goes through the same checks as anyone's. No side doors, no direct pushes to main, no privileged path.
- Specify before you generate. Most bad agent output is a faithful implementation of an under-specified request. Time spent writing down the expected behaviour is repaid immediately.
- Keep diffs small and single-purpose. The limiting factor is a human's ability to review. A change that cannot be reviewed cannot be trusted, however green the checks are.
- Give it a sandbox and real permissions. An isolated environment with the tools to run the tests, and deliberate boundaries around secrets, production credentials and anything with side effects outside the repository.
- Write down the project's context. Conventions, architecture decisions, the reasons behind the odd bits. Agents read documentation more reliably than people do — and the same file helps the next new joiner.
- Check the tests before the code. If the assertions are right and honest, a passing implementation is a much smaller thing to verify.
- Evaluate the workflow, not the vibes. Keep a set of representative tasks and measure how often the pipeline gets to green without human rescue. It is the only way to tell a change of setup from a change of mood.
- Keep a person accountable. Someone approves, and that someone owns what happens next. "The agent wrote it" is not a position anyone can defend to an affected user.
What the map is really showing
Look at the circuit behind this page. The agent depot has cables to almost every station — but the track still runs through review, build, test, security and staging before it reaches the city where people live. Adding a fast new worker to a pipeline does not remove the reasons the pipeline exists. It makes them load-bearing.
✳Glossary
| Term | In one line |
|---|---|
| SDLC | The repeating sequence by which an idea becomes running software and then evidence for the next idea. |
| Repository | The versioned store holding a project's code and its entire history of changes. |
| Pull request | A proposed change, opened for review and automated checks before it joins the main branch. |
| CI | Continuous integration: merging work frequently and building and testing every change automatically. |
| CD | Continuous delivery or deployment: every change that passes the pipeline is releasable, or released. |
| Artefact | The built, versioned output of the pipeline — a binary, a container image, a package. |
| Staging | A production-shaped environment used to rehearse a release. |
| Canary | Exposing a new version to a small slice of real traffic before the rest. |
| Feature flag | A runtime switch that separates deploying code from releasing behaviour. |
| Rollback | Returning to the previous known-good version to restore service. |
| Observability | Metrics, logs and traces good enough to answer new questions about a live system. |
| SLO | A written target for reliability, and the budget of failure it implies. |
| Postmortem | The blameless write-up of an incident and the safeguards it revealed were missing. |
| Technical debt | Accepted structural compromise that makes future change slower until it is repaid. |
| SBOM | A software bill of materials: the inventory of everything that went into a build. |
| Coding agent | A language model in a loop with tools, taking multi-step action against a goal in a codebase. |
| Prompt injection | Hostile instructions hidden in content an agent reads, aimed at making it act against its operator. |
| Eval | A repeatable task set used to measure whether an AI-assisted workflow actually works. |
→Go deeper
- Continuous Integration — Martin Fowler on what the practice actually requires.
- DORA — the research programme behind the four measures above.
- Pro Git — the free book; chapters 2 and 3 are the useful ones.
- Google SRE Books — service level objectives, error budgets and incident response, free online.
- OWASP Top Ten — the recurring shapes of application security failure.
- SLSA — a framework for supply chain integrity and build provenance.
- How the Internet Works — the other half of this series: what happens once your change is live.