There's a trend that encourages addressing challenges such as security and testing, earlier and more directly in the development life cycle. It's called shifting left. It's all about taking on small increments of work that validate you are delivering value in the right direction without letting unknown or unproven items hang around in backlog until it's too late to tackle them effectively.
Starting to iterate on an unknown earlier is a way to de-risk something that might otherwise become a surprise at the moment when you are most pressed for time.
That got me thinking about documentation and in general, system understandability. It is sometimes treated as an afterthought, due to any of the following:
- Lack of interest / not-my-job
- Not being valued by the team doing the work
- It is for 'someone else' and they won't need it until we're done
- It is not worth the effort to maintain throughout
- A perception of a need to go "fast" in the short term
I think it's important to take a step back and look at what the goal of good system documentation should be.
Good documentation affects the maintainability of a system. It results in a system that is:
- easier to support
- easier to change
- safer to change
- faster to change
Great documentation results in all of the above, for more people.
If we step back just a bit and broaden our definition of 'documentation', there is a pattern of behaviors that can lead to the above mentioned outcomes and reframe how to approach documentation in general.
Great documentation should propel the continual delivery of value in a system.
Documentation needs to be accurate, maintained and understandable. It should enable quick and continual evolution of a system because it's easier to approach supporting and modifying areas of the system for new and existing actors. This can be for people new to the team OR people new to that part of the code/infrastructure.
It's a huge challenge to achieve accurate and maintained with 'traditional' documentation. For that reason, I'm advocating shifting left as much as possible. Push more into executable code and infrastructure, in version control. Having a single source of truth, in code, also removes ambuigity (vs prose) – making a system more understandable.
For things that can't be described as source code or generated, sure you can hand-craft guides and trailmaps to store in version control, but BE WARY and diligent to ensure a better option than maintaining those pamphlets is not available.
Let's break it down.
Documenting the Code
How easily can a new team member start contributing and delivering value to production?
Make the code easy to read and approachable for someone new. Names matter. Grouping matters. Minimizing surprises matters. Be good to your future self **, and to those that will come after. Source code is the truth of how the system operates. Make that truth digestable and easy to follow.
Use tests to express expectations, and prove the most important behaviors will continue to function as needed. Tests are essentially executable documentation which proves the behavior of a system, and can provide a level of detail that is difficult to describe in prose.
Do only what is needed now, so you are not adding unnecessary weight to the backpack everyone has to carry forward.
Use the code itself to express the 'what' and use the (inline or commit) comments to express the 'why'.
Make the behavior of the system observable, so you can learn and adjust for the things you did not have the ability to anticipate in pre-production environments.
Documenting the Infrastructure
Can you provision and configure the required environment programmatically and on-demand?
Version Control and script the creation of the Infrastructure. Lock it down, and do it regularly to prevent drift and to avoid systems becoming handcrafted snowflakes over time. This ensures anyone can see exactly how something is configured soup-to-nuts, making is easier, safer and faster to change.
Use traditional documentation only for that which cannot be made executable or generated
The problem with traditional documentation is that it tends to fall out of date easily, and that drift is difficult to prevent or even maintain awareness of.
If something can be described as executable code, it should be. If some Infrastructure provisioning and configuration can be executable, it should be. If understandable and useful documentation can be generated, it should be. What's left after that? Hopefully not much: Readme's, a tutorial, architecture diagrams that tell a story, or whatever else you judge to be appropriate.
Shift left by actively pushing for readable code and scripted creation of infrastructure in version control. Generate documentation where useful, but strike a balance of keeping it easy to understand, maintained, and actively used. Anything else is waste.
** = "Documentation is a love letter that you write to your future self." - Damian Conway