Anika Sorensen
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.
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 queryContext. 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
-
AObservation: this advice assumes a single writer. Much of it still holds with concurrent authors but the counters section needs care.