I've been on both sides of code reviews that felt like interrogations and code reviews that felt like pair programming after the fact. The difference isn't the code. It's the posture and the craft of the feedback.
The Default Failure Mode
Most code review feedback is either too vague ("this could be cleaner") or too blunt ("this is wrong"). Both fail the author. Vague feedback gives them nothing to act on. Blunt feedback triggers defensiveness, which makes them less likely to internalize the actual point.
The underlying issue: reviewers treat code review as quality control — a filter for bad code. The better frame is that code review is knowledge transfer and collective ownership-building. The diff is a conversation prompt.
Distinguish Blocking from Non-Blocking
Not every comment is a merge blocker. Labeling matters:
This taxonomy removes the cognitive burden of decoding the emotional weight of a comment. Authors know what to prioritize.
Ask Questions Instead of Making Statements
"This will have an N+1 query problem" is a statement that can feel like an accusation.
"What happens to query performance as the list grows? I'm wondering if we'd hit N+1 here" invites collaborative thinking.
Same information. The second framing makes it more likely the author engages thoughtfully rather than defensively.
Be Specific About Why
"This should use a Map instead of an Object" is incomplete. "This should use a Map instead of an Object because we need to guarantee insertion order and iterate over it in the same pass" gives the author the reasoning that will stick with them on the next PR.
The goal isn't to fix this PR's code. It's to improve the author's intuition permanently.
Acknowledge What's Good
Most reviewers skip this. Pointing out what worked well costs nothing and builds the relationship. "Nice refactor of the validation logic — much cleaner than what was there" makes the critical comments land differently. It signals that the reviewer read the whole thing and has a balanced view.
The Merge Bar
Perfection is the enemy of good code review. Ask: is this code better than what existed, and does it do what it claims to do without introducing meaningful problems? If yes, merge it. Refinements can iterate. Holding PRs open for theoretical improvements creates bottlenecks and resentment.