DocsGENERALSCALE-SPECIFICLIFETIME-SPECIFIC

Types of Documentation

API docs, ADRs, runbooks, READMEs, domain rules and migration notes are six different products with six different audiences and six different decay rates.

The requirement, the obvious build, and why it breaks

Every lesson starts where the work starts: someone asked for something, and the first implementation that comes to mind survives until the requirement changes.

The question

Who is this document for, what do they need from it, and how fast does it become wrong?

The requirement

A team is told to "document the service". Nobody says for whom, so they write one long page that a newcomer finds too detailed, an on-call engineer finds too vague, and an integrator finds incomplete.

The obvious build

Write a good README and keep it up to date. Everything anyone needs to know about the service should be discoverable from one place.

Why it breaks

The audiences want incompatible things. A newcomer wants orientation and omission; an on-call engineer at 3am wants a numbered list with no prose; an integrator wants exhaustive field-level reference. One document optimises for none of them.

How it breaks as requirements change
  • The audiences want incompatible things. A newcomer wants orientation and omission; an on-call engineer at 3am wants a numbered list with no prose; an integrator wants exhaustive field-level reference. One document optimises for none of them.
  • They decay at different rates. Endpoint reference goes wrong with every schema change; a runbook goes wrong when infrastructure moves, which is rarer but far more dangerous; an ADR never goes wrong at all.
  • As the service changes, the single page grows monotonically, because nobody can tell which sections are still load-bearing and deleting from a shared document requires knowing all its readers.
  • The parts most expensive to get wrong end up buried among the parts that are merely nice to have, so the reader in an incident has to skim a tutorial to find a command.
RequirementConstraintsInvariantsResponsibilitiesBoundariesInterfacesStateDependenciesFailureImplementationTestsFeedbackEvolution

What limits the solution, and what must never stop being true

This domain leads with these two. A design that ignores its constraints is not a design, and an invariant nobody named is one nothing is protecting.

Constraints
  • Every document is maintained by people with other work, so total documentation volume is capped by the team's willingness to keep it true (Documentation Decay).
  • Some audiences cannot read the repository at all — support, product, a partner's integration team — which constrains where their documents can live.
  • Reference material for a public API is a contractual artefact and cannot be as informal as the rest.
Invariants
  • Every document has exactly one primary audience. A document that serves three is failing all three, and merging them is the most common way documentation becomes unmaintainable.
  • Every document that describes the present must have an owner and a way to be found wrong. A document that describes the past — a decision, an incident — needs neither, which is why those are the durable ones.

Who owns what, and where the seams fall

Responsibilities decide boundaries; boundaries decide what an interface has to say.

Responsibilities
  • Reference documentation is owned by the code it describes, and should be generated from it wherever the toolchain allows (OpenAPI: Describing the Contract, Not Designing It).
  • Runbooks are owned by the team on call for the service, and are only real if they have been executed by someone who did not write them (Runbooks).
  • Decision records are owned by nobody after they are written, which is their defining property: they are historical statements and are never updated, only superseded (Architecture Decision Records).
  • The README is owned by whoever onboards next, because they are the only person who can tell whether it works.
Boundaries
  • The boundary between kinds is the audience, not the subject. The same retry policy legitimately appears as a generated field description, a paragraph in a runbook and a sentence in an ADR, each saying a different thing to a different reader.
  • Anything that changes with the code belongs beside the code; anything that changes with the organisation belongs where the organisation looks (Docs Close to Code).
  • Migration notes have a hard time boundary: they are operational instructions for a window, and after that window they are actively misleading and should be deleted (Expand and Contract).

Six documents, six decay rates

The most useful thing to know about a document is not what it contains but what makes it wrong, because that determines where it must live and who must own it. Sorted that way, the categories stop being a taxonomy and start being a maintenance plan.

The column that changes behaviour is the last one. A document whose failure is silent needs a mechanism; one whose failure is loud can be left to fix itself.

  • Only two of the six are safe to leave unowned: the ADR, because it cannot become false, and migration notes, because they get deleted (Architecture Decision Records).
  • The runbook is the highest-consequence entry: it decays slowly, so nobody worries about it, and it is read only when something is already going wrong (Runbooks).
DocumentAudienceWhat makes it wrongDecay rateWhere it belongs
API / reference docsA caller integrating against youAny schema or route changeFast, and silent unless generatedGenerated from the code, published with the API
ADRA maintainer in three years asking "why is it like this"Nothing — it describes a past decisionNone; superseded, never editedIn the repository, numbered, immutable
RunbookOn-call at 3am, possibly from another teamInfrastructure changing under itSlow but dangerous — wrong exactly when it is usedBeside the service, executed in drills
READMEA newcomer on day oneToolchain and setup driftMedium; the setup section rots firstRepository root, short, mostly links
Domain rules / glossaryEveryone, including product and supportThe business changing a definitionMedium, and quietly authoritativeBeside the domain code it describes
Migration notesAn operator during a specific windowThe window closingInstant on completion — then actively harmfulIn the migration's own directory, deleted after

A document has reasons to change, like any other unit

The reason a single "service documentation" page becomes unmaintainable is exactly the reason a god object does: it has too many reasons to change, owned by too many different people. It is worth applying the same analysis, because the conclusion is the same (Single Responsibility, Carefully).

responsibilitiesdocs/payments-service.mdThe one-page service doc
Knows
  • the endpoints and their fields
  • how to run the service locally
  • what to do when the queue backs up
  • why the provider abstraction exists
  • the definition of a settlement
  • how to run the 2024 currency migration
Does
  • onboards newcomers
  • serves as an integration reference
  • serves as the incident runbook
  • records design rationale
  • defines domain vocabulary
Depends on
  • the API schema
  • the local toolchain
  • the deployment topology
  • the alerting setup
  • the domain glossary
  • a migration that finished a year ago
Changes when — 6 distinct reasons
  • a field is added
  • the build tool changes
  • infrastructure moves
  • a design decision is revisited
  • the business redefines a term
  • a migration completes

Six reasons to change, owned by four different teams, in one file with one review process. Nobody can safely delete a paragraph because nobody knows all its readers, so it only grows — and the migration section, which should have been deleted a year ago, is still there being followed. Split by audience and the deletions become possible, which is the whole point (Documentation Decay).

How each kind actually fails

These are the recurring failures for each document type. Note that they are not variations on "it went stale" — each kind fails in its own way and needs its own defence.

Failure by document type
TriggerSymptomCauseResponse
A field is added to the APIAn integrator sends the old payload and gets a validation error they cannot diagnoseHand-written reference docs diverged from the schemaGenerate the reference from the schema and fail CI on a diff (OpenAPI: Describing the Contract, Not Designing It)
The worker pool is replacedThe runbook's restart command targets something that no longer exists, during an incidentThe runbook lives in a wiki that infrastructure changes never touchMove it beside the service and exercise it in a drill (Restore Drills)
The build tool is upgradedA new hire loses a day on setupNobody on the team has run the README steps in a yearMake the next joiner's first PR the README fix, from their own notes
A migration completesAn operator runs a backfill against a schema that no longer has the columnMigration notes with no expiryDelete them as the last step of the migration checklist (Expand and Contract)
A decision is revisitedThe ADR now describes what was decided later, and the original reasoning is goneThe ADR was edited instead of supersededWrite a new record that supersedes the old one and leave the old one in place (Architecture Decision Records)

How to build it

Most important first.

  • Name the audience before writing a word, and write for exactly that person. "A support engineer who has never opened this repository" and "an integrator with our OpenAPI file" produce different documents from the same facts.
  • Generate what can be generated. Types, schemas and route definitions already contain the reference material, and a generated document cannot silently diverge from the code (Schema-First vs Code-First).
  • Keep runbooks as numbered, copy-pasteable steps with the expected output of each, and prefer a script over prose wherever the step is deterministic (Runbook Anti-Patterns).
  • Keep the README short enough that it is credible: what this is, how to run it, how to test it, where everything else lives. Its job is routing, not content.
  • Write domain rules and glossary next to the domain code, so a change to the rule and a change to its description are one commit (Naming and Domain Language).
  • Give migration notes an explicit expiry date and delete them on it, because an instruction for a state the system is no longer in is the most dangerous document in the set.

What the next change costs

The field this whole domain exists for. A structure is only better if it makes the change after this one cheaper — and it is worth saying which changes it does not help.

Cost of the next change
  • Under one merged document, every change to the service requires reading the whole page to decide what is now wrong, so the cost of maintenance grows with total volume rather than with the size of the change.
  • Under separated documents, a schema change regenerates reference material and touches nothing else; an infrastructure change touches the runbook only; a design decision adds an ADR and edits nothing.
  • The next change gets cheaper in a specific way: because each document has one audience and one owner, deleting from it is possible. Deletion is the maintenance operation that keeps documentation trustworthy, and it is the one a merged document makes impossible.
What the recommended approach costs
  • Splitting by audience means more documents, more places to look and more chances for two of them to disagree about the same fact.
  • Generated reference material is always accurate and often unreadable: it describes fields perfectly and explains nothing about intent, so a hand-written narrative layer is still needed on top.
  • Deleting aggressively occasionally loses something that turns out to have been the only record of a decision, which is the argument for writing ADRs rather than for keeping everything.

What can go wrong

Failure modes
  • One page for every audience, which then cannot be deleted from because nobody knows who relies on which paragraph.
  • A runbook that has never been executed by anyone but its author, so the missing step three is discovered during an incident (Restore Drills).
  • Reference documentation written by hand next to a schema that generates its own, producing two sources that disagree and no rule about which wins.
  • Migration notes left in place after the migration, so the next operator follows instructions for a system that no longer exists.
  • ADRs edited in place to reflect what was later decided, which destroys the one property that made them durable (Architecture Decision Records).
Dependencies, and their direction
  • Reference docs depend on the schema, so they should be produced by it rather than written alongside it — a dependency you can automate is not a dependency that rots.
  • Runbooks depend on infrastructure, which is owned by a different team on a different change cadence, which is why they go wrong without anyone in the service's repository doing anything (Infrastructure as Code).
  • ADRs depend on nothing. They describe a decision at a time, so no later change can make them false — only superseded (Decision Records).
  • The README depends on the build, the toolchain and the onboarding process, which is a wide and mostly invisible dependency surface.
Misreads
  • "More documentation is better." Volume is the enemy of accuracy: every page written is a page that must be kept true, and the ones nobody maintains are the ones that cause harm (Documentation Decay).
  • "Documentation should be in one place." Discovery should be in one place. The documents themselves belong wherever their change trigger lives.
  • "Generate everything." Generated docs describe structure and cannot describe intent, constraints or rejected alternatives — which is most of what a reader actually needs.
  • "ADRs are just design docs." A design doc argues for a proposal and is edited until it is agreed. An ADR records a decision and is never edited afterwards, which is precisely why it does not decay (Architecture Decision Records).

Testing it, and how it ages

What to test, and at which boundary
  • A runbook is tested by having someone who did not write it execute it, ideally in a game day rather than an incident (Restore Drills).
  • A README is tested by a new hire following it on a clean machine, and the only useful output is the list of places they got stuck.
  • Reference documentation is tested by generating it in CI and failing the build on a diff, which converts a decay problem into a build failure (OpenAPI: Describing the Contract, Not Designing It).
  • ADRs cannot be tested and do not need to be. They are claims about what was known on a date.
How this design ages
  • Reference material trends toward generation as tooling improves, and hand-written endpoint tables are the first thing to delete when it does.
  • Runbooks trend toward automation: every step that can be scripted eventually is, and the runbook shrinks to the judgement calls between scripts (Toil).
  • ADRs accumulate and that is correct — the collection is the design history, and superseded ones are as valuable as current ones because they record what was tried.
  • READMEs decay in a characteristic way: the setup section rots first, because it is the part nobody on the team runs any more.

Where this applies

This domain's advice is contested more than most. These labels say what each claim is specific to — and where CONTESTED appears, the note gives the strongest form of the opposing view rather than a caricature.

  • GENERALThat different audiences need different documents follows from the audiences having different questions, so it holds for any software with more than one kind of reader — the specific set of six will differ by organisation.
  • SCALE-SPECIFICAt three engineers who are all on call, the runbook, README and domain rules genuinely can be one page, because the audience is one person wearing three hats. The split becomes mandatory as soon as any reader exists who did not build the thing — a support team, a partner, a second engineering team — and the transition usually happens before anyone schedules it.
  • LIFETIME-SPECIFICFor a service with a known two-year life, migration notes and ADRs are the ones worth keeping and the tutorial layer is not; for a platform expected to outlive its authors, the ADR collection becomes the most valuable document in the repository because it is the only record of why the obvious alternatives were not taken.

Where the depth lives

This domain teaches the codebase-level structure and hands the rest off.

Domains that do not exist yet
  • Testing & Reliability Engineering — a runbook is only trustworthy if it has been executed under conditions resembling the ones it is written for, which makes drills a documentation practice as much as a reliability one.