Developer documentation has a specific reader with specific habits: an engineer who is busy, skeptical, and looking for exactly one fact. They will not read your beautifully written narrative. They will skim for a heading, copy a code block, and leave. Good developer docs are built for that behaviour — not against it.
Accuracy beats everything else
A developer who finds one wrong fact in your docs stops trusting all of them, permanently. From then on they read the code instead, and your docs become decoration. So the first best practice isn’t about writing at all — it’s about provenance: can a reader tell where a fact came from and whether it’s current?
- Reference docs (endpoints, schemas, types) should be generated from the source wherever possible, so they’re accurate by construction.
- Every doc should carry a signal of freshness — a last-updated date, a commit reference, a “generated from
mainata3f9b2c” line. Undated docs are guilty until proven innocent.
The README is a landing page, not an archive
A README’s job is to get a developer from zero to a running project and point them to everything else. It is not the place for your entire architecture. A strong README answers, in order:
- What is this and who is it for? (Two sentences.)
- How do I run it locally? (Copy-pasteable commands.)
- How is it structured? (A short map, or a link to one.)
- Where do I go for more? (Links to deeper docs.)
API docs: one row per endpoint, generated
API reference is where documentation pays for itself and where it rots fastest. The contract changes in code; the doc lags; an integrator builds against the stale doc; something breaks in production. Treat the API surface as generated output:
- Method, path, and a plain-language summary of what the endpoint accomplishes — not a restatement of the path.
- Auth requirement, stated explicitly per endpoint.
- Request parameters and body shape, with types.
- Response shape with a real example payload.
- The error cases a caller must handle.
If those rows are hand-maintained across a few hundred endpoints, they will be wrong within a sprint. Generating them from the handlers is the only approach that holds.
Architecture docs: diagrams over paragraphs
Engineers think in boxes and arrows. A request-lifecycle diagram (route → middleware → controller → service → repository → database) communicates the layering of a backend faster than any prose. Pair each diagram with a few sentences on the non-obvious parts: where auth happens, how errors propagate, what’s async and why.
Show, with real examples
Every abstract claim should be anchored to a concrete artifact a reader can open. “Validation happens in middleware” is weak. “Validation happens in middleware — see the Zod schema in order.validation.ts, wired in order.route.ts” is strong, because the reader can verify it in two clicks. File citations turn documentation from “trust me” into “here, look.”
Anti-patterns to retire
- The graveyard wiki: hundreds of pages, half obsolete, no dates. Prune aggressively or generate.
- Docs as a separate project: a backlog item that competes with features and always loses. Make docs part of done.
- Hedged language: “this probably calls the payment service.” If the doc isn’t sure, the reader can’t be either. State facts or omit them.
The throughline
Every best practice here reduces to one idea: a developer should be able to trust a doc without re-checking it against the code. Generate the layer that can be generated, date everything, cite real files, and put each doc where it can be found. For the reference layer specifically, VizRepo generates endpoint, schema, and architecture docs straight from your repo and keeps them synced to your wiki — so the accuracy problem is solved by construction rather than discipline.
Related reading: why documentation goes out of date and software documentation best practices.
