tech, developers, and the code underneath

issue 203· essay·

What "done" actually means

Every team has a definition of done and most of them are a checklist nobody reads. Here is the version that changes behaviour.

Ask five engineers on the same team whether a ticket is done and you will get three answers: the code is written, the code is merged, the code is in production. All three are defensible and they differ by days.

That gap is where most delivery confusion lives, and it is cheap to close.

the honest definition#

A change is done when the outcome it was meant to produce is observable, and the team would find out if it stopped.

Not "the code is merged." Merged code that is not deployed is inventory. Deployed code that nobody looked at is a hypothesis.

That framing sounds demanding and mostly is not, because for a large share of work the observation is trivial — the feature is behind a flag, the flag is on for the team, someone clicked it. The point is that someone did.

the checklist that actually helps#

Most definition-of-done checklists fail because they list activities rather than properties. "Tests written" is an activity. "The change is covered by a test that would fail if it regressed" is a property, and it is checkable.

The version I have seen work is short:

  • The change does what the ticket asked, verified by someone other than the author — a test, a reviewer, or the person who asked for it.
  • It is in production, or in a deliberate queue with a named release date.
  • A regression would be caught by a test, a metric, or an alert. If none of those apply, that is a decision, not an oversight.
  • Its failure mode is known. Someone can say what happens when it breaks.
  • It is documented where the next person will look — which is usually the code, sometimes the runbook, rarely the wiki.
  • The flag, the branch, and the dead code are cleaned up, or ticketed with a date.

Six lines. If a change satisfies them, it is done in a way that survives the author going on holiday.

the two failure modes#

Done-done-done. Teams that discover the ambiguity often respond by inventing stages: "dev done", "QA done", "really done". This makes the confusion explicit without removing it, and adds ceremony. The fix is one definition, not three adjectives.

Definition as theatre. A twenty-item checklist copied from a blog post, pasted into the wiki, referenced never. If your definition of done is not enforced by something — a pull request template, a merge check, a question someone actually asks in standup — it is decoration.

The test: pick a ticket closed last week and walk the list. If it fails two items and nobody noticed, the definition is not operating.

the part about flags and branches#

The most common way "done" quietly is not: the feature ships behind a flag at 10%, works, and then nobody finishes the rollout. Three months later the flag is still at 10%, the old code path is still there, and the ticket has been closed since March.

That is not done. It is half-deployed with the cleanup unfunded, and it is how codebases accumulate the dual implementations that make everything else harder.

Make the rollout part of the ticket, not a follow-up. A change is not finished when it is enabled for some users; it is finished when the decision has been made either way and the losing path is deleted.

why it is worth the argument#

A shared definition of done is what makes "how much is left" answerable. Without it, the burn-down is measuring something nobody agrees on, estimates are uncomparable between people, and "almost done" means whatever the speaker wants.

It costs one conversation and a paragraph in the repository. It is the cheapest process improvement available to most teams and it is skipped because it sounds like process rather than engineering.

get README in your inbox

One dispatch, no noise. Tech and developer news, plus the occasional long piece on the craft.

subscribe →