# Writing Good Technical Documentation ## The Core Principle Developers come to documentation with a specific question. They are not reading for enrichment. Everything about how you structure and write documentation should serve that goal: get the reader to their answer with the least friction possible. --- ## Know Your Reader and Purpose ### Define the document type Documentation serves fundamentally different purposes, and mixing them produces something bad at all of them. Before writing, identify which type you are writing: - **Tutorial:** learning-oriented; leads a reader through a task to build understanding. Success means the reader has learned something. - **How-to guide:** task-oriented; answers "how do I do X?" for a reader who already knows what they want. Success means the reader accomplished the task. - **Explanation:** understanding-oriented; answers "why does this work this way?" or "how does this fit together?". Success means the reader has a mental model. - **Reference:** information-oriented; describes the system precisely and completely. Success means the reader found the specific fact they needed. If you are writing a README, a runbook, an architecture decision record, or an API reference, each maps to one of these types. Identify it, and write accordingly. ### State your assumptions and prerequisites Developers with different backgrounds have different gaps. Naming your assumptions lets readers self-assess rather than getting confused and concluding the docs are wrong. State upfront what knowledge you assume, what must already be in place, and who the document is for. Be specific: "familiarity with Postgres replication" is more useful than "some database experience." ### Acknowledge different entry points A junior developer and a senior developer want different things from the same document. So does someone getting oriented quickly versus someone debugging a production incident. A short orientation section followed by progressively deeper detail handles most cases. Do not conflate them into a single undifferentiated wall of text. --- ## Structure and Information Architecture ### Orient before you detail Give the reader a mental model before you fill it in. State what the system does, what problem it solves, and where it fits before describing how it works. This is the top-down principle: start from the whole, then move to the parts. The exception is reference material, where readers are looking up specific facts and already have the orientation. Readers who encounter an unexplained concept have to hold it in memory until it resolves. That cognitive load compounds. Introduce concepts in dependency order: if understanding A requires understanding B, explain B first. ### Chunk deliberately A paragraph is a unit of one idea. If a paragraph contains two ideas, split it. A section is a unit of one topic. Unrelated information in the same section forces the reader to work out which parts belong together. This sounds obvious but is consistently violated when writing is produced as a stream of thought rather than after thinking. ### Signpost transitions Tell the reader where they are and what is coming. "Before configuring the cache, you will need the service account credentials from the previous section." Signposting reduces the chance of a reader following an inapplicable path and only realising it several steps in. It also reduces the need to re-read when a reader returns to a document after time away. ### Design for scanning Most readers scan before they read. They look for a heading or code block that suggests their answer is nearby. This means: - Your first sentence in each section should carry the meaning, not build up to it. - Headings should be specific and descriptive. "Configuration" is less useful than "Configuring the retry timeout." - Code blocks act as visual anchors. Readers will scan to them. - If a paragraph's opening sentence were removed and the reader had to understand the paragraph from context, you have probably buried your lead. Do not confuse scannability with breaking everything into bullet points. Bullets impose parallel structure that often does not exist, and they strip the connective logic between ideas. Use them for genuinely list-like content, not as a default prose format. ### Use progressive disclosure Present information at increasing levels of detail: an overview paragraph, followed by a fuller explanation, followed by edge cases and deep detail. Readers who only need the overview can stop; readers who need depth can continue. Signal the transition explicitly: "the rest of this section covers less common cases; if the defaults work for you, you can move on." Do not put edge cases and caveats at the same level as the main explanation, or they become noise. --- ## Writing Style ### Choose the right grammatical person Write to the reader directly using second person for anything instructional. "Run the migration" rather than "the developer runs the migration" or "one should run the migration." Second person is unambiguous about who does what and reads more naturally in instructional contexts. Use third person for describing system behaviour. "The service returns a 404 if the resource does not exist." Third person is appropriate when describing what something does, not when telling someone what to do. Avoid first person except in personal posts or explicit opinion statements. "We recommend" is common but often vague; it implies authority without earning it and is usually better replaced with a specific rationale. ### Use the imperative mood for instructions The imperative is the command form: "run", "configure", "set". It is shorter and more direct than "you should run", "you will need to configure", or "the next step is to set." For any step in a procedure, default to the imperative. ### Prefer active voice Active voice names the actor and the action directly. "The scheduler triggers the job" is clearer and shorter than "the job is triggered by the scheduler." Passive voice is legitimate when the actor genuinely does not matter or is unknown, but technical writing tends to overuse it because it sounds more formal. Formality and clarity are not the same thing. ### Avoid nominalisation Nominalisation turns verbs into nouns. Common examples: | Nominalised (avoid) | Direct (prefer) | |---|---| | make a decision | decide | | perform validation | validate | | provide an implementation of | implement | | give consideration to | consider | | have a dependency on | depend on | Nominalisations make sentences longer and the action harder to locate. Use the verb. ### Match register to document type Register is the overall formality level. A formal specification or RFC warrants formal register. A README or internal runbook does not. Applying formal register everywhere creates friction in casual-context documents; applying informal register to specifications makes them harder to treat as authoritative. Match the register to how the document will be used. ### Control sentence complexity Long, nested sentences are hard to parse regardless of vocabulary. When a sentence requires rereading, look for a natural split point. A reliable heuristic is that any sentence carrying more than one subordinate clause is a candidate for splitting. Vary sentence length. A sequence of identically structured sentences of similar length is monotonous and harder to read than prose that mixes short and long. Short sentences after a complex one give the reader a moment to absorb it. ### Eliminate ambiguous pronouns "It", "this", "they", and "which" become ambiguous whenever there are multiple possible referents nearby. If there is any possibility of ambiguity, name the referent explicitly. "This causes the connection to drop" is weaker than "the timeout setting causes the connection to drop." The cost of explicitness is a few extra words; the cost of ambiguity is the reader re-reading the paragraph. ### Use parallel structure Items in a list, steps in a procedure, and headings in a section should follow the same grammatical form. If one step starts with a verb, they all should. If one heading is a noun phrase, the others should be too. Inconsistency forces the reader to parse each item individually rather than scanning. ### Be terminologically consistent Pick one term for each concept and use it everywhere. Using "job", "task", and "worker" interchangeably, because you consider them synonymous, forces the reader to decide whether each distinction matters. If the codebase itself uses inconsistent naming, acknowledge that explicitly rather than silently standardising or reflecting the inconsistency into the docs. Define acronyms and domain-specific jargon on first use. This is especially important for cross-team documentation, where shared vocabulary cannot be assumed. ### Avoid hedging that adds no information Phrases like "it should be noted that", "it is important to mention", and "please be aware that" are preambles that delay the content. Delete them and write the content. Reserve emphasis for things that genuinely warrant it; if everything is important, nothing is. --- ## Content Decisions ### Explain intent, not just mechanics The code already shows what the system does. What gets lost is *why*: the constraint that shaped the architecture, the tradeoff that was accepted, the failure mode that informed the design. Explanations of intent have a much longer shelf-life than descriptions of behaviour, and they are what future developers, including you, need when making changes. ### Document what it does not do Honest documentation of limitations, known issues, and explicit non-goals is often more valuable in practice than feature descriptions. A developer who discovers an edge case through the documentation avoids a developer who discovers it in production. ### Document rejected alternatives For architecture and design documents, recording alternatives that were considered and rejected is extremely valuable. It prevents future developers from relitigating settled decisions, and it signals that the current approach was chosen deliberately. Include the reason for rejection, not just the fact of it. ### Use concrete examples Abstract descriptions of APIs, protocols, or behaviour are much harder to apply than an example with real values. When writing examples: - Show the common case first, then variants, then edge cases. - Use realistic values, not placeholders like `foo`, `bar`, or `example.com` where something more meaningful would fit. - Annotate non-obvious parts of an example inline rather than in a separate paragraph that the reader has to cross-reference. - If an example is necessarily simplified, say so; a reader who applies a simplified example to a real case and finds it fails will distrust the docs. ### Link rather than repeat If information exists elsewhere and is likely to remain accurate, link to it rather than repeating it. Repeated information diverges over time. However, do not over-link to the point that understanding one section requires jumping to several others; for small, self-contained facts, inline them. --- ## Maintenance and Accuracy Stale documentation is actively harmful. A developer who follows incorrect docs with confidence wastes more time than a developer who finds no docs and knows to investigate. Structural choices that reduce drift: - Keep docs in the same repository as the code they describe. Docs in a separate wiki drift; docs next to the code get updated with it. - Link docs from the code where relevant, in comments, READMEs, or inline annotations. Discoverability drives maintenance. - Date or version documentation that is likely to change. A reader who sees a document is two major versions old can weight it accordingly. - Treat doc updates as part of the definition of done for any feature or change. The most reliable signal that documentation needs updating is a developer asking a question that the docs should have answered. Treat those questions as bugs. --- ## A Note on the Curse of Knowledge Most documentation is written by someone who already understands the system and cannot remember what it was like not to. The curse of knowledge produces docs that are accurate but useless, because they skip exactly the parts that a new reader needs, treating them as obvious. The partial fix is to write for a specific, concrete reader: not "a developer", but "a developer who is familiar with distributed systems but has not used this codebase before". Specificity forces you to decide what that person knows and does not know, which makes the gaps visible. --- ## Quick Reference Checklist ### Before writing - [ ] Identify the document type: tutorial, how-to, explanation, or reference - [ ] Define your reader concretely, including what they know and do not know - [ ] State assumptions and prerequisites explicitly ### Structure - [ ] Orient the reader before presenting detail (top-down) - [ ] Keep one idea per paragraph and one topic per section - [ ] Introduce concepts in dependency order (known before unknown) - [ ] Signpost transitions between sections - [ ] Lead each section with the key point - [ ] Make headings specific and descriptive - [ ] Apply progressive disclosure: overview, then detail, then edge cases ### Style - [ ] Use second person for instructions and third person for system behaviour - [ ] Use imperative mood for procedural steps - [ ] Prefer active voice by default - [ ] Use verbs rather than nominalisations - [ ] Match register to document type - [ ] Ensure no sentence requires rereading to parse - [ ] Ensure pronoun referents are unambiguous - [ ] Use parallel structure within lists and headings - [ ] Use one term per concept consistently throughout - [ ] Define acronyms and jargon on first use ### Content - [ ] Explain intent and rationale, not just mechanics - [ ] Document limitations and non-goals - [ ] Record rejected alternatives with reasons - [ ] Use realistic example values and cover the common case first - [ ] Link to existing information rather than repeating it ### Maintenance - [ ] Keep docs in the same repository as the code - [ ] Link docs from the code - [ ] Date or version time-sensitive docs - [ ] Include doc updates in the definition of done