In a previous post , we tackled the problem of doing a large change in your system incrementally. During refactoring, you can stumble upon a lot of problems, but one of the greatest is, how do you react to a past decision that you cannot understand? Do you accept it, with the risk of continuing to pay the technical debt associated with it? Or do you discard it, with the risk of losing some important semantics that should’t be lost along the way?
If you’re lucky enough, the person that made that decision will be one or two desks away. On the other hand, there is a high probability that the decision above was made a long time ago, and that person is long gone from the company you’re working. The only way to keep technical decisions without being lost is to document them. But where and how do you do it?
You all know that saving the decisions in some kind of wiki is not going to work. Large documentation files are scarcely updated along with the code, and most developers just lose their focus when they have to move away from the code and filter a large document. What’s more, you can’t keep that kind of files in version control due to their size.
Documenting with Architecture Decision Records. 🔗
The key in having successful documentation is to keep it updated in version control in small files. This is what Michael Nygard proposed in his Architecture Decision Records (from now on ADRs). ADRs are text files that save the architecture decisions taken over time and have the following format:
- Title: A small descriptive title of the decision.
- Context: A description of the constraints under whom the decision was made.
- Decision: The actual decision.
- Status: Whether or not the decision is proposed/accepted, or amended/superseded by another decision.
- Consequences: The consequences that this decision will have.
Keeping ADRs is a powerful technique, as it captures not only the decisions, but under what circumstances were made and documents the consequences at the time that the decision was actually made.
Even when a decision is superseded or amended by another one, Michael Nygard suggests that you never delete it, but mark it as superseded by the new decision. This way you can see how the code has evolved over time and you can also checkout from version control the commit that the decision was made and see what forces drove the author of the decision to make it.
Before presenting the appropriate tooling to successfully keep documentation of our decisions, let’s question ourselves, what kind of decisions should we document? If we end up saving every little detail, then the objective of keeping the documentation as small as possible and to the point fails. As Michael Nygard puts it himself, the decisions that we ought to keep are:
those that affect the structure, non-functional characteristics, dependencies, interfaces, or construction techniques
Tools for using ADRs 🔗
So let’s say that you’re now convinced that saving ADRs is a technique worth giving a shot. How should you implement it? Fortunately, Nat Pryce has made available his ADR Tools . ADR Tools is a set of command lines that create ADRs in markdown. The installation instructions are available here . After installing, you just have to type the following command:
adr init your/documentation/directory
This will create the very first ADR, saved in a markdown file. It’s also worth noting that the first thing documented is your decision to start using ADRs.
When you will add a new ADR you will simply give the following command:
adr new Name of the decision
A more exhaustive description of how to use ADR Tools is available here or you can use the command line:
Except from the help command above, Nat Pryce has also written down the decisions that were made during the development of the Tools as ADRs . This is a helpful example of real life usage of ADRs, that can guide us during our(let’s be honest with ourselves, not so fascinating) journey to meaningful documentation.
Final thoughts 🔗
Keeping ADRs seems to be a good way to save decisions that will later give good insight during refactoring. It is quite possible that you will not be the person responsible for that refactoring, or even if you are, then Eagleson’s law will be applied:
Eagleson's Law: Any code of your own that you haven't looked at for six or more months might as well have been written by someone else.— Programming Wisdom (@CodeWisdom) December 10, 2017
Before starting coding a decision that affects the architecture of a system, I think maybe it should be better to write it down as an ADR(just as you would first add a test before the real implementation in TDD).
This way, you are obliged to document the constraints under which you made the decision as the Context of the ADR, and document the Consequences as well, so you are in a position to validate that the change that you are about to introduce is built upon sound foundations.
What’s more, even if you change your mind about that decision and want to amend it with another one, you will already have documented it. The next person that will see the documentation, will be available to see a train of thoughts, and not a ladder that has some steps skipped. The decisions will make more sense, and that person will be in a position to better understand them, and in return accept or modify them.