Skip to main content

Someone wanted to learn this too, so Grasp built them a personal learning path.

You can keep exploring this one or create your own

Documenting Architectural Decisions

Welcome back! In our last lesson, we successfully laid the groundwork for our agentic engineering assistant by setting up a TypeScript monorepo. That was a significant architectural step, choosing a specific structure and tooling to manage our project's complexity. Now, we need to formalize that choice.

This lesson is about capturing the why behind our architectural decisions. You will learn about a simple yet powerful practice called Architecture Decision Records (ADRs). We'll explore what they are, why they're crucial for long-term project health and team collaboration, and how to write a high-quality one. Most importantly for your goals, we'll see how well-crafted ADRs can serve as durable instructions for both human developers and AI agents.

By the end of this lesson, you will be able to record an architectural decision, complete with the context, alternatives you considered, the trade-offs you made, the consequences of the decision, and a trigger for when to review it in the future.

Why Record Decisions? The Problem of Lost Context

Have you ever joined a project, looked at a piece of code, and wondered, "Why on earth was it done this way?" This is a common experience in software development. Decisions are made, but the context, debates, and trade-offs behind them are often lost to time, forgotten conversations, or team members who have since moved on.

Architecture Decision Records (ADRs) are designed to solve this problem. They are lightweight, text-based documents that capture the story of a single, significant architectural decision.

To get a feel for the problem ADRs solve, please watch the first few minutes of the following video from CodeOpinion. It perfectly sets the stage for why we need a log that answers the question, "Why?"

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

This video provides a great introduction to the motivation behind ADRs.

Watch the segment from the beginning until the core problem is explained. Focus on the distinction between institutional knowledge and the need for durable, accessible context.

The Anatomy of an Architecture Decision Record

Now that you understand the problem, let's look at the solution. The core idea of an ADR was popularized by Michael Nygard and refined by many, including Martin Fowler. An ADR is not a lengthy design document; it's a concise record of a choice and its surrounding context.

For a foundational understanding of what ADRs are and how they are managed, please read this classic article by Martin Fowler.

Architecture Decision Record - Martin Fowler

This article is a concise, authoritative overview of the key principles behind ADRs.

Read the entire short article. Pay close attention to these key ideas: The "inverted pyramid" style of writing. Where ADRs should be stored (doc/adr in your repository). The lifecycle of an ADR: proposed, accepted, and superseded. The immutability principle: once accepted, an ADR is never changed, only superseded by a new one.

The structure of an ADR is simple and designed for clarity. This mind map gives a great visual overview of the components.

This mind map illustrates the typical sections of an Architecture Decision Record, providing a clear template for capturing the essential information about an architectural choice.

This mind map illustrates the typical sections of an Architecture Decision Record, providing a clear template for capturing the essential information about an architectural choice.

The Heart of the Decision: Trade-off Analysis

An ADR is only as good as the thinking that goes into it. The most critical sections—"Considered Options" and "Consequences"—depend on rigorous trade-off analysis. This is the essence of a senior engineer's work: there are rarely "best" solutions, only the "least worst" combination of trade-offs for a given context.

Neal Ford's talk on trade-off analysis is a masterclass in this thinking. We won't watch the whole video, but a few key segments will give you a powerful mental model for evaluating architectural choices.

Modern Trade-off Analysis for Software Architecture - Neal Ford - DDD Europe

This talk provides a framework for the rigorous thinking that should precede the writing of an ADR. We'll focus on the core concept and a practical example of analysis.

Please watch the following two segments: Everything is a Trade-off: Start with the introduction to understand why architecture is fundamentally about analyzing trade-offs, not finding "magic bullet" solutions. A Practical Analysis: Watch the segment on analyzing a specific trade-off (hydrated contract vs. key-only). Notice how the alternatives are compared against a set of important characteristics (scalability, performance, contract management). This matrix-based thinking is an excellent technique to bring to your ADRs.

This kind of structured analysis is what separates a weak ADR that just states a decision from a strong one that preserves the judgment behind it.

From Good to Great: ADRs for Humans and Agents

With the principles of trade-off analysis in mind, we can now focus on crafting a high-quality ADR. A great ADR doesn't just record the outcome; it preserves the tension, reasoning, and constraints that shaped the decision. This is not only valuable for future developers but is absolutely essential for guiding AI coding assistants, which lack human intuition about architectural intent.

The following article provides excellent, practical advice on writing ADRs that are useful for both people and AI.

ADRs in Practice: Aligning Teams and AI Agents Through Better Documentation

This article connects the practice of writing ADRs directly to your goal of mastering agentic software engineering.

Please read the following sections: Start with the section contrasting a poor ADR with a useful one. This is the most important concept to internalize. Continue to the section on the key questions an ADR must answer. Note the addition of the "Agent guidance" field—this is a powerful technique for our project. Finally, study the concrete example of "ADR-018: Keep domain logic out of controllers." It's a perfect model of a concise, effective ADR.

Your Turn: Recording Our Monorepo Decision

Now it's time to put this all into practice. In the previous lesson, we decided to use a TypeScript monorepo managed with pnpm and Turborepo. Let's create our first ADR to formalize this choice.

Create a new directory doc/adr in the root of your project. Inside it, create a file named 0001-use-typescript-monorepo.md.

Use the following template and the knowledge from our previous lesson to fill it out. I've provided some prompts to guide your thinking.

# ADR-0001: Adopt a TypeScript Monorepo using pnpm and Turborepo

**Status:** Accepted

**Context:**
Our agentic engineering assistant consists of several distinct but tightly-coupled components: a Vue.js frontend (`web`), a TypeScript backend (`api`), a background `worker`, and a `shared-contracts` package for type definitions and schemas. These components need to evolve together, and changes in the shared contract must be reflected across all of them simultaneously.

**Decision:**
We will use a single repository (a "monorepo") to house all project source code. We will use `pnpm` workspaces for dependency management and `Turborepo` as the high-performance build system to manage tasks across the packages.

**Considered Alternatives:**

1.  **Polyrepo (Multiple Repositories):**
    *   *Description:* Each component (`web`, `api`, `worker`) would live in its own dedicated Git repository. The `shared-contracts` package would be published to a private npm registry and consumed as a versioned dependency.
    *   *Pros:* ... (Think about independent deployments, clear ownership)
    *   *Cons:* ... (Think about the overhead of managing dependencies, atomic changes, and version drift)

2.  **Monorepo with other tooling (e.g., Lerna + npm/yarn):**
    *   *Description:* Still a monorepo, but using older or different sets of tools.
    *   *Pros:* Lerna is a mature, well-known tool.
    *   *Cons:* `pnpm` offers superior disk space efficiency and performance. `Turborepo` provides sophisticated caching and task orchestration that is more advanced than what Lerna offers out of the box.

**Consequences:**
*   All architectural decisions of significance will be documented as ADRs in the `doc/adr` folder.
*   To prevent the monorepo from becoming a tightly-coupled "big ball of mud," we **must** enforce architectural boundaries. We will use ESLint rules (`@typescript-eslint/enforce-module-boundaries`) to prevent illegal imports between packages (e.g., the `api` must not import from the `web` app).
*   The development workflow will be standardized around `pnpm` and `turbo` commands run from the project root.

**Review Trigger:**
We should revisit this decision if:
*   The CI build and test times for a typical pull request consistently exceed 15 minutes, suggesting that Turborepo's caching is no longer effective for our scale.
*   Distinct sub-teams form and need to deploy their components on completely independent schedules, and the monorepo structure becomes a significant bottleneck.

**Agent Guidance:**
When generating or refactoring code, you must respect the package boundaries defined in the root ESLint configuration. Any import that violates these boundaries must be flagged for human review, citing this ADR. When creating a new package, you must ask for guidance on how to update the ESLint dependency rules to integrate it correctly into the architecture.

Take about 15 minutes to fill in the missing Pros and Cons for the "Polyrepo" alternative based on your understanding.

Conclusion

Congratulations! You've not only learned about a key senior engineering practice but have also created the first piece of durable documentation for our project. This ADR now serves as a permanent record of our reasoning, available to anyone who joins the project in the future—including our AI assistants.

Key Takeaways:

  • Architecture Decision Records (ADRs) are concise, immutable logs that capture the "why" behind significant architectural choices.
  • They live with the code in the repository, making them easy to find and reference.
  • A great ADR is built on rigorous trade-off analysis, systematically comparing alternatives against important project goals.
  • For agentic engineering, ADRs are not just documentation; they are a critical form of durable, machine-readable instruction that guides AI tools to respect architectural intent.

In this module, we defined our project's scope, sketched its architecture, and established a process for recording decisions. We are now ready to move from planning to execution. In the next module, "Operating Coding Agents as a Senior Engineer," we'll dive into the practicalities of using AI to build our system, starting with the crucial skill of deciding which tasks to delegate and which to own.

Can't find a good explanation? Sign up and we'll make it for you

Sign up