Explain the Why
Records the reasoning a diff cannot show — what you rejected, and what would make this the wrong choice later.
When to reach for it
Right after making a choice that looks odd from the outside: a workaround for someone else's bug, a hardcoded number, deliberate duplication, an unusual dependency.
What changes
- Each non-obvious decision gets one written reason where the code lives, answering why rather than restating what.
- The alternatives you rejected are named, so the next person does not clean the code back to the thing that already failed.
- Constraints are pinned to something checkable — a version, a measurement, a date, an upstream issue — instead of resting on memory.
- Every magic number carries its origin: measured, mandated or guessed. Guessed is a fine answer once it is written down.
- Each note says what would make it obsolete, so stale reasoning can be found and removed instead of outliving everyone who understood it.
Pairs with
- Handoff NoteCompresses a long session into the few things the next person — or the next agent — needs in order to keep going.
- Ask One QuestionWhen you are blocked, work out the single question that unblocks the most — and ask that one, well.
- Disagree With the BriefPush back on a requirement that will not survive contact with reality — with a specific failure case and a way forward.
Explain the Why
A diff shows what changed. It never shows what you rejected, or what would make this the wrong choice. Write that down while you still remember it, which is now and not later.
1. Find the decisions in your own change
Read the diff for anything a competent stranger would want to change on sight:
- A workaround for someone else's bug
- A number that is not self-evident: a timeout, a batch size, a limit
- Duplication you chose on purpose
- An unusual dependency, or an obvious one deliberately not used
- Code that looks wrong and is not
- An ordering that matters for a reason the code does not reveal
2. For each, write three things
What you did, what you rejected, and why the rejected option fails here. The middle one is what stops the next person from confidently restoring the version that did not work.
3. Anchor the constraint to something checkable
A reason ages badly unless it is pinned to a fact: a library version, a date, a measured number, a specific device, a link to the upstream issue. "This was slow" is a rumour. "This took 900ms on the smallest instance, measured on the date below" is something a person can re-test and retire.
4. Say what would make it obsolete
One sentence naming the condition under which this should be removed or reconsidered. "Delete this once the upstream fix ships" turns a permanent oddity into a task somebody can close.
5. Put it where it will be found
- Reasoning about one line: a comment at that line
- Reasoning about why the change exists: the commit message
- Reasoning that outlives the file — a datastore, a protocol, a boundary: a short decision record kept in the repository
6. Delete comments that say what the code says
They dilute the ones that matter, and they are the first to go stale.
Rules
- Do not restate the code in prose. "Increment the counter" above an increment is noise wearing a helpful expression.
- Do not write "temporary" without the condition that ends it.
- Do not record a decision as an instruction from a person. Record the reason underneath it; people move on, and reasons have to stand on their own.
- Do not leave the only explanation in a chat thread or a ticket comment. Both are searchable right up until the day you need them.
- Do not think naming a constant explains it. A constant called MAX_RETRIES still has to say why it is three.