The problem
Documentation serves two masters: the engineer who writes it and the engineer who reads it six months later. Too little documentation leaves readers guessing. Too much buries the signal in noise. The goal is documentation that helps engineers understand and use code correctly. Nothing more, nothing less. The principles in this guide apply to all languages. The examples are in Go since that is most of the backend, but the philosophy is universal.Quick checklist
Before submitting documentation, verify each item. Accuracy- Every claim matches actual code behavior
- Return values match what code returns
- Error conditions listed are possible and described correctly
- Default values match actual defaults
- Constraints documented are enforced, and the docs note when and how
- Every exported symbol has a doc comment
- Package has a
doc.goif it has non-trivial behavior - Non-obvious behavior is documented (edge cases, nil handling, concurrency)
- The why is explained for design choices that are not self-evident
- Every named SQL query has a doc comment block
- Doc comments start with the symbol name
- Uses prose, not bullet lists, unless items are parallel
- Depth matches complexity
- SQL comments add non-obvious context instead of restating obvious clauses
- Cross-references use bracket syntax:
[TypeName],[FuncName] - No stale documentation from copy-paste or refactoring
- You read the implementation, not just the signature
- For value plus error returns, you checked what value returns on failure
- For unmarshal operations, you verified whether partial values return
- Examples compile and run
- SQL comment examples match real query behavior (ordering, fallback, joins)
Writing style
Write naturally. Use prose for explanations, not bullet points. Bullet lists are for parallel items or steps. A list of single sentence bullets is often better as a paragraph.Document the why, not the what
The code shows what it does. Documentation should explain why it exists, why it works this way, and what could go wrong.Documenting design choices
When you choose between reasonable alternatives, explain the reasoning in a sentence.Public API documentation
Every exported function, type, constant, and variable must be documented. This is the contract with users of the code. The depth of documentation should match complexity. A simple getter needs one line. A distributed algorithm needs paragraphs.Simple functions
Complex functions
When to include specific details
Parameters: Document when the purpose is not obvious from the name and type, or when there are constraints like must be positive. Return values: Explain when return patterns are subtle or when multiple success states exist. For functions that return a value plus an error, document what value returns on failure. Error conditions: List specific errors only when callers need to handle them differently. Concurrency: Document when a function or type is safe or unsafe for concurrent use. Performance: Mention non-obvious characteristics that affect usage decisions. Context: Document context behavior only if it is non-standard.SQL query documentation
Named SQL queries are part of the public contract between application code and the database. Treat query comments like API documentation. For SQL query docs, explain why this query exists, how it resolves non-obvious behavior, and what guarantees callers can rely on. Do not just restate theSELECT clause.
Keep SQL comments concise. In most cases, two to five lines are enough. If a comment is longer than the query, each sentence must carry non-obvious information such as fallback guarantees, deterministic ordering, intentional join behavior, or performance tradeoffs.
Avoid duplicate explanations. If the SQL already makes behavior obvious, for example AND s.health = 'healthy', do not repeat that in prose unless you are documenting a non-obvious guarantee that depends on it.
For selection queries with fallback logic, document deterministic behavior explicitly. If exact matching must win over wildcard matching, explain how SQL enforces it, for example with ORDER BY and not candidate list order.
For query docs that are not obvious from a quick read, include a small concrete example with inputs and the expected returned row. This is required for logic that depends on ordering, fallback, or tie-breaking.
Document performance-sensitive choices when they are intentional, for example using LIMIT 1 to avoid transferring large payload rows that are not selected.
What not to document
Do not document implementation details in doc comments. Those belong inside the function. Do not explain that context is used for cancellation or mention O(1) performance unless it is surprising.Package documentation
Every significant package should have adoc.go file with the package comment and declaration. It should explain what the package does, why it exists, how it fits into the system, key concepts, usage, and cross-references.
Structure of doc.go
Use# headers to organize sections. Include a usage example.
Internal code
Internal functions have different documentation needs. The audience is teammates maintaining this code. The why matters even more than the what.Complex algorithm documentation
For complex internal logic, explain the approach and reasoning.Types and interfaces
Type documentation should explain what the type represents and any constraints or invariants. Interface documentation should focus on the contract and concurrency guarantees.Error documentation
Document sentinel errors with meaning and conditions.Constants and variables
Document purpose and reasoning when it is not obvious.Examples
Use Go example tests for non-trivial usage patterns. Examples compile and run, so they do not go stale.Test documentation
Document test helpers and complex test scenarios so future maintainers understand the purpose.Document what not to do
Warn against common mistakes when a misuse would be easy and costly.Verify before you document
The most dangerous documentation is confident and wrong. Read the implementation. Document what the code does, not what you think it should do. Common verification failures include return values on error, partial values from unmarshal, constraint enforcement timing, defaults, and context behavior.Common mistakes
Restating the signature adds no value. Documenting irrelevant details creates noise. Missing critical information is dangerous. Stale documentation is worse than no documentation.Go conventions
Start doc comments with the name of the thing being documented. Use present tense. Write complete sentences. Use bracket syntax for references, for example[TypeName] and [FuncName].

