Code review does two jobs at once: it catches problems before they ship, and it spreads understanding of the codebase across the team. The second job is the one people forget, and it is arguably the more valuable. A team where only one person understands the payment code has a bus problem, and review is how we fix it without a meeting.
Review the change, not the person
The fastest way to poison reviews is to make them feel like an exam. We phrase comments about the code, ask questions instead of issuing verdicts, and we are explicit about what is a blocker versus a preference. "This will null-pointer if the list is empty" is a blocker. "I would name this differently" is a preference, and we label it so, so the author does not have to guess which comments they must address.
- Separate blockers from preferences explicitly - do not make the author guess
- Ask "what happens if this is null?" rather than declaring the code wrong
- Approve with minor comments instead of holding the PR hostage over nits
- Praise the good parts out loud - review is not only for finding faults
Small PRs get real reviews
Nobody reviews a thousand-line pull request properly. They skim it, rubber-stamp it, and the bug ships anyway. A change small enough to read in ten minutes gets actual attention, and the feedback comes back the same day instead of sitting for two. We push hard for small PRs, even when it means splitting a feature across several, because a fast, honest review beats a slow, theoretical one every time.
A rubber-stamped thousand-line PR is not a review, it is a signature on something nobody read.
The author owns the response
Review is a conversation, not a one-way verdict. The author is free to disagree, explain, and push back - sometimes the reviewer is missing context. What we ask is that every comment gets a response, even if it is "good catch, fixed" or "I left it because of X." Comments that vanish into silence are how trust erodes, and trust is the thing that makes the whole practice work.