Many individuals and teams fail at documenting their projects properly, effectively drawing other developers away from their code. Fortunately, the most common documentation pitfalls are quite simple to overcome. In this article, I’m going through techniques that have helped make our projects more approachable to new developers whilst also appealing to power users, eventually bringing more people into using them.
When documenting code, we should be mindful of readers who:
- have a limited amount of time,
- don’t speak English very well,
- are probably multi-tasking,
- are interrupted, then come back to start reading from where they stopped.
Allow me to share with you a few of the available techniques coming from the field of content design to help set our projects up for success.
Here they are:
- Be concise
- Use the active voice, avoid the passive voice
- Use positive sentences, avoid negative ones
- Don’t explain code when the code speaks for itself
- Start with the most basic and common concepts to then drill progressively into the details
- Break the content down clearly into sections
- When providing support, explain why an error occurred without implying the reader caused it
- Write as little documentation as possible, but as much as necessary
- Document code clearly and your job will get easier
Content design is a craft, and I’ve only scratched the surface of that discipline. As a foreigner living in London, I am very appreciative of documentation that is mindful of that fact. I would like to mention the Government Digital Service. They have set a gold standard in content design: GOV.UK has accessible, well designed content that uses a language I can understand when I need to get into the intricacies of English immigration law and taxes. I encourage you to read more about content design on the Government Digital Service’s website.
Note that these tips mostly apply to certain types of projects, such as frameworks, self contained modules, and web components.
Be precise and make it short
Decorating prose with fancy words is tempting but these extra words generate noise, detrimental to our message. Use the simplest language, grammar and syntax you can. This simplicity gives the important bits of information a chance to shine.
Bad: unnecessary words
You can do foo if required by setting bar to true
In this sentence, “You can” and “if required” are unnecessary to understand its meaning.
As for code, it takes time to “refactor” documentation, and that is probably the most overlooked part of the documentation process. As a great poet once wrote:
I have only made this letter longer because I have not had the time to make it shorter. — Blaise Pascal, The Provincial Letters
Good: concise sentences
Do foo by setting bar to true
When we are done removing unnecessary words, we can remove unnecessary sentences from paragraphs and redundant paragraphs from documents.
Find more tips on writing concise content on the Guide to Grammar and Writing.
At the scale of a whole framework, shortening content does make a documentation considerably more attractive.
Use the active voice
In case English is a second or a third language for you, there are two “voices” in English:
- active voice: Sir Tim Berners Lee invented the web.
- passive voice: The web was invented by Sir Tim Berners Lee.
It happens that one is easier to process than the other. In our documentation, where every bit of our readers’ attention should be focused on understanding our content, it becomes important to choose the one that will require the least effort to read.
Bad: passive voice
Do foo by setting bar to true
The brain processes information faster when content is in the active voice rather than the passive voice. The passive voice also happens to sound very official to us, which puts a barrier between us and our readers.
Good: active voice
Do foo: set bar as true
Set bar as true to do foo
The active voice helps communicate things more clearly, simply and in a more accessible fashion.
Tip: favor positive sentences, they are faster to process for the brain than negative sentences. Keep away from double negative sentences such as “not false” or “avoid not doing something”, obviously harder to understand.
Code snippets are worth a thousand words
Words are great to declare intent and share the value of our code. But using words to describe actual code is like asking for our documentation to be hard to understand and begging it to get out of date really quickly.
Bad: using text to describe code itself
Do foo: set bar as true
In the above example, it takes a bit of effort to transpile the sentence from plain English to code. In the perspective of the reader’s current state, they are multi-tasking (coding, reading our documentation, manipulating many concepts in short memory) and we are stealing precious attention from them.
Now, imagine a whole documentation written like this, with all of our classes, functions, options and parameters described in plain language. Would you read it?
Get rid of all the steps where developers have to translate English into code.
Good: code snippet (with a comment)
Code snippets demand very limited amounts of “brain processing time” from our readers, especially if they are already familiar with our code:
// Do foo
var bar = true;
Including code directly in our documentation not only enables readers understand the code but also to copy and paste it in their codebase, which reduces further the barrier between the documentation and them.
Note that code snippets are great for short and simple examples but the technique won’t scale very well. To thoroughly cover whole codebases, we can rely on self-generating documentation tools such as JSDoc and SassDoc. That way, the most detailed documentation lives alongside the code, which helps keeping the two in sync with each other.
From macro to micro
Good documentations should answer these questions:
- What does the thing do?
- Where, when and why should I use the thing?
- How do I use the thing?
To do so, we need to help users (our readers) get smoothly through a learning journey while dealing with this dilemma:
- users want power and features,
- users want simplicity.
This is where the technique of progressive disclosure comes to mind. Good documentations start with a simple set of instructions (the most common use cases), and then reveal the details of the component as we go, only upon request.
To achieve a sense of progressive disclosure, we can structure our documentation with the “inverted pyramid” method: from the most global perspective (macro) to the most specific (micro).
This technique prevents us from overwhelming our readers with highly complex concepts from the beginning, while providing relevant content at the different stages of the learning process.
Here is how I find it best to break the content down:
- Overview: short description in plain English of what the component does and, if applicable, of the value it brings to a larger system. If it is a web component, include a block of code of the simplest viable implementation.
- Quick Start: installation steps and requirements, most common use-case(s)
- Important use-cases and examples
- API details
- Troubleshooting, version upgrade path, external resources
- License, credits, contributing details
Note that if we have a system composed of a lot of components or micro-services, clear sectioning and consistency across the documentation of these components help readers go through the concepts they already know and discover new ones more easily.
Don’t make it personal
Users who read deeper into the troubleshooting sections of our documentation are probably frustrated because something unexpected happened. How to ensure we are not making things worse for them?
Bad: making it personal
make: execvp: gcc: Permission denied: depending on how you’ve configured permissions on your machine, “make install” may fail. Try again with “sudo make install”.
In the above example, we are making it about our reader. We’re implying that the user may have done something wrong at some point. Telling them that may increase their (already high) frustration level.
When an error occurs, we shouldn’t make assumptions on whether the user is responsible for any of the environment’s configuration or that they are in any way the source of the problem.
Let us instead focus on the problem itself and explain why it happened without mentioning a human cause:
make: execvp: gcc: Permission denied: “make install” failed due to a problem with permissions on the machine. Try again with “sudo make install”.
The reader should feel like the program is wrong, not them…
…or as they hit their maximum level of frustration, they will put our project away and use somebody else’s instead (or worse: they might start a full rewrite).
Write as little documentation as possible, but as much as necessary
Writing any documentation has a cost: at every major change, developers need to update both the code and the documentation. As it gets larger, maintainers will forget to update it.
Projects whose documentations aren’t in sync with their code anymore become deserted in favor of better documented projects. So what is the solution to that?
The best documentation is the one you don’t need to write.
For a component, a good test coverage, some examples, coupled to a few inline comments and a short readme file are usually easier to understand and more maintainable than a heavy, thorough, multi-page documentation.
Tip: as I’ve mentioned earlier, self-generating documentation tools such as JSDoc and SassDoc retain implementation details close to the code. This proximity does help developers keep them both in sync.
Writing simple, elegant code is hard ; so is documentation. The difference when writing documentation is that it is a lot less fun than coding and its impact is harder to measure. It also appears to come in the way of productivity (in the short term). This seems to lead to a developer disinterest in writing documentation. Maybe this is the reason why so much of it is so bad, outdated, or non-existant…
We are not writing code for machines, but for other people to understand what it does. In effect, documentation is an integrated part of our code.
The better our documentation, the more people will use our code.
I wonder what would happen if as developers we thought of documentation like we think about code: we iterate on it, refactor it, rewrite it, cut whole parts of it…
Our rewards will be measured in the number of times our code is successfully re-used, the number of pull requests opened and the amount of bugs other developers fix in our code. Not only that valuable feedback makes us better as developers, it can also make us happier people, all part of a community who knows how to share knowledge efficiently.
On that note, allow me to close with a quote:
- National Archives writing guide
- Content Designer (GOV.UK)
- A few studies I can’t find any links to, that I recall from science of the language and cognitive science classes at university
Acknowledgements: thanks to Max Harlow, Ian Feather, Luke Kavanagh and Ben Holland for their precious help and inspiration.