An engineering team starts a new project. Work comes so thick and fast that documentation (docs) barely registers as a need. And things will be so different in six months or a year – surely it’s better if they wait for things to settle, for the codebase to firm up, right?
The year passes, and the now-complex project now presents a thorny question for which docs would be helpful. But there is none! The team muddles through the problem with Slack forensics, scattered notes, and commit messages, and the need passes. In a retro, an engineer wistfully mentions how nice it would be to have had docs. But where to start? Where should they be kept? What formats or tools should they be written with? A problem that no one had time for is now a problem that feels intractable – so no one has time for it.
Proactively writing and maintaining docs is one of the toughest knots for software engineering teams to untie. Like a certain knot of legend, the obvious approach might not be the best one – or the most straightforward.
Bandwidth & Change
Software systems of a non-trivial size present three challenges to documenting them:
- They can’t be documented in one go – we have to prioritize what parts to document.
- They grow even as they’re documented – you’ll likely never be caught up.
- They change over time – we should presume that any doc will eventually grow stale.
The demand on us, then, is to continually write documentation – alongside the other demands of our work. What we need is a heuristic: when do we write or update the docs?
In my experience, the heuristic teams reach for is something like “document what we just worked on”. It’s a step in the right direction. We have fresh knowledge and context, and documenting work soon after it’s done maximizes the docs’ useful lifespan. But so much of what we work on is not big, documentable things, but smaller stuff like bugfixes and tweaks. Our code gradually slips out from under our docs.
More fundamentally, change is coming for whatever we write. When we describe the project in a given moment, it’s like setting up a frame of bowling pins – initially nice and orderly, but inevitably rearranged. We become pinsetters, waiting for change to happen so we can make things temporarily tidy again.
Enter the Decision
If change is what makes documentation so hard, why don’t we document change instead? Changes don’t change, because they are events that package together state and temporality. “Here is the current state of the project” may not be true in a year, but “given the state of the project at the time, it changed in the following way…” – even if a subsequent change completely reverses this one, that will always be accurate.
Of course, projects don’t change by themselves. We change them! And not at random. Changing an application is deciding on a direction for change, and implementing it. Decisions stem from our consideration of the code, its context, a problem to be solved, and our intent on how to address that problem. Decisions help us cut the knot by slicing across every relevant dimension of a software project:
- They are maximally explicit about our intent. Why is the code the way it is?
- They are a dynamic snapshot of the project. What was the code like, how is it changing, and what are the consequences?
- They capture the project’s environment. What were the requirements and constraints that drove the decision?
- They let us consider paths not taken. What other decisions could we have made, and why did we not make them?
- Finally, they act as a flywheel for other docs. Are user workflows changing, or are API contracts being updated?
Which Decisions?
We can’t document every decision. We make innumerable small decisions every day – naming variables, styling code, structuring tests. Where do we draw the line between small decisions and big, documentable ones?
By now, you may think this sounds a lot like Architectural Decisions Records, or ADRs – and you’d be right. Tech practitioners devised the ADR as an “Agile” way of writing docs that would evolve along with codebases and requirements. You can start reading about them at https://adr.github.io/.
Confronted with this question of which decisions to document, those same practitioners arrived at the idea of architectural significance. This is typically a list of criteria to check off, like a feature being “cross-cutting” or “first-of-kind” (see more examples here). I prefer something lightweight, so I start with a single criteria:
Will I be searching Slack about this in 6 months?
Slack is a wonderful tool for unearthing past work. But instead of you-had-to-be-there conversations or ancient PRs, you’ll find comprehensive time capsules of your project’s signpost moments: here’s what was happening, and what we decided to do about it.
What Do We Write?
We know want to document decisions, and we know when, but what do we actually write? Here, too, I like to keep it lightweight. A decision record should contain, at a minimum:
- Some context or problem.
- A decision made in response to it.
Whether you include other sections commonly found in decision records, like “Considered Options” or “Consequences”, is up to your team, and may vary from decision to decision. Like significance criteria, experiment with different formats and see what works.
Finally, keep your writing high-level, similar to how you might describe it to someone new to the project. Technical jargon is okay as long as it’s not too project-specific. And save yourself some writing (and the audience some reading) by providing as much supporting material as you can. Code snippets, links to PRs or stories, and Mermaid charts all help bolster the narrative and give the audience ways to chase down more detail as needed.
Looking Back & Forward
It was ultimately my own experience writing decision records that sold me on them. I’m much more confident in the docs I write – I know they will never be wrong, and even if they are superseded by future decisions, they’re still an important part of the story.
This confidence cut through the feeling of painstakingly untangling my knowledge to get it on paper. Instead, I felt like I was mapping a journey – “we were here, and we went in this direction.” Sure, there was plenty behind me that was still undocumented – but the important places will get mapped, if and when you need to double back.
Start when and where you are, and keep going. Give it a few months, enough time to not just record your big decisions, but to refer back to them. You may be surprised at how much easier it is to see not just where you’ve been, but where you are going.
Loved the article? Hated it? Didn’t even read it?
We’d love to hear from you.