Documentation & Engineering Communication
Documentation & Engineering Communication
Documentation is the memory of a software system. When it's absent, knowledge lives only in the heads of the engineers who built it — and walks out the door with them. When it's present and maintained, it enables onboarding, correct usage, safe operation, and informed evolution.
What Documentation Actually Gets Read
Most documentation doesn't get read because it doesn't answer the question the reader has in the moment they have it. Effective documentation:
API/library documentation: readers want to know how to use the thing, not how it was built. Show examples first. Put common use cases at the top. Detailed parameters tables last.
README files: should answer in order: (1) what is this, (2) who is it for, (3) how do I install/run it, (4) how do I do the most common thing, (5) how do I get more help. Stop there for most projects.
Architecture documentation: readers are making decisions about the system. They need to understand structure, tradeoffs made, and constraints. Data flow diagrams and component diagrams beat prose.
Runbooks: readers are in an incident. They need step-by-step procedures that can be executed without expert knowledge. Numbered steps. Clear pass/fail conditions. Links to dashboards.
Architecture Decision Records (ADRs)
An ADR captures a significant architectural decision that would otherwise be lost to history. Six months later, when someone asks "why is this in Postgres instead of MongoDB?", the ADR is the answer.
ADR format (Michael Nygard):
- Title: "Use PostgreSQL for the orders service"
- Status: Proposed, Accepted, Deprecated, Superseded
- Context: the problem situation and forces that led to this decision
- Decision: what was decided
- Consequences: positive and negative outcomes of this decision
- Alternatives considered: why they were rejected
ADRs live in the repository (docs/adr/ or adr/) alongside the code they document. They use sequential numbering (ADR-001, ADR-002) and are never deleted — deprecated ADRs are marked as Superseded with a pointer to the new decision.
When to write an ADR: for decisions that are hard to reverse, that affect multiple teams, or where understanding the reasoning matters as much as the decision itself.
RFC Process
RFCs (Requests for Comments) are proposals for significant changes. Rather than one engineer making a unilateral decision and submitting code, an RFC documents the proposal, opens it for feedback, and records the resulting decision.
RFC structure:
- Summary: one paragraph of what this proposes
- Motivation: the problem being solved and why it matters
- Detailed design: how the proposal works in detail
- Drawbacks: honest discussion of downsides
- Alternatives: what else was considered and why this approach was chosen
- Unresolved questions: what's not decided yet
RFC lifecycle:
- Author writes RFC and opens a pull request
- Team reviews and comments (typically 1-2 weeks)
- RFC is either accepted (merged), revised (updated based on feedback), or rejected (closed)
- Accepted RFC becomes a binding commitment; implementation follows
Companies that have scaled RFC processes well: Rust, React, Ember, Figma, Stripe. The value: decisions are documented, dissent is surfaced before implementation, and authors have thought through edge cases.
Technical Writing Principles
Audience first: every piece of documentation has an audience. Who are they, what do they already know, and what question are they trying to answer? Write for them, not for yourself.
One topic per document: mixing installation, concepts, and API reference in one document forces readers to hunt. Separation by purpose (tutorials, how-tos, explanations, references) is the Diátaxis framework.
Active voice: "The system processes the request" is clearer than "The request is processed by the system."
Examples over explanations: show before you tell. One concrete example communicates more than three paragraphs of abstract description.
Maintain or remove: stale documentation is worse than no documentation — it actively misleads. Documentation must be updated with the code it documents, or deleted.
Docs as Code
Treating documentation as code means:
- Store docs in the same repository as the code (or a linked one)
- Review documentation changes through the same PR process as code
- Automated checks: link checking, spell checking, API doc generation from code annotations
- Deployment via CI/CD: docs build and publish automatically when merged
This prevents the drift where code changes but documentation doesn't. The PR that changes an API should also change the documentation — they're reviewed together.
Documentation generators: JSDoc/TSDoc for JavaScript/TypeScript, Sphinx for Python, Javadoc for Java, Rustdoc for Rust. These extract documentation from code comments and generate reference documentation automatically.
Incident Communication
Engineering communication extends to incident management. During an incident:
Status page updates: brief, factual, in plain language. "We are investigating elevated error rates on the checkout API" not "Our infrastructure team is actively engaged in root-cause analysis of anomalous behavior patterns."
Internal incident channels: use a structured format. Declare severity. Assign roles (Incident Commander, Communications Lead). Regular updates (every 15-30 minutes). Clear "all clear" message.
Post-mortems (blameless): document what happened, when, how it was detected, how it was resolved, contributing factors, and action items. The purpose is learning, not blame. "The engineer deleted the wrong database" is not the root cause — "we had no confirmation step before a destructive operation on a production database" is.