Plan before code: review the approach, not 1,400 lines
Wednesday, 14:10. The spec was clear: add a cancellation reason. The agent's pull request touches 23 files and 1,400 lines, and somewhere inside it, a migration deletes 180,000 support notes. Maya wants to approve it by 17:00.
Ask the agent how it will do the work before it touches a file. A short plan is far easier to check than a huge change.
- Problem
A clear spec: add a cancellation reason to bookings. The agent returns a 23-file, 1,400-line change that includes a migration dropping a column 180,000 support notes live in.
- Why the simple system fails
Reviewing a huge finished change is slow and unreliable: the dangerous line hides among hundreds of harmless ones, and by then the work is sunk cost, so people approve it.
- Engineering concept
Review the approach while it is still a list of steps. A plan names the files, the data changes, the irreversible operations, the order and how each step is verified, so you can correct direction in minutes.
- Technology
Claude Code's plan mode (reads and proposes, doesn't edit), a plan review checklist, small steps on separate commits or PRs, expand/contract for schema changes.
- Trade-offs
Planning costs a few minutes and can feel slow for trivial edits; skipping it makes every large change a gamble. Smaller steps mean more reviews but each one is easy and safe to revert.
The problem
2 min- Maya · Product managerThe PR is up: 23 files, about 1,400 lines. I'd like to approve by 17:00.
- You · Engineer at StayHubOne migration converts
cancel_noteinto the new field, then drops it. - Omar · On-call SREThat's where support writes notes. About 180,000 of them.
The big idea
4 minA spec says what; a plan says how. Review the agent's plan before it edits anything: fixing a plan costs a sentence.
The decisions that matter aren't in the details of the code; they're in a few choices about how. A plan lists exactly those, and you can review it without reading TypeScript.
How it works
5 minBefore renovating a hotel floor, the manager walks it with the contractor: this wall comes out, water off Tuesday. That walk is where someone says "that wall carries the sprinkler pipe". Ask the agent for a plan (steps, files, data changes, order and checks) in , where it reads and proposes but edits nothing until you approve. Then run five checks.
- 1Scope
Does every step serve the spec? Step 6 renames
cancelBookingin 14 files: not asked. Out. - 2Data
A migration is a script that changes the database's structure or data. Any that rewrite or delete? Step 1 converts and drops
cancel_note. - 3Can't undo
What won't a code revert restore? Deleted data. Safest pattern: , as a separate decision.
- 4Verify
How is each step checked? "Run tests" at the end says nothing about real data or the real screen.
- 5Size
Can it ship in pieces? A big hides single dangerous lines. Schema first and additive, feature second.
- 6Then watch for drift
After each step, compare the changed files with the plan. Plans are predictions; you want to hear when reality differs.
Watch a decision being made
4 minYou run the plan review; Lina asks questions
Throw away the 23-file PR, get a 7-step plan in plan mode, review it with the five checks, and turn it into small steps you can verify.
- 1Ask for the plan, not the code
"Propose a step-by-step plan: files, database changes, anything irreversible, how you'll verify each step. Don't edit anything."
Why: The decisions show up as a 7-line list instead of 1,400 lines of diff.
- 2Cut scope and make data additive
Drop the 14-file rename. Change step 1 to: add a nullable
cancellation_reason, keepcancel_noteuntouched.Why: Extra steps are risk for no requirement, and additive changes can always be undone.
- 3Give each step a check
Migration: run on a staging copy, confirm the notes are intact. Feature: the spec's criteria as tests, plus cancelling a staging booking with each of the six reasons.
Why: Each step proves itself before the next depends on it.
- 4Cut into small PRs, then compare
PR 1: the migration (2 files). PR 2: API, guest picker, support view (6 files). Dropping the old field is a later decision. PR 2 planned 6 files and changed 6.
markdownPR 1: add nullable cancellation_reason (keep cancel_note) PR 2: API + guest picker + support view (tests = spec criteria) Later, separately: drop cancel_note when nothing reads itWhy: Each review takes minutes; each step can be reverted alone.
In real life
3 minDesign docs first (Google engineers have described it publicly)
- Goals, non-goals, approach
- Alternatives considered
- Reviewed before code exists
Catch wrong direction early.
Trunk-based, tiny steps
- Many small merges a day
- Unfinished work behind feature flags
- Fast tests on every change
Keep every step small and safe.
What goes wrong
3 minA long, fluent plan can still drop a column.
Run the five checks: scope, data, can't-undo, verify, size.
Tests use a tiny database; real tables lock and take minutes.
Ask: how long on the real table, does it lock, when does it run, how is it undone?
Plans drift; extra files slip in.
Compare the changed-files list after each step.
Trade-offs
3 min| Approach | Fits when | You pay |
|---|---|---|
| Edit directly | Single-file, visible, reversible edits | Decisions found only in the diff |
| Plan, then one change | Medium changes, no data migration | One big diff; all-or-nothing revert |
| Plan, then small steps | Schema or data changes, several parts, other teams | More PRs and reviews |
- Maya · Product managerOne PR, please. I review once, it ships Friday.
- Omar · On-call SREThree PRs. Schema first, alone. No more 23-file changes at 11:00.
- Maya · Product managerBut the first PR does nothing a guest can see!
Your job as tech lead
4 minClaude Code can write the code for this. You still own the decisions, and you have to know what good looks like to accept or reject its work.
- When a plan is required before any edit: several files, any schema or data change, payments, permissions, another team's code.
- How data changes happen: additive first, removals later as a separate decision.
- How the work splits into small PRs, and what check proves each one before the next starts.
Read docs/specs/cancellation-reason.md and the booking code in packages/bookings and apps/support. Don't edit anything yet. Propose a step-by-step plan: files each step changes, every database change (adds, rewrites or removes data), anything a git revert can't undo, and how you'll verify each step. Keep cancel_note untouched. No renames the spec doesn't need. If you later need to deviate, stop and tell me why.
- Read the data steps first: does anything rewrite, drop or delete?
- Every step has its own check, not just "run tests" at the end.
- After each step, the changed files match what the plan said.
- A migration that drops or converts a column in the same step that adds the new one.
- Renames or library swaps riding along with the feature.
- A step touched far more files than planned, with no explanation.
Check yourself
2 minNext: the plan was right and the PR is small. Now you have to read the code itself, and you've never written a line of it.
Mark it complete to update your skill map.
Go deeper (optional)You don't need this to understand the lesson. Open it when a project needs the details: Technical deep dive, Analogy, Why it matters, Check your understanding, Practice ladder, Explain it yourself.
Technical deep dive
Run the plan review for cancellation reasons
Throw away the 23-file PR, get a plan in plan mode, review it with the five checks, and turn it into small steps you can verify.
- 1Ask for the plan, not the code
"Read docs/specs/cancellation-reason.md and the booking code. Propose a step-by-step plan: files, database changes, anything irreversible, how you'll verify each step. Don't edit anything."
Why: The decisions show up as a 7-line list instead of 1,400 lines of diff.
- 2Check scope against the spec
Step 6 renames
cancelBookingin 14 files. The spec doesn't need it. Out.Why: Every extra step is extra review and extra risk, for no requirement.
- 3Find what can't be undone
Step 1 converts and drops
cancel_note. Change it to: add a nullablecancellation_reason, keepcancel_noteuntouched.Why: A code revert can't restore deleted data. Additive changes can always be undone.
- 4Give each step a check
Migration: run it on a staging copy and confirm the notes are intact. Feature: the spec's criteria as tests, plus cancelling a staging booking with each of the six reasons.
Why: "Run tests" at the end says nothing about real data or the real screen.
- 5Cut into small steps
PR 1: the migration (2 files). PR 2: API, guest picker, support tool shows the reason next to the notes (6 files). Dropping the old field is a future decision with its own plan.
markdownPR 1: add nullable cancellation_reason (keep cancel_note) PR 2: API + guest picker + support view (tests = spec criteria) Later, separately: drop cancel_note when nothing reads itWhy: Each review takes minutes; each step can be reverted alone.
- 6Compare result with plan
After each PR, ask for the changed-files list. PR 2 planned 6 files and changed 6. Lina: "That's the habit."
Why: Plans drift. A quick comparison catches extra changes before they merge.
| Check | Question | Found in this plan |
|---|---|---|
| Scope | Steps the spec didn't ask for? | Rename in 14 files |
| Data | Schema change, rewrite, delete? | Convert and drop cancel_note |
| Can't undo | What won't a revert restore? | 180,000 notes |
| Verify | How is each step checked? | Only "run tests" |
| Size | Can it ship in pieces? | Yes: 2 PRs |
Analogy
- Renovating a hotel floorWalkthrough before work startsDirecting an agentPlan mode
- Renovating a hotel floor"That wall carries the sprinklers"Directing an agentSpotting a can't-undo step
- Renovating a hotel floor"Do one room first"Directing an agentSmall steps
- Renovating a hotel floorChecking plumbing before closing wallsDirecting an agentVerify each step
Where the analogy breaks: a contractor sticks to the walkthrough. An agent may quietly change its plan as it works, so you compare the result with the plan you approved.
Why it matters
No plan
- You see choices in a huge change
- Danger hides among harmless lines
- Hours of work push you to approve
Hard to review, hard to undo.
Plan first
- You see choices as a short list
- Fixing one is a sentence
- Work splits into small steps
Minutes to review, easy to undo.
And one thing to remember forever: undoing code does not undo data. If a change deleted a column full of notes, going back to the old code gives you an empty column, not the notes.
Check your understanding
Select all that apply.
Practice ladder
Trace a plan's consequences
Scenario Warm-upThe agent's plan for "let hotels set a minimum stay per date":
- Migration: add rates.min_nights (default 1) and remove rates.min_stay_weekend (old weekend-only rule, used by 900 hotels).
- Update the rate calendar UI and the availability search.
- Run tests.
Trace what happens to a hotel that today requires 2 nights on weekends, the moment step 1 runs.
Complete the plan review
Design PracticeFill in the missing rows of your review of the minimum-stay plan.
| Check | Finding |
|--------------|------------------------------------------------------|
| Scope | Steps match the spec |
| Data | ___ (1) |
| Can't undo | ___ (2) |
| Verify | Only "run tests" |
| Size | ___ (3) |Review a plan for invoice PDFs
Design PracticeSpec: hotels can download a monthly PDF of their StayHub commission invoices. The agent's plan:
- Add a PDF library and a new invoices/pdf endpoint.
- Regenerate and email all 36 months of past invoices to every hotel so they have PDFs.
- Replace the existing CSV export with the PDF.
- Run tests.
Review it with the five checks and write the plan you would approve.
Plan mode for everything?
Decision StretchKarim proposes a team rule: "Plan mode is mandatory for every Claude Code task, even one-line fixes." Write your counter-proposal or agreement as "We chose X over Y because…, accepting the risk of…", with a clear trigger for when a plan is required.
Explain it yourself
Maya asks: "Why read the plan if I'm going to review the pull request anyway?" Explain.