Architecture Decision Records: 3 keys to success
Software architecture is an art of decision making. As the project grows over time, we need to correct and change our past choices. However, their consequences can be still seen many months later. Architecture Decision Records (ADR-s) help us recording and managing technical decisions. In recent years, I introduced ADR-s in two projects, and watched how other teams use them. In this article, I would like to show 3 key points for a successful adoption of ADR-s in your project, based on my personal experiences.
For a successful ADR adoption, your team needs 3 things: understand why keeping ADR-s immutable matters, learn how to document your decision, and choose easy-to-use tools for writing them.
What is ADR?
Without going too deep into why we might need ADR-s, let’s just remind what this idea is about. A single architecture decision record basically notes down a single, important technical decision. It must include at least the following information:
- title, number and date: help us in managing records
- context: what happened that we need to make a decision?
- decision: the actual decision
- consequences: what this decision gives us (both positive and negative)
- alternatives: alternative options that were rejected
In addition to this, we must have a single place to store all ADR-s. It must be well-known and accessible to everyone in the project. We should also create a table of contents: a sortable list of all ADR-s that shows at least their number, date, and title. The ADR repository basically serves us as a decision log history, where we can look at any point in time. It allows us seeing all decisions made at different stages of the project, including the obsolete/withdrawn ones.
1st key: immutability
The key difference between an ADR and a technical documentation is that ADR-s are immutable. Once you create an ADR, you do not change it anymore. It’s like a commit in Git history. If you make a new decision that invalidates your previous choices, you simply write a new ADR, and just mark the previous one as “obsolete”.
In one of the projects, I saw that developers and architects frequently changed existing ADR-s. I asked them about this and one of the architects replied: “oh, we keep all ADR-s in Git anyway so if we want to look at the past state, we can just jump back to a previous commit”. Technically speaking, he was right. But also technically speaking, there are plenty of tools that record the history of changes. Should we call all documents created in them “decision records”? The ADR-s in that project did not differ much from a regular documentation, just they had worse navigation and structure of information.
Why immutability matters
The reason why immutability matters is that you don’t have to use any version control tool to jump to some old decision. You use ADR-s to quickly find all past decisions that affect you today. For example, you are debugging some code and you found some strange piece of code made by your teammate 2 years ago. A quick glimpse at the list of ADR-s with the magic Ctrl+F shortcut is often enough to find everything you need to know. Or maybe, the link to the ADR is in the user story description? When writing any document (even new ADR-s) you can easily link the older ADR-s without worrying than in the future, the link will become dead.
Getting used to immutability takes time. When the team uses ADR-s for the first time, developers often feel uncomfortable with it, and may feel that “making this change in this ADR is just right”. Pay attention to this and keep reminding them why immutability matters.
If you want to create just a technical documentation, create a technical documentation with proper navigation, organized by topics, not by creation date. It will be easier to navigate and use. Just giving the documents a number and sorting them by creation date doesn’t give us ADR-s.
2nd key: context, decision, consequences
When I introduced architecture decision records in a greenfield project, I encouraged everyone in the team to write them. We were making many spikes, and we agreed to capture their outcomes in ADR-s. It was a good exercise for everyone, however we quickly ran into an unexpected issue. In the beginning of this article I listed the 4 main parts of every ADR: context, decision, consequences and alternatives. In theory, they are simple to understand. It turned out that in the first ADR-s, there were all sorts of mistakes: consequences landed in decision, decision in context, context in consequences, etc. Peer reviews were very useful here. We openly discussed the best location for each piece of information. As a result, we got to the common understanding over time.
Remember that you write ADR-s to the future you. Therefore, it not only matters what you record. It is also important how you do it. It is normal that at the beginning, developers might get confused how to document their decisions. Expressing our thoughts in a clean way is also an art, and ADR-s are a good way to improve our skills here.
By doing this exercise, your team learns to discover, name and understand context and consequences. It learns how to distinguish them from the actual decision, and how they all affect each other. This leads in turn to making better decisions. It starts paying off very quickly, so pay attention to this while introducing ADR-s to a new project. I strongly recommend doing peer reviews of ADR-s, especially with people who write them for the first time.
In ADR-s, it is extremely important to distinguish context from decision from consequences. It will help you understand your own decision records in the future, and teach you making better decisions today.
3rd key: editing tools
The last key thing in introducing architecture decision records is picking up the right editing tools for writing them. It may sound like a cosmetic issue, but tooling usability affects how much time we need to spend on writing ADR-s. This translates directly to the satisfaction of developers (or their frustration), and the success of the adoption. Pay attention to:
- formatting: it should be very easy to format the text. Visual editors are the best here.
- peer-review: other developers should be able to review it and leave comments.
- diagrams: in architecture decision records, you usually draw, not write code. Make sure you can easily create diagrams and add them to the ADR.
For me, a typical ADR is usually between 1 and 2 pages long, and it takes 15-30 minutes to write it. I consider it as a reasonable time, especially if I spend it on actual writing, not working with the tool. Over the last 2 years I used 3 different tools for writing ADR-s:
- spreadsheets: good for retroactively adding ADR-s for an ongoing project, but unfriendly in other aspects: peer reviewing, formatting, diagrams.
- Git + Markdown: reviews through normal pull requests. Formatting is acceptable, but we don’t see the results immediately, and adding and updating diagrams is challenging.
- online word processor: very easy to use. Modern word processors (Word Online, Google Docs) have collaboration features and can be easily integrated with diagramming tools. However we might want to keep just the list of ADR-s in a separate tool.
A wiki can be also a good choice, but some companies don’t offer any for employees or there are restrictions in using it (as in my case, this is why I don’t list it here). Currently I’m using the combination of online word processor and just the list of ADR-s stored on wiki and I’m happy with it.
Take time to choose an easy-to-use tool for writing your ADR-s and keeping their list. Make sure that you can easily draw diagrams in it.
The 3 key points shown above address the main 3 aspects of a successful adoption of architecture decision records:
- what makes ADR a true record, so that you don’t end up with creating a technical documentation with poor organization,
- how to write them, so that you will still understand them 2 years from now,
- where to write them, so that developers like it.
Note that ADR-s are not the only technique that I use to document the project. I also maintain a regular technical documentation, but thanks to ADR-s, it is much shorter, and thus easier to keep up-to-date.
Thanks for sharing your thoughts about ADRs.
Some time ago we started to use them in my team, but we created very little of them with very brief content. And since then we are missing quite a few important decisions which were made. I wonder if that may backfire in the future.
I observe that we don’t have much motivation to actively maintain ADL. Maybe we do not clearly see a value in them. We also have a problem with who actually should write them. A leader, chosen developer, or maybe someone who implements that change?
Also, what is not obvious for me is what should be a trigger to write them. Making that decision, finishing implementation – should it be included in DOD of the story or something else? I saw that in some templates they use also “status”, like: proposed, accepted, rejected, deprecated, etc.
What you didn’t mention is what decisions are worth putting into a log and which are not. I think that only the most impactful decisions should be written down. For example, small refactoring in one service/module is not worth that but changing an aggregate to have better boundaries of consistency or changing database from MySQL to Mongo is worth it.
Ultimately when should we write ADRs and when is simply overkill and nobody will use it?
Hi! I can provide a couple of tips for you. First of all, ADR-s should not require much maintenance, that’s their point :). You only write the new ones, and link them to understand dependencies. Engage the entire team into writing ADR-s, it’s a good opportunity to build a common understanding of both the project and the consequences of various decisions. Let the tech leaders or senior developers help less experienced devs through peer reviews. Completing a spike is a good opportunity to capture the results into an ADR, but I would not wait until the implementation is finished. If you need to integrate with some other system or service, you can also document how the integration would look like and why you chose that way. Usually, the decision is the result of agreements with other teams/companies or the need to fit into the existing architecture.
Regarding “what to include”, you are right. I’d try to focus on decisions that have an impact on the entire project. As you said, refactoring of a single unit or component is probably not worth the effort, unless this is a critical piece that affects the rest. On the other hand, key technology decisions, like the database choice, blocking vs asynchronous, REST vs GraphQL, etc. are worth documenting. I also read one interesting advice: to document rejected decisions, as well. For example, you use the solution A, and one day you start wondering whether to switch to B. You do the research and conclude that you stay with A. This is also a decision, and you can make a note why you rejected the solution B. Finally: try to keep ADR-s short and quick to write (I strive for 15-30 minutes). In this way, even if you write an ADR for something less relevant from time to time (and one day you will), it won’t hurt too much.