Skip to content
All posts

Architecture

Why I Write ADRs Before Code

Md Shamim Hossain June 20, 2026 4 min read 2,411 views Updated Oct 26, 2026

An architecture decision record is the cheapest artefact you will ever produce and the only one that tells a future engineer why the obvious solution was rejected.

More ways to share

Link copied to clipboard

Code tells you what the system does. Comments tell you what a line is for. Neither tells you what was rejected, and the rejected options are usually where the real engineering judgement lives.

The failure mode an ADR prevents

Eighteen months from now someone — possibly you — will look at the queue configuration and ask why jobs retry five times with a 10-second initial backoff instead of ten times with a 60-second one. The code says nothing. Slack has scrolled past 10 000 messages. The person who made the call has left.

So they change it. And they reintroduce the exact latency spike the original numbers were chosen to avoid, because the constraint that made them correct — an upstream API with a 5rps rate limit — is not written down anywhere.

What an ADR contains

Four sections. Anything longer does not get read; anything shorter does not get used.

## ADR-007: Related posts by tag overlap, then category, with a bounded query

Context. Each post should suggest further reading without a
recommendation service. Naive candidate selection grows linearly
with the corpus.

Decision. Rank candidates by shared tag count, break ties by
shared category, then by recency. Limit to 3. Compute the ranking
in PHP over a candidate set that is bounded in the database first.

  • Consequences.
  • Deterministic, explainable, testable.
  • No extra infrastructure.
  • The candidate set must be bounded or the query degrades as the
  • corpus grows. Bounded by category plus the top-N tags, hard
  • capped.

Rejected. A window function over the full corpus — clearer in
SQL, but not portable across the SQLite/MySQL/PostgreSQL targets
this project supports.
```

The Rejected section is the one that earns its keep. It is the only place a future engineer learns that the obvious approach was considered and why it lost.

Why it goes before the code

Writing the ADR first changes what you build, because it forces you to state the constraint you are optimising for. Half the time, articulating the constraint reveals that the decision is not actually a decision — there is only one option that satisfies it.

The other half of the time, it reveals that there are two options and the tie-breaker is something nobody has said out loud yet, like "we do not have the operational capacity to run a search cluster."

That is a much cheaper discovery than making it three sprints into the implementation.

The ADR is not a design document

A design document describes what you are going to build. An ADR records a decision — a fork in the road where the alternatives were real and the reasoning is not recoverable from the code.

Things that deserve an ADR:

  • Choosing a datastore, a queue backend, or an auth strategy.
  • Deciding not to add a dependency the team expected.
  • A performance trade-off with a number attached.
  • A deliberate inconsistency with the rest of the codebase.
  • Any decision that would look like a mistake without the context.

Things that do not:

  • How a specific class is structured.
  • Naming conventions.
  • Anything reversible in an afternoon.

Making it stick

Three rules that have kept this working on the teams I have been on:

Keep them in the repository. docs/decisions/ADR-007-*.md, next to the code, reviewed in the same pull request. A wiki nobody opens is where ADRs go to die.

One decision per file, numbered, never edited. To change a decision, write a new ADR that supersedes the old one. The history is the point; editing it destroys the artefact's only advantage over a design doc.

Timebox it to twenty minutes. If an ADR takes an afternoon, you are writing a design document. The value is in the constraint statement and the rejected option, not in the prose.

What it actually buys

It is not documentation for its own sake. It is a mechanism for preventing relitigating the past, which is one of the most expensive things a team does.

A team that can answer "why is it like this" in thirty seconds spends its engineering judgement on new problems. A team that cannot spends it arguing about decisions that were already made for good reasons nobody can now recall.

Keep reading

Discussion

1 comment

Sign in to join the discussion. Comments are published under your name.

Markdown-style emphasis and `code` are supported. 0 / 2000
Held for moderation
  1. A

    Anika Sorensen

    Observation: this advice assumes a single writer. Much of it still holds with concurrent authors but the counters section needs care.
Enter your credentials to continue to your workspace.
Email address
Remember me
Don't have an account? Sign up
Enter your details below to create your account
Name
Email address
Password
Confirm password
Already have an account? Log in
Enter your email and we will send you a reset link
Email address
Or, return to log in