Documentation
Sooner or later someone other than you needs to run your system: a new teammate, your project partner, whoever maintains it after you graduate. This page covers which documents to write for each of them, from the README to the API reference, how much detail each one needs, and how to keep them accurate once the code starts moving. It doesn’t cover the design document or the requirements, which have guides of their own.
Before writing any of these, decide what each document is for. Diátaxis, a framework by Daniele Procida, sorts documentation by the reader’s need into four kinds. A tutorial takes a beginner through a first success. A how-to guide helps someone who already knows the system finish a specific task. Reference describes what exists, precisely and without narrative. Explanation covers why things are the way they are. The split matters because the four needs conflict: a tutorial that pauses to justify every design decision loses the beginner, and a reference that tells a story is slow for someone scanning for a function signature. Procida argues that crossing or blurring the boundaries between the four is at the heart of “a vast number of problems in documentation”. When a page feels wrong and you can’t say why, check whether it’s trying to be two kinds at once; splitting it in two usually fixes it.
Write for the reader with the least access to you: whoever inherits the project after you leave. That person can’t ask you anything, so every gap in the README becomes an afternoon of guessing, and every undocumented decision is at risk of being reversed by someone who didn’t know it was a decision. A document that gets that person running also serves the teammate who joins partway through and the project partner who wants to evaluate what you built.
Repository Documentation
Section titled “Repository Documentation”Put the files below at the root of every repository, because that’s where GitHub, GitLab, and most other hosts render them, so they’re the first thing a visitor sees.
README
Section titled “README”The README is the first thing anyone opening your repository reads, so it has to answer the questions they arrive with:
- Purpose: one paragraph on what the project is and the problem it solves.
- Audience: who uses it.
- Setup: step-by-step instructions to install and run it, starting from a clean machine.
- Usage: basic examples with their expected output.
- Status: prototype, in production, actively maintained, or archived.
- Contributing: a link to
CONTRIBUTING.md. - License: a link to
LICENSE.
Test the README the way you’d test code: have someone who hasn’t set up the project get it running from the README alone, without asking you, and time it. Somewhere around half an hour is a reasonable target. When it takes much longer, the missing step is usually one the team does from memory, which is exactly the step a newcomer can’t guess.
CONTRIBUTING.md
Section titled “CONTRIBUTING.md”CONTRIBUTING.md tells a new contributor how the team works, in the terms a repository can check. A working agreement records how the team decided to collaborate; this file is its technical side. It should cover:
- Development setup (dependencies, environment variables, local services needed).
- Branching strategy (e.g., feature branches off
main, naming convention). - Pull request requirements (required reviewers, review checklist, CI must pass).
- Coding standards (linter, formatter, style guide).
- Definition of Done.
- How to write and run tests.
If the project accepts outside contributions, add a code of conduct next to it, because, as GitHub’s Open Source Survey (GitHub, 2017) puts it, documentation helps orient newcomers to a project’s standards of conduct as well as to how to use it. The survey, an industry report built on responses from 5,500 randomly sampled respondents across more than 3,800 open-source repositories on GitHub.com, found that documentation explaining a project’s processes, such as contributing guides and codes of conduct, is valued more by groups underrepresented in open source, like women. The Contributor Covenant is a ready-made code of conduct you can adopt.
LICENSE
Section titled “LICENSE”Add a license or an explicit copyright notice to every repository you share, so anyone who finds it knows what they may do with the code. Without a license, default copyright law applies: you keep all rights, and no one else may reproduce, distribute, or build on the work. That’s rarely what an open-source project intends, and would-be users notice. In the same survey, 64% of respondents called a license very important when deciding whether to use a project, and 67% when deciding whether to contribute to one (GitHub, 2017).
Which file you add depends on the project:
- For an open-source project, choose a license.
- For a closed-source project (proprietary, or under an NDA), add a copyright notice.
- For a contribution to an existing open-source project, inherit its license.
The common open-source licenses differ mainly in what they ask of people who reuse the code:
- MIT: permissive, with minimal conditions. Pick it when nothing pushes you toward another, because it asks the least of the people who reuse your code.
- Apache 2.0: permissive, plus an explicit patent grant from contributors.
- GPL v3: strong copyleft; anyone who distributes a derivative must release it under the same license, so pick it if you want every derivative to stay open.
Choose a License, maintained by GitHub, compares these and the less common ones in plain language.
CHANGELOG
Section titled “CHANGELOG”A changelog records the notable changes between versions, written for people rather than machines. Two readers need it most:
- A project partner, who needs to know what to test after each release.
- Users and maintainers of an open-source project, who follow releases closely.
Keep a Changelog is a common convention: one section per release, newest first, with entries grouped as Added, Changed, Deprecated, Removed, Fixed, and Security. It argues against pasting the commit log into the changelog, because a commit log is full of noise and records each step in the source code, while a changelog entry records the noteworthy difference, often across several commits. Tag each release with a semantic version so the changelog’s headings match the tags; Versioning, below, covers the scheme.
Code Documentation
Section titled “Code Documentation”Code documentation lives in the source files, next to what it describes. It carries what the code itself can’t: the intent behind it, the assumptions it depends on, and the behavior a caller has to know about.
Comments: When and How
Section titled “Comments: When and How”Comment the why, not the what. The code already says what it does. A comment earns its place by explaining why it’s done this way, what assumption it relies on, or what subtle behavior a reader should watch for. A comment that repeats the code costs a line, and it goes stale the first time someone edits the code without editing the comment.
Good comment:
# Binary search over the sorted segment list.# Segments are stored as (start, end) tuples; we match by start offset.Unnecessary comment:
i = 0 # initialize i to zeroThe comment that isn’t there is a failure too, and missing information is the most frequent problem with what documentation says. Aghajani et al. (2019) classified 878 documentation-related artifacts from mailing lists, Stack Overflow, issue trackers, and pull requests. Of the 485 about what the documentation said, 55% reported missing information, and API references and code comments were the documentation types it affected most.
Docstrings and API Documentation
Section titled “Docstrings and API Documentation”Give every public function, class, and module a docstring. At minimum, a docstring describes:
- What the function does (not how).
- Parameters and their types.
- Return value.
- Exceptions that may be raised.
- A short example of a call and its result.
Don’t skip the example. Robillard (2009) surveyed developers at Microsoft about learning new APIs: 78% of the 80 respondents learned them by reading documentation, and inadequate learning resources, such as documentation, topped the list of obstacles, named by 50 of the 74 who reported one. Insufficient or inadequate examples was the most-named resource problem, by 20 respondents, tied with the API’s own structural design as the most-named specific obstacle.
Tools like JSDoc (JavaScript), Sphinx (Python), TypeDoc (TypeScript), and Rustdoc (Rust) generate a navigable API reference from the docstrings, so the reference’s list of functions and signatures can’t fall out of step with the code. The examples inside it still can: Aghajani et al. (2019) found code examples were the documentation type most often affected by correctness issues, and recommend testing them the way production code is tested. Python’s doctest and Rust’s documentation tests do exactly that, running the examples in your docstrings as part of the test suite. The authors note the catch: documentation examples are often fragments rather than runnable programs, which makes them harder to test.
For REST APIs, the OpenAPI Specification, maintained by the OpenAPI Initiative, is a standard description format for HTTP APIs. One OpenAPI document can drive rendered documentation, generated client and server code, and testing tools, so you write the description once and get all three from it.
User Documentation
Section titled “User Documentation”User documentation explains how to use the software, not how it was built, and its reader is an end user rather than an engineer. For a small project, it might be:
- A user guide or wiki page for each key workflow (a how-to guide, in Diátaxis terms).
- Help text or tooltips in the app.
- A short video walkthrough of a first session (a tutorial).
User documentation matters most when your project partner will hand the software to non-technical users after the team leaves: those users will have questions, and without a guide, the only place to take them is the partner.
Developer Documentation
Section titled “Developer Documentation”Developer documentation targets the people who will build on, maintain, or deploy the system. It includes:
- Architecture overview: the major components and how they fit together. Link to your design document.
- Data model: the schema and what each entity represents, in your design document; link it rather than describing it twice.
- Environment setup: how to configure development, test, and production environments.
- Deployment guide: the steps to deploy the system, including environment variables and infrastructure requirements. The deployment shape (what runs where, who owns it) is in the design document.
- Troubleshooting guide: common failure modes and their resolutions.
Versioning
Section titled “Versioning”Use semantic versioning (MAJOR.MINOR.PATCH) for releases:
- MAJOR: breaking changes (old integrations may stop working).
- MINOR: new features, backward-compatible.
- PATCH: backward-compatible bug fixes.
Tag releases in your repository (git tag v1.0.0). A tag tells you which version your project partner is running, and gives you a known-good version to roll back to when a release introduces a regression.
Documentation Tools
Section titled “Documentation Tools”Nothing in this table is required, and a project documented entirely in Markdown files in the repository is a perfectly good outcome. Reach for a tool when the manual version has started to drift, or once you have more pages than a reader can navigate by filename.
| Need | Tool |
|---|---|
| Project documentation site | Docusaurus, MkDocs |
| API documentation (REST) | Swagger UI / OpenAPI, Redoc |
| Python API docs | Sphinx, pdoc |
| JavaScript / TypeScript | TypeDoc, JSDoc |
| Diagrams as code | Mermaid, PlantUML |
| Changelog | Keep a Changelog convention |
Best Practices
Section titled “Best Practices”- Write the documentation in the same pull request as the feature, while you still remember the decisions behind it.
- Keep documentation in the repository, next to what it describes, so a reviewer sees the code change and the documentation change in one diff.
- Run the README’s setup steps on a fresh machine or in a clean container before each release.
- Fix or delete stale setup steps and code examples as soon as you find them; Some Truths, below, explains why those come first.
- Put a system diagram in the README or the architecture overview, because a newcomer can place a component in a diagram faster than they can reconstruct the system from paragraphs.
- Review documentation in code review, and don’t merge a change that adds or changes a public API without its docstring. Some open-source developers enforce this to keep documentation up to date, adding documentation updates to the contribution checklist or making a Javadoc update mandatory before a pull request is accepted (Aghajani et al., 2019).
Some Truths About Documentation
Section titled “Some Truths About Documentation”Documentation goes stale faster than code, because nothing fails when it’s wrong. A broken function breaks a test; a README describing a setup procedure that changed months ago passes every check in your repository and costs the next person an afternoon. Lethbridge et al. (2003) found that engineers rarely updated documentation other than test documents, and when they did, it was usually several weeks after the code changed; 68% of their survey respondents agreed at least somewhat that documentation is always outdated relative to the system. Of the problems with what documentation said that Aghajani et al. (2019) classified, 39% were outdated information.
What stayed current, in Lethbridge et al.‘s account, was documentation attached to a change, or cheap or useful enough to keep up. Engineers were likely to update documentation continually only when it was attached to the process for completing a change request. In the authors’ discussion, code comments, notes in the bug tracker, and test cases stay current because each costs little or plainly pays: a comment is short and right next to the code, a bug note is a small addition made while fixing the bug, and a test case has a simple structure and an obvious use in verifying the system.
That gives a sharper rule than “keep it updated”. Prefer documentation that’s executed or generated over documentation that’s only written: setup instructions that are a script someone runs can’t silently drift, and the same instructions as prose will. Where prose is unavoidable, keep it in the repository next to what it describes and change it in the same pull request, because a document outside the repository isn’t in the diff a reviewer reads.
“Outdated documentation is worse than none” is common advice, and the same paper suggests it’s only half right. Of Lethbridge et al.’s survey respondents, 81% agreed that documentation can be useful even when it isn’t up to date, and in their interviews, the more abstract a document, the more likely engineers were to consider it accurate and useful. How much accuracy mattered seemed to depend on how close the document sat to the code: the link between a document’s perceived accuracy and how often engineers consulted it was strongest for test documents and low-level design, weaker for requirements, architecture, and detailed design, and near zero for specifications.
Use that split to decide what to fix first. Wrong information concentrates in the documentation a reader executes: of the correctness issues Aghajani et al. (2019) could attribute to a documentation type, 50% were in code examples and 20% in installation guidelines. Fix or delete a stale setup step or code example as soon as you find it, because a reader follows it exactly and has no way to tell it’s wrong until it fails. A stale architecture overview still orients a newcomer if its major components are right, so mark when it was last checked instead of deleting it. Google does this: Manshreck (2020) describes documents that carry an owner and a “last reviewed” date, with a reminder sent when one hasn’t been touched in, for example, three months.
Documentation pays its author back late, and Manshreck names that as one reason engineers consider documentation poor: the benefits of documentation arrive downstream, mostly for its readers, while the effort lands up front, on its author. Attach documentation to each change you already make, so the question is never “should I write documentation today” but “does this change alter anything a reader was told”.
Documentation in Industry and Academia
Section titled “Documentation in Industry and Academia”Google’s own history is a case study in how documentation goes stale. In Manshreck’s account, the company’s internal wiki, which anyone could edit and nobody owned, filled with obsolete and duplicated pages: at one point there were 7 to 10 documents on setting up Borg, Google’s production compute environment, only a few of which seemed to be maintained. Documentation quality became the number one developer complaint on Google’s annual developer surveys, and when the wiki was retired, around 90% of its documents had had no views or updates in the previous few months. The fix was to treat documentation like code, with owners, canonical locations in source control, bug tracking, and code review, and Manshreck reports that the documents became better.
Technical writers don’t take documentation off an engineer’s plate. Manshreck notes that engineers will always write most documentation themselves, and that at Google most of it takes the form of code comments. Treat your project’s documentation as practice for that part of the job.
Open-source projects show the same pattern. In GitHub’s survey, 93% of respondents had run into incomplete or outdated documentation, yet 60% of contributors said they rarely or never contribute to documentation (GitHub, 2017). The report’s recommendation to its readers follows from those two numbers: when you hit a documentation problem in an open-source project you use, open a pull request that fixes it.
In research, the benchmark is reproducibility: another researcher should be able to run your code and reproduce your results from your documentation alone. Borrow that test for any project you hand over, because it’s concrete where “well documented” isn’t: it names a reader (someone who wasn’t on the team), a starting point (a clean checkout), and an expected result (the system running and producing what yours does).
References
Section titled “References”- GitHub (2017). Open Source Survey. opensourcesurvey.org. https://opensourcesurvey.org/2017/
- Aghajani, E., Nagy, C., Vega-Márquez, O. L., Linares-Vásquez, M., Moreno, L., Bavota, G., and Lanza, M. (2019). Software Documentation Issues Unveiled. Proceedings of the 41st International Conference on Software Engineering (ICSE). https://doi.org/10.1109/ICSE.2019.00122
- Robillard, M. P. (2009). What Makes APIs Hard to Learn? Answers from Developers. IEEE Software. https://doi.org/10.1109/MS.2009.193
- Lethbridge, T. C., Singer, J., and Forward, A. (2003). How Software Engineers Use Documentation: The State of the Practice. IEEE Software. https://doi.org/10.1109/MS.2003.1241364
- Manshreck, T. (2020). Documentation. Software Engineering at Google, edited by T. Winters, T. Manshreck, and H. Wright (O'Reilly), chapter 10. https://abseil.io/resources/swe-book/html/ch10.html
Additional Readings
Section titled “Additional Readings”The two style guides are worth skimming once and then keeping open while you write.
Sources and further reading
- Write the Docs guide: a practitioner community’s accumulated advice on documenting software, including its docs as code page.
- Google developer documentation style guide, Google: conventions for clear technical writing, and a good tiebreaker when the team disagrees.
- Microsoft Writing Style Guide, Microsoft: a second style reference, with sections on voice and on writing for a global audience.
- Docs Like Code, Anne Gentle: a book on running documentation through the same repository, review, and CI workflow as the code.
- Software Documentation: The Practitioners’ Perspective, Aghajani et al., ICSE: two surveys of 146 practitioners on which documentation issues matter most to them and which kinds of documentation they need for which tasks.
Activities that exercise this
- User Manual: writing the manual is the fastest way to find out what your system actually requires of a user.
- Describe your API Reference: the reference for the interface other code or people build on, with one example call and its result for each entry point.
- Describe your Architecture: the diagram that belongs in your developer documentation.
- Make Your Artifact Reproducible: the one README command that takes a clean checkout to your results.
- Software Release and Versioning: the versioning scheme your tags and changelog follow.
- Planning for Maintenance and Long-Term Support: the plan for user manuals, FAQs, and support guides that outlives the team.
- Analyze an Existing Codebase: the receiving end of someone else’s documentation, which shows you what yours needs to do.
- Public Code Repository: a README and setup instructions verified from a clean clone.
- Write for Accessibility and ESL: plain-language rules, applied to the documents here.