Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 70

Documenting Architectural Decisions with ADRs

Recommended resources

Hello!

In our last lesson, we compared REST, GraphQL, and gRPC, focusing on how to choose the right API paradigm based on the specific needs of your application. This process of evaluating trade-offs and making a deliberate choice is a core activity of a software architect. However, making the decision is only half the battle. What happens six months or two years from now when a new team member (or even your future self!) looks at the system and asks, "Why did we do it this way?"

This lesson tackles that exact problem. We will cover how to document an architectural choice using an Architecture Decision Record (ADR). You'll learn what ADRs are, why they are one of the most valuable and lightweight tools in an architect's toolkit, and how to create them effectively. This practice is a crucial step in formalizing your architectural thinking and ensuring the rationale behind your decisions stands the test of time.

1. The Problem: The Mystery of the "Why"

As a developer, you've likely encountered code, a library, or a design pattern in a project and had no idea why it was chosen. This "codebase archaeology" is a common and frustrating experience that slows down development and increases the risk of making poor changes.

The core issue is the loss of context. The original team understood the constraints, the alternatives they considered, and the reasons for their final choice. But this knowledge often exists only in meetings, chat logs, or people's heads, and it fades over time.

To understand this problem more deeply and see how ADRs provide a solution, let's start with a short video.

Architecture Decision Records (ADR) as a LOG that answers "WHY?"

This video, 'Architecture Decision Records (ADR) as a LOG that answers "WHY?"' from CodeOpinion, does an excellent job of setting the stage by describing the common pain points that ADRs are designed to solve.

Please watch the first segment (00:00 - 02:49). Pay close attention to the distinction between simply knowing what was decided and understanding the context of why it was decided.

As the video highlights, the goal is to create a persistent log that captures the context and reasoning behind significant decisions. This is precisely the purpose of an Architecture Decision Record.


2. What is an Architecture Decision Record?

An Architecture Decision Record (ADR) is a short, text-based document that captures a single, important architectural decision. The collection of all ADRs for a project forms an Architecture Decision Log (ADL).

Architecture Decision Records in the Software Development Lifecycle
As this diagram shows, an ADR formalizes a key decision within the software design process, capturing its context, the options considered, the final decision, and its consequences to guide future development.

So, what makes a decision "architecturally significant"? It's any choice that has a measurable effect on the system's structure, non-functional characteristics (-ilities), dependencies, interfaces, or construction techniques.

To get a formal definition, let's turn to another expert.

Lesson 55 - Architecture Decision Records

In 'Lesson 55 - Architecture Decision Records,' Mark Richards from Software Architecture Monday provides a concise and clear definition of what constitutes an architecturally significant decision and outlines the core structure of an ADR.

Watch the first part of the video (00:10 - 01:08), where he breaks down Michael Nygard's definition of an architecturally significant decision.

Key points to remember:

  • One Decision per Record: Each ADR focuses on a single decision to maintain clarity.
  • Immutable Log: ADRs are not "living documentation" that you constantly update. They are a historical record of a decision made at a point in time. If a decision is changed later, you create a new ADR that supersedes the old one, preserving the history.
  • Stored with the Code: ADRs are typically written in a format like Markdown and stored in the project's version control repository (e.g., in a docs/adr/ directory). This keeps them close to the code they describe.

3. The Anatomy of an ADR

While various templates exist, the most common one, proposed by Michael Nygard, consists of a few key sections. Understanding these is key to writing effective ADRs.

Let's explore these sections with a reading and a video walkthrough.

Blueprint for Brilliance: The Anatomy of an ADR

The article 'Blueprint for Brilliance' provides a well-structured overview of the core components of an ADR. It helps reinforce the purpose of each section.

Read the section titled 'The Anatomy of an ADR'. Focus on the purpose of the 'Title', 'Status', 'Context', 'Decision', and 'Consequences' components.

Now, let's see these components come to life with a concrete example.

Lesson 55 - Architecture Decision Records

This segment from 'Lesson 55 - Architecture Decision Records' details the five core sections of an ADR and then applies them to a realistic scenario.

Please watch from 01:08 to 07:21. The first part (until 03:26) explains each section in detail. The second part demonstrates how to fill out an ADR for a decision about using a centralized vs. a dedicated message broker. This is a perfect example of a real-world architectural choice.

To summarize, a standard ADR includes:

  • Title: A short, numbered noun phrase describing the decision. E.g., 001-Record-architecture-decisions.
  • Status: The current state of the decision (e.g., Proposed, Accepted, Superseded by ADR-005).
  • Context: This is the "why." It describes the problem, the forces at play, the constraints, and the alternatives considered. This is arguably the most important section.
  • Decision: This is the "what." A clear and affirmative statement of the chosen course of action. It often starts with "We will..." to be unambiguous.
  • Consequences: This captures the "so what?"—the trade-offs. It should list both the positive outcomes of the decision and any negative impacts, new risks, or future decisions that are now required.

While text-based templates are common, some teams use more visual or collaborative formats.

Architecture Decision Record Canvas Example
This "ADR Canvas" from Miro is an alternative template that visually lays out the drivers, alternatives, and decision, making it well-suited for collaborative brainstorming sessions.

4. The ADR Workflow and Tooling

Creating ADRs should be a lightweight process integrated into your team's workflow.

The Process:

  1. Draft: When a significant decision point arises, a team member creates a new ADR file and drafts the Context, listing alternatives.
  2. Review: The draft is shared with the team (e.g., via a pull request). This is where discussion and debate happen. The goal is to reach a consensus.
  3. Approve: Once the team agrees, the Decision and Consequences are filled out, the status is set to Accepted, and the ADR is merged into the main branch.
  4. Supersede: If a future decision invalidates an old one, a new ADR is created. This new ADR explicitly states that it supersedes the old one (e.g., Supersedes ADR-002), and the old ADR's status is updated to Superseded by ADR-015. The history is preserved.

Tooling and Resources:

You can manage ADRs with simple text files, but tools can streamline the process. adr-tools is a popular command-line utility that helps initialize a directory, create new ADRs from a template, and link between them.

The video from CodeOpinion you watched earlier demonstrates these tools in action from 04:08 onwards.

For practical application, having good templates and examples is invaluable. The following resource is a comprehensive collection.

Architecture decision record (ADR) examples

This GitHub repository by Joel Parker Henderson is a fantastic, practical resource. It contains definitions, templates, and dozens of real-world ADR examples.

Spend about 10 minutes exploring this resource. First, look at the 'ADR example templates' to see different styles, starting with the popular one by Michael Nygard. Then, browse the 'Examples' section. Notice the kinds of decisions documented, such as 'Monorepo vs multirepo' or 'CSS framework'. This will give you a strong sense of what constitutes an 'architecturally significant' decision.

Test your understanding!

Recall the last lesson where we compared REST, GraphQL, and gRPC. Imagine your team has decided to build a GraphQL API to serve your new mobile application, acting as a "Backend for Frontend" (BFF).

Based on what you've learned, how would you start filling out the Context and Consequences sections of an ADR for this decision?

Show answer

Here's a possible way to structure those sections:

Title: 007 - Use GraphQL for Mobile Application API

Status: Accepted

Context:

  • Our new mobile application needs to display complex, nested information on its main dashboard (e.g., user profile, their recent orders, and the status of each order).
  • Using our existing REST APIs would require the mobile client to make multiple, sequential HTTP requests (e.g., /user, then /orders?userId=..., then /products?id=... for each order). This "chattiness" increases latency and negatively impacts user experience, especially on slower mobile networks.
  • This pattern also leads to over-fetching, as endpoints like /user might return more data than the dashboard needs.
  • Alternative 1: Continue using REST. Pro: No new technology to learn. Con: Poor performance and high data usage for the client.
  • Alternative 2: Create custom REST endpoints for the mobile app. Pro: Solves the performance issue. Con: Tightly couples the backend to this specific frontend view, leading to endpoint proliferation and maintenance overhead.

Decision:
We will implement a GraphQL server that acts as a Backend for Frontend (BFF). This server will resolve client queries by fetching data from our internal microservices.

Consequences:

  • Positive:
    • The mobile client can fetch all data needed for a screen in a single request, improving performance and reducing data usage.
    • The client is decoupled from the backend service architecture; it only needs to know the GraphQL schema.
    • Frontend developers can iterate faster by modifying queries without requiring backend changes.
  • Negative:
    • Introduces a new technology (GraphQL) into our stack, which requires team training.
    • Caching becomes more complex compared to standard HTTP caching with REST. We will need to implement a client-side or server-side caching strategy for GraphQL.
    • The GraphQL server becomes a new, potentially single point of failure that must be made highly available. A follow-up ADR may be needed for its deployment strategy.

Conclusion

You have now learned how to formalize and document the "why" behind your architectural choices. This simple practice elevates your work from just writing code to building a sustainable, understandable, and evolvable system. It's a fundamental skill for moving from a developer to an architect.

Key Takeaways:

  • ADRs solve the problem of lost context by creating a permanent, written record of why a decision was made.
  • An effective ADR captures the Context, the Decision, and the Consequences (trade-offs).
  • ADRs form an immutable log, stored with the codebase, where new decisions supersede old ones without erasing history.
  • This practice is a powerful communication tool that helps align teams, onboard new members, and guide the long-term evolution of a software system.

Preview of the Next Lesson:
With this module on architectural patterns complete, we will shift our focus in the next module, "Designing Scalable & Resilient Systems," to the specific components and techniques used to build systems that can handle growth and failure gracefully. We will begin by exploring a fundamental building block for scalability: the load balancer, and analyze the different algorithms it can use to distribute traffic.