How to review code in three focused passes
A better way to review code (without checklists)
3:47 AM on a Tuesday.
My phone buzzes. PagerDuty alert.
The system is down.
I scramble to my laptop. Check the alerts. Database connections maxed out. API timeouts everywhere. Users can’t access the service.
First priority: get it back up. We identify the offending caller and block them. System stabilizes. Crisis averted.
The post-mortem hits differently.
We built a new feature. Added fan-out to notify multiple services. Seemed fine for manual usage. We tested it. Reviewed the PR. Shipped it.
But one user scripted their access.
That single script triggered the fan-out hundreds of times per minute. Brought down the entire system.
The fix? A simple rate limit. One line of code. Would have taken 5 minutes to add.
I pulled up the original PR. Two reviewers had signed off. “LGTM.” All the tests passed. The code worked exactly as specified.
Nobody thought like an adversary.
Nobody asked: “How would someone abuse this?”
But here’s what everyone misses: The code review worked perfectly. Two experienced engineers approved it. Tests passed. The code did exactly what we built it to do.
The problem wasn’t the review process.
The problem was nobody changed their thinking between Line 1 and Line 300.
The code review problem nobody talks about
Code review has massive value in theory.
In practice? Two extremes.
Most engineers rubber-stamp with “LGTM.” They don’t see the value. They have their own work. So they skim it, see tests passing, and approve it.
The other extreme? Engineers who spend hours digging through every line. They block progress. They argue about formatting. They slow everyone down.
Microsoft studied 900+ developers and found 36% perform code reviews multiple times daily. Google analyzed 9 million reviews and found median time under 4 hours for small changes.
We’re spending massive time on this.
And still missing critical bugs.
Both problems stem from the same root cause.
Nobody taught us how to review code.
The checklist trap
I started as that junior engineer who winged it. No structure. No method. Just looked at code and hoped I’d catch something.
As I grew, I over-indexed on what I’d personally seen go wrong. Saw a race condition once? Now I check every PR for race conditions. Saw a memory leak? Now I’m the memory leak police.
Eventually I got serious. Read the book on code reviews. Studied the research. Built comprehensive checklists. Shared them with my team.
I even ran formal code review sessions. Got everyone in a room. Went through the code together. Line by line. Following the checklist.
First few sessions? People were engaged.
Then the fatigue set in. Hour-long meetings. Everyone’s calendar blocked. The checklist grew longer. The sessions felt mechanical.
People stopped seeing the value.
Research backs this up. A 2015 Microsoft study found that as PRs grow larger, the proportion of valuable comments drops. Checklists make you thorough but mechanical. You tick boxes. You lose the forest for the trees.
Eventually it fizzled out.
Back to square one.
The breakthrough
Here’s what I learned after that production incident and years of iteration:
Code review isn’t about what to check.
It’s about how you think.
Google analyzed their review process and found something surprising. Design is the FIRST thing reviewers check. Not bugs. Not syntax. Design.
Microsoft’s research showed 75% of review comments address long-term maintainability, not immediate functionality.
The best reviews aren’t about catching today’s bugs.
They’re about preventing tomorrow’s disasters.
What actually works? Personas.
Instead of one exhausting pass through a 47-item checklist, you make three focused passes. Each time, you put on a different hat. You step into a different role. You ask different questions.
The three-pass system prevents checklist fatigue because each pass requires a completely different mindset.
Pass 1: Does it work and make sense?
Mental frame: “Can I understand what this does and verify it’s correct?”
You’re the engineer on the team right now. Today. You need to understand this code.
Three questions:
Does the code do what it claims to do?
Do the pieces fit together sensibly?
Are there tests that verify the right behaviors?
Design naturally emerges while you’re reading for correctness. When you find yourself asking “why is this structured this way?” - that’s design review happening organically.
You’re not checking boxes. You’re understanding the code.
Google’s guidelines explicitly call this out: “Do the interactions of the various pieces of code make sense?” This is where you catch architectural issues before they become technical debt.
AI can help here: semantic bug detection, cross-file logic analysis, automated test generation. Let AI catch the mechanical stuff.
Pass 2: Can we live with this code?
Mental frame: “Will this code age well and operate reliably?”
Now you’re the future engineer. Six months from now. You need to modify this code or debug a production issue at 2 AM.
Will you thank or curse the original author?
Look for:
Can we modify this later without breaking things?
Will it handle errors gracefully?
Do we have logging for debugging?
Is performance reasonable for requirements?
This is your future-proofing pass.
Research shows that 75% of review value comes from catching maintainability issues, not functionality bugs. This pass is where you earn that value.
Microsoft’s study found that poorly-reviewed code directly correlates with post-release defects. Code that’s hard to maintain becomes code that breaks in production.
AI can help: documentation generation, code smell detection, error handling gap analysis, performance bottleneck identification.
Pass 3: What could go wrong?
Mental frame: “How would I attack or break this?”
This is the pass that would have caught our production incident.
You’re no longer an engineer on the team. You’re an outsider. A user with a weird name. A black hat hacker. Someone trying to use the system in unintended ways.
Stop assuming the happy path.
Look for:
Security vulnerabilities - injection, auth flaws, crypto issues
Edge cases - null handling, boundary conditions, race conditions
Resource issues - memory leaks, connection pooling, scalability concerns
Abuse scenarios - what happens if someone scripts this?
If I’d done Pass 3 on that original PR—the one that caused our 3:47 AM incident—I would have asked: “What happens if someone scripts this?”
That single question would have led to: “We need rate limiting.”
One line of code. Five minutes. Crisis prevented.
Put on your chaos monkey hat.
AI can help: vulnerability scanning, fuzzing, edge case test generation, resource leak detection.
Why three passes?
I tried everything. Two passes felt incomplete. Four passes brought back checklist fatigue.
Three is the sweet spot.
Research supports this. Studies show review effectiveness drops after 60-90 minutes. Three distinct passes let you maintain focus without burning out.
Two passes miss something. You can’t fit all three personas into two mental frames without overlap.
Four or more? You’re back to checklist fatigue. Too many context switches. Too much cognitive load.
Three passes get you 95% of the value. Easy to remember. Each pass feels distinct. No checklist required.
What changed when we adopted this
My team complained about long PR review cycles. Inconsistent quality. Nobody saw the value.
I introduced the three-pass system.
Two weeks later, Sarah caught a SQL injection vulnerability in Pass 3. She posted in our team channel: “Just did Pass 3 on the user profile endpoint. Asked myself ‘how would I attack this?’ Found we’re concatenating user input directly into queries.”
She was excited about it. Not because I forced her. Because she felt smart.
The next week, Marcus caught a memory leak in Pass 2. “Imagined debugging this at 2 AM. Realized we never close database connections in the error path.”
In our next team meeting, people started sharing what they caught. Real problems. Security issues. Scalability concerns. Edge cases that would have caused incidents.
Engineers got excited about code review again.
A few weeks later, it came up organically. Engineers asking others: “Did you do all three passes?”
The system stuck because it worked.
How to start using this
Next PR you review, try this:
Pass 1: Read it like you’re trying to understand it. Does it make sense? Does it work?
Take a break. Get coffee. Reset your brain.
Pass 2: Read it like you’ll have to debug it at 2 AM in six months. Will you hate the person who wrote this?
Take another break. Walk around. Clear your head.
Pass 3: Read it like you’re trying to break it. What happens if someone abuses this? What edge cases exist? What could go wrong?
The breaks matter.
For small changes under 200 lines, you can do all three passes in one sitting. For larger changes, spread them across different times.
SmartBear’s research shows reviews under 400 lines are most effective. Keep PRs small. Do thorough passes.
The hardest part
Learning to actually reset your mindset.
When you’re tired, when the PR is 800 lines, when you have five other reviews waiting - it’s tempting to skip passes. To blend them together. To fall back into checklist mode.
That’s when you have to be disciplined.
Take the break. Reset completely. Step into the next persona with intention.
That discipline is what makes this system work.
What you’ll notice
After using this for a few weeks:
You’ll catch bugs you would have missed. Real bugs. The kind that cause incidents.
You’ll review code faster. Not because you’re rushing. Because you’re focused. Each pass has a clear purpose.
You’ll stop arguing about formatting. Pass 1 doesn’t care about that. Pass 2 might note if it’s unreadable. Pass 3 definitely doesn’t care.
You’ll build better intuition. The personas become second nature. You’ll start thinking adversarially when writing your own code.
And when someone asks “Did you review this thoroughly?” - you’ll actually have an answer.
Yeah. I did three passes.
Pass 1: It works and makes sense.
Pass 2: We can live with this code.
Pass 3: I tried to break it and couldn’t.
Ship it.







