TL;DR:

  • PRs over 400 lines get reviewed worse — not because reviewers are lazy, but because cognitive load makes thorough review genuinely impossible at scale
  • The most valuable part of a code review is “does this solve the right problem,” not “is the code formatted correctly”
  • Psychological safety determines whether review feedback improves code or just creates defensiveness

Code review best practices get discussed constantly and followed inconsistently. Most developers have been through hundreds of code reviews and could tell you what made the good ones good — clear PR descriptions, focused scope, constructive comments. The harder part is doing that consistently when you’re behind on a deadline and the PR has 800 lines of changes.

What Makes a Good Pull Request

The author’s job is to make the reviewer’s job easy. A PR that’s hard to review gets a superficial review. It’s that simple.

Keep PRs small. The research here is consistent: PRs over 400 lines receive significantly fewer meaningful review comments. Not because reviewers don’t care, but because the human brain’s working memory can hold roughly 200–400 lines of context. Beyond that, reviewers start pattern-matching rather than reasoning.

If a feature requires 2,000 lines of changes, it should be four or five PRs: data model first, then API layer, then frontend, with each PR independently deployable or at least independently reviewable.

Write a real description. A PR description should answer: what problem does this solve, how does it solve it, and what should the reviewer focus on? Link to the issue or ticket. Include screenshots for UI changes. If there are areas of uncertainty or places where you made a judgement call, call them out explicitly.

Self-review before requesting review. Open your own diff, read it as if you’re reviewing someone else’s code, and fix what you catch. This is the highest-ROI code review you’ll get — you can act on it immediately and it costs the reviewer nothing.

A minimal PR template that works:

## What

Brief description of what changed.

## Why

Link to issue or explanation of the problem being solved.

## How

Key implementation choices, especially non-obvious ones.

## Testing

How this was tested. Manual steps if automated tests don't cover it.

## Review focus

Specific areas where reviewer attention is most valuable.

How to Review Effectively

Distinguish between requirements and preferences. Blocking a merge because you’d have written the function differently is imposing preference, not enforcing standards. Reserve blocking comments for: correctness issues, security concerns, missing tests, or violations of established team conventions.

Use comment prefixes consistently. A simple convention reduces ambiguity enormously:

  • nit: Minor style suggestion, not a blocker
  • question: Genuine question, not a critique
  • blocker: This needs to change before merge
  • suggestion: Idea worth considering, not required

Ask questions before making assertions. “Why did you choose X instead of Y?” surfaces context you might be missing. “This should be Y” asserts without understanding. The first leads to a conversation; the second leads to defensiveness.

Approve when the code is good enough, not perfect. Good code that ships is worth more than perfect code stuck in review. If your remaining comments are nits and preferences after a thorough review, approve and let the author decide what to address.

Async vs Synchronous Review

Most teams default to async review — reviewer leaves comments, author responds, repeat. This is correct for the majority of reviews. It scales, it creates a record of decisions, and it doesn’t require scheduling.

Synchronous review (pairing over a PR, or a quick call) is better when the PR needs significant redesign and written feedback will kick off a long async thread, when a junior developer needs guidance rather than just corrections, or when there’s a technical disagreement that’ll take more than two async rounds to resolve.

Here’s a useful heuristic: if you’re writing a comment that requires more than three sentences to explain, consider a five-minute call instead.

Tools That Help

GitHub PR templates (.github/pull_request_template.md) prompt authors to fill in the same information every time. Removing the blank-page problem increases PR quality with zero ongoing effort.

CodeRabbit and similar AI review tools provide an automated first pass — catching obvious issues, summarising changes, and flagging potential problems before a human reviewer ever reads the PR. Used well, this means human reviewers can focus on architecture and intent rather than typos and missing null checks. Several UK dev teams have found this cuts review turnaround significantly.

Reviewpad adds workflow rules to PR review: auto-assign reviewers based on changed files, enforce minimum approvals, label PRs by size, and block merges when automated checks fail.

Measuring Review Quality

The metric most teams track is time-to-merge. It’s useful but incomplete. A PR that merges in two hours because the reviewer clicked approve without reading is not a good review.

Better signals: defect escape rate (bugs that make it to production despite review), review comment resolution rate (comments addressed vs. dismissed), and re-review rate (PRs that come back for a second review due to significant changes after initial feedback).

None of these are worth building dashboards around at small team sizes. They’re useful diagnostics when you notice a pattern — bugs getting through, reviews being perfunctory — and want to understand why.

The Bottom Line

Good code review comes down to three things: PRs small enough to review thoroughly, comments that distinguish requirements from preferences, and a team culture where feedback is specific to code rather than attached to the person who wrote it. The tools help at the margin. The behaviours are what determine whether review actually improves code or just slows down shipping.