practice · adrs & technical design
Writing ADRs
A technical decision recorded in writing, with the alternatives that were considered and rejected. The artefact that survives the developer leaving. Written before the code, not after.
TL;DR
An ADR captures one constrained choice that would cost more than a day to undo. It uses MADR format — seven sections. It has at least two real options (the third is usually do nothing). It is signed by two engineers before the code lands. If you cannot name a real alternative, the decision is not an ADR — it is a default.
What it is
An ADR (Architecture Decision Record) records a technical decision that constrains future code. It is named in What We Shape · ADR. It does not record decisions with no constraints — we are using TypeScript is not an ADR. We are using Mongoose rather than Prisma for this service because of [reason], accepting [trade-off] is.
Distinguish from
Technical Design Brief — the cycle's technical shape; references ADRs. System design doc — multi-cycle, multi-team; ADRs are one decision. RFC — proposal stage; ADR is the signed decision. See Confusable with at the foot.
Why it matters
Without ADRs:
- Choices are made implicitly. The only record is in commit history; the why is lost within six weeks.
- The same choice gets re-made. Three engineers each fix the same symptom differently because nobody agreed once.
- Reversibility decays. Reversing a never-recorded choice costs more than reversing a signed one.
- The next senior engineer cannot reason from precedent. They re-invent or worse, re-litigate.
The ADR is the corpus's discipline against the architecture happening by accident.
How to do it
Step 1 — Decide whether it deserves an ADR
Two filters. If the answer is yes to both, write an ADR.
- Would undoing this choice take more than one day of work?
- Will a reader six months from now want to know why this rather than the alternative?
Filing every decision as an ADR floods the record. Filing too few hides the structural choices. The rule of thumb: a normal cycle produces 0–2 ADRs. A foundational cycle (new service, new persistence, new auth) may produce 3–5.
Step 2 — Status: Proposed
Open the ADR as Proposed. The Proposed state is for the team to read and react. Do not start coding the chosen option while the ADR is Proposed.
Status: Proposed
Date: 2026-05-17
Author: the TLStep 3 — Context and Problem Statement
What forced this decision now? Bind it to the cycle's brief.
## Context and Problem Statement
The cycle's Feature Brief commits to "Gal grades a cycle in
<15 min". The cycle requires persisting normalised Hebrew
names with diacritic-fold lookup. The current Mongoose
service does not support custom collation per field.
We must decide where the normalised form lives and how
it is queried.Step 4 — Decision Drivers
The forces and constraints. Two to five, no more.
## Decision Drivers
- Read-path performance: queue render <300 ms (TDB ility).
- Reversibility: this cycle's brief, with possible follow-up
cycles changing the locale set.
- Operational cost: existing team's familiarity with current
ORM.
- Schema migration cost: ~50 M rows in submissions table.Step 5 — Considered Options (≥2, including do nothing)
At least two real options. Do nothing is always one of them. Do nothing means: ship the cycle without solving this, with named consequences.
## Considered Options
1. Application-side normalisation on write, indexed normalised
column in DB.
2. DB-side trigger normalising on insert/update, with
covering index.
3. Do nothing — accept current alt-tab pattern, write a story
for a documented Hebrew-name search workaround.If you cannot name a second option, the "decision" is a default. Stop. Find the second option, or downgrade this to a TDB note.
Step 6 — Options Analysis
Pros and cons for each, anchored in the drivers.
## Options Analysis
### Option 1 — Application-side normalisation
Pros:
- Lives in our codebase; team owns it.
- Easy to evolve when locale set changes.
- Testable in unit tests.
Cons:
- Read-only queries from other services bypass it.
- 50 M-row backfill needed.
### Option 2 — DB-side trigger
Pros:
- All paths through DB get correctness.
- No application code touches normalisation.
Cons:
- DB-side logic harder to evolve; harder to test.
- Team less familiar with trigger debugging.
- Same 50 M-row backfill needed.
### Option 3 — Do nothing
Pros:
- Cycle ships faster.
- No 50 M-row backfill risk.
Cons:
- The brief's prediction will not be met.
- The alt-tab workaround remains a Level 2 chain failure
we are knowingly accepting.Step 7 — Decision Outcome
The chosen option, with the trade-off explicitly accepted.
## Decision Outcome
Chosen: Option 1 — Application-side normalisation.
Rationale:
Reversibility is the dominant driver. The locale set will
change in the next two cycles; application-side normalisation
is changeable in code. The 50 M-row backfill is identical for
options 1 and 2; option 1 only adds a wrapper in the service
layer.
Trade-offs explicitly accepted:
- Read-only queries from other services that query the
submissions table directly will see un-normalised names
until a follow-up ADR migrates them. ETA: 1 cycle.
- The team takes on the operational responsibility of
keeping the locale map current.Step 8 — Consequences
Positive, negative, and risks.
## Consequences
Positive:
- Read-path performance protected by indexed normalised
column.
- Easy to add Russian/Spanish locales without DB change.
Negative:
- One additional service-layer write path to maintain.
Risks:
- If the locale map drifts between application and the
backfill, queries return stale data.
Mitigation: locale map version pinned in DB row metadata.Step 9 — Sign and move to Accepted
Two engineers sign. Status moves to Accepted. The ADR is now precedent — future ADRs that contradict this must explicitly say so (Superseded by ADR-NNN).
Signed by: the TL, the senior dev
Status: Accepted
Date: 2026-05-19A complete ADR
See the template for the copy-paste skeleton.
Evidence
Across cycles, ADRs that aged well shared three properties.
- They named do nothing as a real option. ADRs without a do nothing option were superseded within two cycles 3× more often than ADRs with do nothing. The discipline of writing do nothing honestly often changed the chosen option.
- The trade-off was named in the Decision Outcome, not buried in Consequences. ADRs whose trade-off lived in Decision Outcome · Trade-offs explicitly accepted produced less drift in the implementation than ADRs whose trade-offs lived in Consequences.
- They were signed before the code. ADRs written after the code landed described what was rather than why we chose; the why decayed within a quarter.
Anti-patterns
| Pattern | What it looks like | Where to fix |
|---|---|---|
| One-option ADR | "We considered approach X and went with X" | Clinic — An ADR with one option |
| ADR written after code | The choice is in commit history; ADR is retroactive | Write at Proposed before code; the team reads it before approving |
| Trade-off buried in Consequences | "Things we lost" listed but never confronted | Move to Decision Outcome · Trade-offs explicitly accepted |
| Default decisions filed as ADRs | We chose REST because… (no real alternative considered) | This is not an ADR; record it in the TDB instead |
| ADRs that never get superseded | Status all Accepted, none Superseded | Either the architecture never changes (unlikely) or supersessions aren't being recorded — the precedent is decaying silently |
Confusable with
| This | Not this | Difference |
|---|---|---|
| ADR | TDB | TDB = the cycle's technical shape; ADR = one constrained choice that survives the cycle |
| ADR | RFC | RFC = proposal for discussion; ADR = signed decision |
| Do nothing | Defer | Do nothing is we ship without it, accepting [consequence]; defer is we'll do it next cycle |
| Trade-off accepted | Consequence | Trade-off = what we knowingly chose to lose; consequence = what happens next |
Further reading
- Canon — What We Shape · ADR · Sequence, Schema, API · Ilities Selection
- Template — ADR (MADR format)
- Checklist — ADR · ≥2 options including do-nothing
- Clinic — An ADR with one option
- Practice — Writing Technical Design Briefs — the cycle artefact that references ADRs
- Skill path — Tech Lead foundations · Step 4
- Reference — Area · ADR