An Architecture Decision Record (ADR) is a lightweight document that captures a significant decision relating to technical architecture, along with the context around the decision and the consequences of the decision taken. They're used by software/engineering teams to capture and communicate a choice that was taken during the design of a system.
Sounds simple? Well, it is really. But the impact of adopting this process is disproportionately bigger than the simplicity suggests. We didn't invent ADRs at endjin - this post by Michael Nygard from 2011 is often referenced as a starting point - but they've been a game-changing tool in how we work over the last few years, both on internal initiatives and OSS projects, as well as with our customers teams' and their technology solutions.
There's a lot of existing posts around the ADR process, including from well established industry leaders like Google and Github, and this post isn't intended to replace that thinking. If you're new to ADRs, I'd recommend reading a variety of perspectives, especially as everyone has slightly different flavours of how they've implemented ADRs in their team.
But whilst there's a lot out there about how to write (good) ADRs and even when to write ADRs there's less of a focus on the why, beyond a few high level, generic statements. Even more so, specific examples about how they've helped real teams are hard to find.
So, this post aims to add some real world context around the positive impact of ADRs in our team. It's based on a few years of experience of applying ADRs to a variety of project, architecture and customer scenarios. It's not intended to be a rigid or prescriptive set of instructions of what to do, but an explanation of why you should be doing it.
But first, for the sake of completeness, let's start with an example. As I already mentioned, there are many existing variations of an ADR template, and many opinions as to why you should use one or the other. Here's a template that we typically start with, but we might sometimes tweak it if there's a specific and valid reason to do so. Regardless, the important thing to remember is that the value and impact of this process isn't in the choice or format of the template.
# Title: An example ADR document
Status: proposed | approved | deprecated
## Context and Problem Statement
This is the background context as to why we need to make this decision and the scope of the decision being made
## Decision Drivers
- We needed to consider this which will impact the decision
- And also this
## Considered Options
Here we enumerate the options that we've considered, why, and the unique/specific characteristics of each option
1. Option 1
Details about option 1
2. Option 2
Details about option 2
## Decision Outcome
The decision we have made given the options above
## Pros and Cons
This is the impact/consequence of the decision taken
## Mitigation strategy
These are the things we might consider doing to mitigate the negative outcomes/impact of the decision
Whichever template you choose, the following key points should apply:
An ADR must have a title. The title scopes the ADR to a particular decision that needs to be made. The ADR is not intended to be a "Solution Architecture Document", rather a series of documents about specific pieces of the solution architecture.
An ADR must have a status. The status indicates whether this ADR is still in discussion, it has been agreed, or it has been deprecated and/or superseded by a different decision.
An ADR should be a plain text document. The most obvious choice here is markdown, so that we can add a structure, but stay within our favourite IDE (more on this later).
An ADR should be stored in a version control system. This means that we can see when the decision was made, and how the decision has evolved/changed over time in relation to the technical solution.
Now we've got the basics out the way, let's explore why ADRs are so effective.
ADRs allow decisions to be made asynchronously
Because we use markdown for our ADRs, and because we store and version them in a Git repository, it means we can review, comment and collaborate on them in the same way that we would for a code artefact change. Specifically, we can use pull requests as part of our collaboration and review process, which also means we can set policies around the approvals that are required and we automatically get an audit trail on those approvals.
This is significant as it means our decision making process can be asynchronous, and can include all the relevant parties, regardless of location, timezone and calendar schedule. This doesn't negate or prohibit more "traditional" decision making processes - for example formal CAB meetings or realtime discussion/white-boarding, but it means we're not restricted by synchronous communication channels to reach consensus.
ADRs allow documentation to reflect a specific state of a system
Because we store and version ADRs in the same Git repository as our application/solution artifacts (we typically have a
/docs/adrs) folder in our repositories, our decisions follow the same timeline as the state of our codebase. If a new feature has an architectural impact, then a logical set of changes includes not only the associated application and infrastructure artefacts, but also the ADRs that needed to be written/updated as part of this change.
This means that for any state of the repository - for example, if we need to roll back to a previous version, or just understand historical context - the architectural documentation is correct and reflects that point in time.
ADRs allow us to evidence our thinking process
Typically the answer to any architectural question starts as "it depends", and the hard work is in understanding the specifics of those constraints around which the decision depends on. Because ADRs capture the context, constraints, considered options and consequences around the decision making process, they're deliberately designed to "show your working out", rather than just the outcome.
As developers / software engineers / architects we're paid to solve problems, which means being paid to think, and ADRs capture that thought process as a physical artefact. And if you're a consultant / consultancy like us, this can prove incredibly valuable by adding tangible and explainable output to what can otherwise seem like a black-box process.
ADRs allow us to do successful handovers
All documentation is useful in knowledge transfer - whether that's onboarding someone new into the team, or handing over from one team to another. But documenting the what only goes so far in embedding understanding. Because ADRs add the why - they can shortcut that understanding, meaning follow ups and deeper dives are relevant and contextual and therefore more valuable in gaining knowledge.
ADRs can also help with politics or egos in handovers - diffusing classic team dynamics like "not invented here" or avoiding unnecessary changes in direction caused by new or dominant voices. Because ADRs capture decisions that are based in context and around a set of drivers/constraints, they should only be revisited/challenged when one of more of those input factors change.
ADRs allow us to establish a shared set of defaults
Some of the most effective technology frameworks are opinionated, taking advantage of sensible defaults and conventions that allow you to move quickly. But in order to have those opinions, they need to make assumptions about the context in which they apply. If you align to that context, then things go smoothly, but if you don't things get difficult quickly.
The same principles apply when thinking about ADRs. Because they frame a decision in a specific context and/or set of constraints - if the same factors are true in the future, then the decision outcome should be the same. This is very powerful when you start thinking about a wider context than your specific project/team/solution. We can create a library of shared/common ADRs that allow us to establish our default decisions across a variety of scenarios. As well as creating consistency, this reusability of decisions adds efficiency to the decision making process, as you only need to focus on the exceptional cases.
ADRs allow us to make progress whilst acknowledging change
Change is inevitable in technology projects - it's why the agile movement emerged as an effective way to deliver software. Technical architecture in a changing landscape can be challenging, but decisions need to be made in order to progress. Because ADRs acknowledge context, and they are stored in a version control system, they allow us to make decisions based on the known context at any specific moment in time. This can help us avoid getting to "analysis paralysis", where we overthink decisions based on too many hypothetical "what-ifs". We can capture the context and make a sensible decision at the last responsible moment.
ADRs also include acknowledgement of the consequences of the decision, and possibly even the circumstances under which the decision might be revisited. Typically this would relate to the core pillars of project management - timelines, scope/quality or cost. If one of these factors changes then there may be reason to change an impacted decision.
ADRs mean that things actually get documented
It's no secret that documentation isn't always high up on a technical team's agenda when given a choice of what to prioritise. Because we write ADRs in markdown, and use familiar tools and processes to do so (we mostly use VS Code to author markdown documents), there's a subtle yet important psychological shift in how ADRs are viewed by the team - not as unnecessary Word documents that won't ever see the light of day again - but a living and breathing part of the codebase.
When you factor in all the benefits above, everyone understands why this process is valuable, as they've seen it benefit them in so many ways, so there's been no friction around this adopting this process as part of our core ways of working.
ADRs are not tied to Architecture Decisions
Finally, whilst everything so far has been about architecture, it's worth pointing out that this decision making process can (and should) be applied to any key decision across the design process. Conveniently the acronym can easily be updated to "Any" Decision Record if you desire, or just drop the "A" entirely. Architecture Decision Record is the most widely used term, so stick with that if you want to communicate a well known process, but feel free to adapt it if you feel it's going to have benefit for you and your team.
A note on tooling and templates
As I've already mentioned - the value and impact of the process isn't tied to a specific ADR template or format or acronym. Find one that works for you and get going. If you're going to adopt ADRs at any kind of scale, then you might want to look at tooling, for example
dotnet-adr - a .NET Global Tool that separates out the mechanics of managing the documents from the library of templates that you might want to use. You'll also find lots more references and pointers to examples.