Back to Blog
Available in:
May 6, 20264 min read

Why I Write ADRs Before Writing Code

Code captures what you built. An ADR captures why you built it that way — and the why is the first thing to disappear as a project ages.

Without the decision context written down, every past architectural choice looks arbitrary to whoever arrives later. That applies to a new engineer on the team, and increasingly to an AI agent trying to make sense of the codebase.

The problem isn't documentation

It's context transmission. Code is excellent at capturing the what and the how. It is terrible at capturing the why and the why we didn't do it differently.

In projects that run longer than six months, this shows up predictably. Someone questions an architectural decision. Nobody remembers the original reasoning. A two-hour discussion happens, and the conclusion is "let's keep it because we don't know what changing it would cost."

The alternative version: the discussion starts, someone opens ADR-006, reads the context in five minutes, and the decision to keep or change gets made with actual information.

For AI agents working in the codebase the problem is sharper still. An agent without decision context will propose "improvements" that violate constraints existing for good reasons — and you'll spend your time reverting changes generated by missing context.

The format

I use Michael Nygard's original format, versioned in the same Git repository as the code:

# ADR-NNN: Descriptive title

## Status
Proposed | Accepted | Deprecated | Superseded by ADR-XXX

## Context
Why this decision needs making now. What forces are in play.

## Decision
What was decided, stated affirmatively: "We will use X."

## Consequences
What changes as a result — the good and the bad.

The value isn't in the document. It's in forcing explicit articulation of the reasoning before you code. If you can't write the context and the alternatives, you probably don't understand the problem well enough to decide well.

When to write one

The criterion is reversibility, and the rigor should be proportional to the cost of undoing the decision.

Reversible, low cost of change — switching CI from GitHub Actions to CircleCI. No formal ADR needed. A line in the commit message covers it.

Irreversible, or expensive to reverse — the multi-tenancy isolation scheme, the ORM, the tenant data model. These need an ADR.

The multi-tenancy decision is the clearest example. Changing a tenant isolation scheme in production would require migrating every active tenant's data, coordinating downtime, and re-validating isolation afterward. The cost is measured in weeks. Documenting the context beforehand cost thirty minutes.

That asymmetry is the entire argument.

What twelve ADRs actually covered

For a compliance product, the set covered the search provider, the classification engine, persistence, job scheduling, deduplication of repeated alerts, the multi-tenancy model, authentication and authorization, and the core stack — among others.

What's notable is what isn't in that list. No ADR for code formatting. None for the test framework. None for the CI provider. Those are all cheap to change, so they didn't earn the ceremony.

What I learned

Writing the ADR frequently changed the decision. Several times I started documenting a choice I'd already made, hit the "alternatives considered" section, and realized I couldn't articulate why the obvious alternative was worse. That's the mechanism working — the document is a thinking tool that happens to leave an artifact behind.

Keep the status field honest. An ADR marked Accepted that the codebase no longer follows is worse than no ADR at all, because it actively misleads. When an approach changes, mark the old one Superseded by ADR-XXX rather than editing history.

And write them at the moment of the decision, not afterward. A retrospective ADR reconstructs a rationalization; a contemporaneous one records a reason.

References

ArchitectureDocumentationDecisionsEngineering