In my last blog post I explained why writing design documents is such a powerful approach to building well-engineered systems. But what should one document? When it comes to software, if one documents too much, the content of the documentation can become inaccurate very quickly, and inaccurate documentation is quickly ignored.
What to document?
My most useful design documents have been less than 5 pages long, but still served their purpose so well. Design documentation does not have to be exhaustive to be useful.
When writing design documents, consider the following.
Explicit Design Decisions
Any high-level decision made about the system design should be documented. For example, if your system uses OAuth2 then call it out. Planning to use AWS RDS? State it. Fundamental choices like this are a critical part of your system’s specification and need to be captured somewhere outside of the code.
REST APIs are ubiquitous today, and if your system implements these APIs, it is always worth documenting the calls outside of the source code. These APIs are consumed so widely that this documentation is really valuable. REST APIs are generally pretty stable in practise, so maintenance overhead is usually not that severe. I often start documenting a system design that expose REST APIs by first specifying the API itself. It’s usually just a proposal, but it’s an excellent way to start design discussions, and show how various concepts within the system will relate to each other.
One useful approach when it comes to documenting the API is to show how the calls would be made using curl. This has two advantages — it is an unambiguous way to describe the API call and the reader can often simply copy-and-paste the command if she wants to try out the API call, if reviewing the system after implementation. The elasticsearch documents are an example of this approach.
Document what happens if your system encounters an error. Explain what will happen if an external dependency is unavailable. Make it explicit what your policies are. Does your system retry? If so, how many times? Or does it give up? These decisions are really important when it comes to system design and should always be called out.
What not to document?
Sometimes it’s just as important what you leave out.
I never document lower-level details like source code structure; it changes too quickly and those documents rarely remain correct for long. I rarely, if ever, document the use of design patterns such as factory classes.
In my experience, an Open Issues section is one of the first to go stale in documentation. Next time you have an open issue in your design, try forcing the issue. Instead of writing:
The question of which key-value store to use is yet to be decided.
This system uses Cassandra 2.0 as its key-value store.
This second option may force a decision to be made much quicker, as interested parties know that if a decision is not made, the designer is entitled to use Cassandra.
It’s still hard work
Maintaining design documentation is work. Committing to keeping the information accurate requires work and attention to detail, but saves engineering time. However, if you can’t commit to keeping the documentation entirely up-to-date, sometimes it’s sufficient to link to a source file in source-control. Combined with some conceptual diagrams and high-level descriptions, documentation can be very helpful and remain accurate.