ADRs (Architecture decisions records) is one of the main techniques for registering context related to our software architecture evolution.
For several years, we have learned about them in many books, conferences, and blog posts.
Along with this article, I will expose some aspects and practices of my preferred workflows to manage Architecture Decision Records.
These practices make sense, especially when many teams contribute to several components and projects related to big software architectures.
Let’s remember why ADRs are an important thing.
Last September, I took some days off to visit Peñiscola, Spain.
If you avoid the crowd and go there in late September, Peñiscola is a great place to have a perfect disconnection, sunbathe, and experiment with the authentic serenity of one of the longest Mediterranean beaches.
Apart from all of this, Peñiscola is well known because of its castle.
This castle is one of the last templar fortresses. This one was built on top of a prominent crag over the sea.
Although the castle is known for being templar, its origins are Arabic. It was an Alcazaba (an Arabic fortress) for many centuries, from 718 to 1233.
From 1294 to 1307, the templar knights rebuilt the fortress following the templar castles’ patterns. Yes, it only took 13 years to rebuild the entire castle!
In the following years, they made several modifications to transform it into an impregnable fortress.
After a couple of centuries, the templar knights left the castle, abandoned until 1411.
In the late century XVI, the architect Battista Antonelli added modifications to the castle’s walls with a renaissance style and built the weapons courtyard from scratch.
We know many details about the evolution of this castle’s architecture thanks to the historic registry.
Similarly, the different architects could add their contributions to this magnificent castle thanks to understanding the previous decisions and the historical context related to each of them.
Back in 2021, and thinking about our software or infrastructure systems, the fact is that we make a lot of architecture decisions not per decade or centuries, but per month.
In the first iterations, those decisions are usually made per week!
ADRs are a great tool to register the context of every decision and other evaluated alternatives to them. This is crucial information for new people who will need to evolve the architecture in the future.
ADRs are usually based on a simple Markdown file. There are many different templates out there. On this GitHub repository, we can find some of them.
Although there is no standard and can use any template you want, the most conventional template is the adr-tools one. The adr-tools tool has been adopted massively, and other tools like structurizr or ADRGen are using part of its structure for the title, date, and status.
Here is an example based on this template:
# 1. Record architecture decisions
We need to record the architectural decisions made on this project.
We will use Architecture Decision Records, as described by Michael Nygard in this article: http://thinkrelevance.com/blog/2011/11/15/documenting-architecture-decisions
See Michael Nygard's article, linked above.
In any case, the essential part of an ADR is not about the format but leaving the minimum context that impacted the decision, allowing others to make better decisions in the future.
The status information is also important because it clarifies if the decision has been taken or not. It communicates the step where the decision is related to our workflow.
It is essential to have a transparent workflow that is understandable by all the people of our teams.
Understanding and designing your ADR status lifecycle.
When we are using Architecture Decision Records, probably we are following a workflow like the one that is described in the diagram below:
We are used to using the following statuses:
Proposed is the initial status. Every decision starts with a proposal describing the context, alternatives considered and the solution described in it. All the people interested in the solution add contributions to the proposal and comments to the ADR file.
The proposal is voted, and depending on the result, it changes its status to accepted or rejected. At that moment, the ADR content is immutable, and only the status can be modified in the future.
The only way to modify or improve a decision is by creating another new decision. New decisions can supersede or amend another decision to replace or improve it, respectively.
When you supersede a decision with another one, the previous decision changes its status from accepted to superseded, and the relation between the decisions is written in both ADR files.
Similarly, the same is done in other contexts when you amend one ADR file with another new one.
We need to take into account the ADR file status lifecycle to design our reviewing workflows.
As the ADR template format, we can customize this lifecycle to adapt it better to our ways of working. Tools like ADRGen can help us define the different statuses we support in our custom workflow and ensure all our teams follows it.
ADRGen allows creating a YAML configuration file in our repository to specify the custom statuses we need in our workflow. When someone tries to change an ADR file with a new status, ADRGen will validate it to ensure that only the right statuses are used.
Even if you don’t want to use ADRGen or any tool at all, it is important to document the workflow and status lifecycle we are using in the company for all the people to be aware and engaged with the process.
ADR as living documentation.
Living documentation (or documentation as code) is a crucial practice for software engineering teams and technology companies.
The goal is that the documentation is generated and updated automatically, extracting it from the source code instead of writing it manually.
These sources could be, for example, Behaviour Driven Development tests written in the Gherkin language, Architecture Decision Record files, Contract Testing files, Specification YAML files, etc.
The generation process relies on a Continuous Integration pipeline that will transform the source format to the format that the end-users expect.
This removes the manual effort of ensuring that the documentation remains updated while the final file’s format generation is delegated on an automatic tool.
For example, every time that a Pull-Request is merged in our repository after the ADR review process, we can regenerate a static web portal, pdfs, or word documents using a corporate design template, regenerate read-only pages in a concrete section in our Confluence, or generate another documentation format that we could imagine.
The automatic generation of documentation comes with another challenge: the documentation needs to be findable and easy to discover.
Improving the findability and discoverability.
If we have many teams working in different parts of a big architecture, we can end with hundreds of ADR entries in our registry.
It could be challenging for new people to review and be aware of the relevant decisions they need to understand and consider before contributing to the team.
A solution I find interesting is adding a front-matter section to our ADR and other Markdown files. The front matter section is just a YAML section in the Markdown files that contains metadata.
---# 1. Record architecture decisions
You can use the ADRGen tool to adding them easily to your ADR files.
The specified metadata in the front-matter section can be useful for many purposes. In the living documentation context, we can add labels and filters to our generated documentation, allowing the engineers to filter and discover only the architecture decisions relevant to them.
Metadata can also be useful to make it easy to automate notification channels for the people interested in the evolution of specific parts of the overall architecture.
Socializing the ADR workflow.
In a context where many teams work in different domains, components, or projects related to a single architecture or ecosystem, it is important to get all the people on the teams engaged and updated about the decisions being made in a concrete moment.
As an engineer, it could be easy to lose the context about parts of a big architecture when you are too focused on the domain you are responsive to.
This is not a new idea; Software architecture reviews are done for decades. We can find some ideas about driving the review process of the architecture decisions from papers about this topic.
I found these three especially interesting:
- D.L. Parnas and D.M. Weiss, “Active Design Reviews: Principles and Practices” written in 1987, where they propose a better alternative than the old processes of software architecture review. Ironically, we can find these processes were considered old at the end of the ’80s in some current companies.
- R. Kazman and L. Bass, “Making Architecture Reviews Work in the Real World” written in 2002, where they expose the different steps of a review process and how to drive review meetings effectively. Although their recommendations are mainly for synchronous rituals, we can take some ideas for designing an asynchronous process.
- M. Ali Babar and I. Gorton, “Software Architecture Review: The State of Practice” written in 2009, where we can find interesting data about the benefits, a resume of practices, and other interesting references.
If we have implemented a workflow as this article described earlier, it can be easy to drive an asynchronous conversation through the open Pull Request in your GitHub or GitLab space.
Some tips can be useful to ensure engagement:
- Automate the new Pull Request notifications only for the ADR file updates in concrete slack (or another messaging tool) channels. Ensure that all the people interested in understanding the architecture decisions are aware of that channel’s existence.
- Depending on the size, amount of scopes, and diversity of your architecture’s components, you will need to design your notification strategy to ensure the right number of asynchronous channels. Too many notifications could be ignored or churn the attention of the engineers.
- Use the metadata in the markdown files' front-matter section to filter or distribute notifications in the right notification channels and improve your decisions’ findability and discoverability.
- Set a due date to make it clear when a decision will be closed as accepted or refused. If we don’t set a due date, decisions could remain open forever, adding noise to our registry. It doesn’t make sense to have a decision open for a long time.
- Determine how the validation will be made: by consensus of a group of determined roles, by a concrete number of approvals, by the approval of the owners of a concrete domain, etc. There is no silver bullet here; it depends on the context and the team.
Architecture decisions records are a fundamental tool to register our decisions’ context and status related to the software and systems we build.
We can also see them as a powerful tool to share relevant context and information with other teams engaging other workmates in our decision-making process.