DocsGENERALSCALE-SPECIFICCONTESTED

Docs Close to Code

Proximity and ownership are the only defences against decay that work without discipline. What belongs in the code, what belongs in the repository, and why the wiki entry is the one that rots.

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

Where should a piece of documentation live so that the change which invalidates it is forced to touch it?

The requirement

The team has documentation in four places — code comments, a docs/ folder, a wiki space and a pinned Slack message — and no rule about which goes where. Three of them describe the deployment process and they disagree.

The obvious build

Put everything in the wiki. It is searchable, everyone in the company has access, it does not clutter the repository, and non-engineers can read and edit it.

Why it breaks

The wiki is not in any diff. A pull request that changes the deployment process cannot show the reviewer that a wiki page has become wrong, so the only mechanism that could catch it is absent by construction.

How it breaks as requirements change
  • The wiki is not in any diff. A pull request that changes the deployment process cannot show the reviewer that a wiki page has become wrong, so the only mechanism that could catch it is absent by construction.
  • It has no owner that anything enforces. A repository has CODEOWNERS and a review requirement; a wiki page has a "last edited by" from two years ago (Code Ownership).
  • It is editable by anyone and versioned in a way nobody reads, so a well-meaning edit by someone with partial knowledge is indistinguishable from an authoritative one.
  • As the system changes, the wiki accumulates pages that describe systems that no longer exist, and search delivers them confidently to whoever is in the most hurry (Documentation Decay).
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
  • Support, product and partner integrators cannot read the repository, and pretending otherwise does not make them able to.
  • The wiki is where the rest of the company looks first, and that is not going to change because engineering prefers Markdown in git.
  • Documents in the repository are reviewed by engineers only, which is a benefit for accuracy and a limitation for reach.
Invariants
  • Every document that describes current behaviour has a change trigger, and it must live inside that trigger's blast radius or it will not be updated (Documentation Decay).
  • One fact has one home. Anywhere else it appears must be a link, never a copy, because copies diverge silently (Duplicate Knowledge).

Who owns what, and where the seams fall

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

Responsibilities
  • The code owns anything expressible as a name, a type, a constant or a test — those cannot go stale without something failing (Naming).
  • The repository owns anything that changes when the code changes: runbooks for this service, ADRs, domain rules, the README, architecture notes for these modules.
  • The wiki owns what changes when the organisation changes: who owns what, how to escalate, glossaries for a non-engineering audience, and pointers into repositories.
  • CODEOWNERS owns enforcement. A document with a review requirement has a person who must look at every change to it, which is the only reliable form of ownership (Code Ownership).
Boundaries
  • The boundary is the change trigger. Ask what event makes this document wrong, and put the document where that event happens.
  • A second boundary is the audience: material for people without repository access has to live outside it, and the honest answer is that some duplication of *pointers* is the price (Types of Documentation).
  • Between the two, the rule is one-directional: the wiki links into the repository, never the reverse, so the authoritative copy is always the one that travels with the code.

Three homes, one question

The decision is not about tools or preference. Ask what event makes this document wrong, and then ask whether a person will be looking at the document when that event happens. If the answer is no, the document is in the wrong place and no amount of discipline will fix it.

That single question sorts almost everything, and it explains why the wiki entry is the one that rots: nothing about a code change brings anyone near it.

  • In the code — anything expressible as a type, a constant, a test name or a comment. It cannot go stale without something failing (Units in Names and Types).
  • In the repository — anything whose change trigger is a code change: this service's runbook, ADRs, domain rules, the README (Architecture Decision Records).
  • In the wiki — anything whose change trigger is organisational: ownership, escalation, cross-team glossary, and links to the repositories.
  • Nowhere — anything you will not maintain. Deleting it is a defence, not a loss (Documentation Decay).
A code change, and what it is forced to touch
cannot change one without the othersame diff, same reviewerno link, no notificationA pull request changes behaviourTypes, names, tests, commentsdocs/ in the same repositoryWiki pageReview sees the diffWrong, silently, until someone acts on itCaught before merge
UserLLMAgentToolDataDecisionHumanGuardrail

The same runbook, in two places

FRAMEWORK-SPECIFICThis assumes the deployment target is named in the repository at all. On a platform where deployment is configured entirely in a hosted UI, the rename never appears in any diff and proximity buys nothing — there the defence has to be a drill or an automated check against the live environment, not co-location (Infrastructure as Code).

It is worth seeing what proximity changes in practice, because the content of the two documents can be identical and their life expectancy is not.

The difference is not quality of writing. It is whether the person who renames the deployment target is standing in front of the document at the moment they rename it.

Same content, different blast radius
Wiki: "Payments — deploy and rollback"
Confluence > Engineering > Payments > Deploy
Last edited 14 months ago by someone who has left

  4. Restart the worker pool:
     kubectl rollout restart deploy/payments-workers

Not in any diff. No owner a tool enforces. Found by
search, by whoever is in the biggest hurry.
Repository: `payments/docs/runbook.md`
payments/docs/runbook.md   (CODEOWNERS: @payments)

  4. Restart the workers:
     kubectl rollout restart deploy/payments-workers

The PR that renamed the deployment also touched this
file - grep found it in the same repo. Reviewed by the
same person who reviewed the rename. Reverts with it.

The right-hand version is inside the blast radius of the change that invalidates it: a rename is greppable in the same tree, the diff shows both, and the same reviewer sees them together. The left-hand version can only be corrected by someone who already knows it is wrong, which is exactly the person who does not need it.

How the arrangement fails anyway

Proximity is necessary and not sufficient, and the failures are worth naming because each one looks like the practice is working.

Failures of co-location
TriggerSymptomCauseResponse
A docs/ directory is added with no CODEOWNERS entryPages go stale at the same rate as the wiki didProximity without enforced ownership — nobody is required to lookAdd the ownership rule; a review requirement is what makes proximity bite (Code Ownership)
Everything is moved out of the wikiSupport rebuilds their own guide from chat answersAn audience without repository access was removed from the designKeep routing and org context in the wiki, linking into the repository for facts (Types of Documentation)
A repository is renamed or splitEvery wiki link 404s, quietlyLinks are an undeclared dependency in the wrong directionCheck links in CI where you can, and prefer one durable index page over many deep links
Infrastructure changes outside the repositoryA co-located runbook is wrong despite everything being done rightThe change trigger lives in another team's system entirelyProximity cannot help here — exercise the runbook in a drill instead (Restore Drills)
The same fact is written in the README and the runbookThey disagree after one is updatedTwo copies of one piece of knowledgeOne home, everything else links to it (Duplicate Knowledge)

How to build it

Most important first.

  • Push facts down the ladder as far as they will go: into a type, then a named constant, then a test, then a comment, then a document in the repository. Each rung down is harder to falsify silently (Units in Names and Types).
  • Put service documentation in the service's repository, in a docs/ directory reviewed with the code, so a change and its documentation are one pull request (Runbooks).
  • Add a CODEOWNERS entry for the docs directory. Ownership that a tool enforces survives people changing teams; ownership by convention does not.
  • Keep in the wiki only what does not change when the code changes — org structure, escalation paths, cross-team glossaries — plus links to the repositories for everything that does (Knowledge Sharing).
  • Where a non-engineering audience genuinely needs a fact that lives in the code, generate their page from the same source rather than writing it twice (OpenAPI: Describing the Contract, Not Designing It).
  • Delete the pinned Slack message. Chat is a transport, not a store, and a pinned message is documentation with no owner, no version and no search that anyone outside the channel can use.

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
  • With documentation in the repository, the next change costs a few extra lines in the same pull request and gets reviewed by the same person who reviewed the code — a small, visible, recurring cost.
  • With documentation in a wiki, the same change costs nothing today and creates an undated liability, which is why it is chosen and why it fails. The cost lands later, on someone else, during an incident.
  • The change after that is where proximity compounds: because the document is versioned with the code, a revert reverts both, a bisect shows both, and a reader on an old release sees the documentation for that release rather than for main.
What the recommended approach costs
  • Repository documentation is invisible to everyone without a git client, which is most of the company. That is a real cost and the honest reason wikis exist.
  • Review requirements on documentation slow down documentation changes, including good ones, and a barrier to fixing a document means some documents stay wrong.
  • Splitting by change trigger means a reader must know which trigger applies to find the page — so discovery has to be solved separately, usually by one index that is allowed to be a list of links and nothing else.

What can go wrong

Failure modes
  • The docs/ directory is created and nobody is required to review it, so it becomes a wiki that happens to be in git — proximity without ownership buys much less than it looks like it should.
  • Everything is moved into the repository on principle, support cannot find anything any more, and they rebuild their own wiki from questions in chat — now there are two sources and one of them is hearsay.
  • The wiki links into the repository, the repository is renamed, and every link breaks silently. Links are a dependency and need the same care as any other (Dependency Direction).
  • Documents are co-located but not owned, and when the author changes team the directory is maintained by nobody while looking maintained.
Dependencies, and their direction
  • A document in the repository depends on the code and travels with it: a branch, a revert or a repository split carries both, and history is preserved.
  • A wiki page depends on the code with no link back, on the wiki product, on its permission model and on its search index — four dependencies, none of them in the change's path.
  • Generated pages depend on the source of truth in the correct direction, which is the only arrangement that cannot drift (Schema-First vs Code-First).
Misreads
  • "Everything in the repository." That abandons every reader without repository access, and they do not stop needing answers — they start asking people, which is more expensive than the wiki was (Types of Documentation).
  • "Proximity is enough." Proximity without enforced ownership decays more slowly and still decays. CODEOWNERS is the other half (Code Ownership).
  • "The wiki is the problem." The tool is not the problem; being outside the change's blast radius is. A repository docs/ folder nobody reviews has the same disease.
  • "Just keep them in sync." Two copies of one fact diverge, always, and the only stable arrangements are one copy or a generated copy (Duplicate Knowledge).
Smells this explains
  • duplicate-knowledge

Testing it, and how it ages

What to test, and at which boundary
  • Fail CI when a generated document differs from its source, which converts the entire class of drift into a build failure.
  • Check links in the repository as part of the build; a broken link is the cheapest detectable form of decay there is.
  • Exercise runbooks in drills. Proximity keeps a runbook current with the code and does nothing about infrastructure changing underneath it (Restore Drills).
How this design ages
  • Repository documentation tends to survive reorganisations and tool migrations because it is text in git, which is the most durable format any organisation has.
  • Wiki spaces get migrated every few years and lose structure each time, which is why anything genuinely load-bearing should not be there.
  • As a team grows, the wiki's legitimate role narrows to routing and org context, and everything technical migrates toward the repositories — usually after an incident makes the case that no argument could (Learning Across Incidents).

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 a document survives only if the change invalidating it is forced to touch it is a claim about process visibility, so it holds regardless of tooling — the same logic applies to a monorepo, a wiki, or a folder of Word files on a share.
  • SCALE-SPECIFICOn a small team with one repository, "in the repo" and "in the wiki" barely differ, because the same three people read both weekly. Past the point where support, product or another engineering team are readers, the split becomes structural: the repository holds truth, the wiki holds routing, and confusing the two is how three deployment guides come to disagree.
  • CONTESTEDThe strongest case for the wiki: documentation that nobody can find is worth nothing, and in most organisations the wiki is genuinely where people look, has better search, and is editable by the people who spot errors first — often support, who cannot open a pull request. Teams who have moved everything into git report that non-engineering readers simply stopped reading, and that the accuracy gain was paid for in reach. That trade is real; the position taken here is that reach for pointers and accuracy for facts is the arrangement that loses least, not that the wiki is a mistake.

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 — the documents whose change trigger lives outside your repository cannot be defended by proximity at all, and the only remaining control is rehearsing them.