Why review speed matters
Code review is a core part of my work as a staff engineer at GitHub. Over eight years I’ve reviewed more than 7,000 pull requests, and the reason is simple: another set of eyes catches problems. When a teammate marks a pull request ready for review, it has already passed CI and met their own bar for “done.” That means it’s likely closer to shippable than whatever branch I’m currently on, so I’d rather help land their change than keep churning on my own work.
The faster I give feedback — “this can be nil and cause an error,” “this looks like an n+1 query,” “it would be great to have a method signature on this” — the sooner bugs get squashed and features ship. Reviewing early also keeps me current with changes to code I’m responsible for.
How to find pull requests that need a reviewer
I live in my GitHub notifications inbox; it’s one of the few tabs I keep pinned. Any spare moment — waiting on CI, between tasks, starting the day — I check it. That’s where I find most pull requests to review. Teams at GitHub also announce ready-for-review work in a dedicated Slack channel. The GitHub Slack integration can subscribe a channel to relevant pull requests:
- Use a team-specific label, then a subscribe command like
/github subscribe your/repo pulls +label:"your-team-label"to filter notifications. - Search for outstanding work with a query like
is:open archived:false is:pr org:github -is:draft team-review-requested:github/relevant-codeowner-team. I usually omit thereview:requiredqualifier because I want to see pull requests even if a teammate has already reviewed them.
Keep review notifications under control
Broad review requests create a diffusion of responsibility: when everyone is pinged, nobody feels accountable. That leaves pull requests languishing or merging without proper scrutiny. Keeping the set of code owner teams you’re on tightly scoped helps ensure that what lands in your inbox actually requires your attention.
Large catch-all code owner teams are fine as a fallback, but not as the default request target. Keep the CODEOWNERS file organized with well-defined boundaries. Another approach is scheduling a first responders team: use the PagerDuty API to determine the on-call person for the day, then use the Octokit library to add and remove them from the review team automatically. This lets the rest of the team focus on their own code while first responders handle incoming review requests for service areas.
Standardize the process across teams
Repository configuration can enforce process: a CODEOWNERS file and branch protection rules handle some of the work. But standards like what’s worth commenting on have to be maintained by people. Document how reviews work within your team so contributors know the expected turnaround time, how to request a review, and what automation is in place.
Different teams have different successful patterns. Some use a project board to track incoming requests — I’ve seen that work well for shared APIs modified by outside teams. Others rely on GitHub notifications alone, which works when code ownership is tightly scoped. If outside teams depend on your review, automation can set expectations — for example, a bot that comments on every pull request asking for your team’s review, stating when the author can expect a response.
What separates good review comments from noise
A good review pushes the code toward a better state and adds clarity. As the reviewer, make explicit which comments are personal preference and which block approval. Provide examples of the approach you suggest; code from the same repository is ideal because it encourages consistency.
Vague feedback creates a poor experience for the author. A blanket approval with no comments leaves the author wondering whether the review was careful. Even restating your understanding of the author’s intention can surface a mismatch in assumptions. When you suggest refactoring existing unchanged code or handling an additional case, be clear whether those must happen before merge or can land in a follow-up pull request. When a small diff is safer, say so explicitly.
Model review comments
A strong comment is specific, references real code or issues, and suggests a resolution:
“I see your new method matches the existing style in this file, taking [X] parameters. Having that many parameters hurts readability and implies the function is doing too much. What do you think about refactoring this method and the existing ones in a later pull request to reduce how many parameters they take?”
This works because it cites specifics, proposes next steps, and explains the rationale.
Compare that with comments like “I don’t like this,” “This won’t work,” or “I think this fixes a bug.” Each signals a problem without telling the author what it is or what to do about it.
- Instead of “I don’t like this”: “This line is doing a lot, could we simplify it to improve readability?” or “I think this will have performance problems because of an n+1 query.”
- Instead of “This won’t work”: “This won’t work because [X], see this relevant issue: [issue link]” or “This was tried before in [pull request link] and it didn’t work because of [X].”
- Instead of “I think this fixes a bug”: “I think this fixes [issue link]” or “This looks like the bug we ran into with [link to failing build]. Thanks for the fix!”
Review comments that pair a concern with concrete evidence, a proposed alternative, and a clear sense of urgency help the author act quickly and ship better code.
Building Positive Review Dynamics
Code review is a collaborative exercise, not a one-way inspection. The person who wrote the pull request usually has the deepest context on the change. As a reviewer, you can leverage that by asking questions rather than issuing directives. Your own background—whether that's work in a Ruby on Rails monolith, TypeScript, or a high-traffic database—can help you spot potential issues, but the author's answers often carry more weight.
Questions that challenge underlying assumptions tend to be especially valuable. For example: What is the shape of the data? Does any existing data break that shape? Does the code fail gracefully if it does? Is the implementation resource-intensive? When asking these sorts of questions, the ideal response is an automated test that proves the code handles the edge cases correctly. A close second is empirical evidence, such as a query result from a data warehouse or a Datadog graph showing why a particular scenario isn't a problem.
As an author, receiving such questions is useful too. It creates an opening to explain your reasoning with citations to issues or data, and it lets you document your thought process for other reviewers and future engineers who might be looking for context on an old decision. Questions, unlike blunt change requests, presume the author's confidence might be well-founded.
Acknowledge What Works
Reviews that contain only critique are draining. Comments that affirm what's working are just as useful: "Looks like this matches the pattern used in other classes in this module," or "Thanks for adding a test for this!" A quick note like "This is much more readable than before" costs nothing but can genuinely boost the author as they field feedback from multiple parties. It also shows that you read the code carefully and verified assumptions, not just hunted for flaws.
Keep Assumptions in Check on Both Sides
It's easy to let preconceptions about the author—their seniority, their historical area of work—skew your review. But everyone makes mistakes. Your fresh eyes on a change, questioning assumptions that may have become invisible to the author, is exactly what can catch a problem before a merge. Automated tests are a useful counter to bias: if a test verifies the behavior, you don't have to take the author's word that it works—you only need to check that the test itself is sound.
This cuts the other direction as well. Junior engineers should ask what feel like obvious questions of senior engineers; if a point isn't obvious, others will benefit from having the answer written down. By asking, they create documented context for anyone who comes later.
Approving and Merging, Pragmatically
A review approval should be treated as a serious signal—a gate that can halt progress. I aim to use that responsibility carefully. I will often share personal preferences or optional ideas, but those alone won't block a merge. If the code as it stands won't break production or make life worse for users, I approve with comments left on the record. The author decides whether to handle those before merging or to defer them to a later branch.
Think about the cost of your suggestions. Is your point worth delaying a release cycle: author sees the comment, makes the edit, reruns CI, waits for re-review, deploys, and merges? If a suggestion's absence won't actively harm someone's day, leave the schedule in the author's hands.
The 'Request changes' option halts the merge process entirely. I use it very rarely. It tends to feel heavy-handed, and I'd rather trust a teammate's approval as well as the author's judgment about respecting significant feedback. A request for changes is mostly reserved for the situation where an immediate security risk needs to stop the merge right now.
Making Each Merge Count
Review Your Own Diff First
Before you send a pull request to anyone else, do your own pass. See it from the perspective of a future reviewer. Adding a self-review comment to non-obvious code is often a good idea; it can prevent a lot of back-and-forth. A self-review can also reveal when a pull request has grown too sprawling—and then it might be best to split it into smaller, more digestible pieces. If you want automatic enforcement of small PRs, the lerebear/sizeup-action GitHub Action can label PRs by how large or complex they are.
Welcome Reviews After the Merge
Sometimes a pull request lands before others have gotten to it. That shouldn't mean opportunity lost. If the change causes problems, an early post-merge review comment leaves a useful "why did this break?" trail for future readers. When feedback arrives after merge, treat it seriously. Respond with your perspective in a comment, create follow-up branches to iterate, or open issues to prevent lost improvements.
Drafts Communicate State Clearly
Using draft pull requests indicates to reviewers whether you are actually interested in them looking at the code. As a personal rule, I keep work in draft if I'm not done yet, CI is failing, or the merge is otherwise not imminent. Likewise, I read other authors' draft status: if it's a draft, they don't want reviews yet. A branch marked 'ready for review' should basically mean it's mergeable as soon as approvals line up.
When I struggle with merge conflicts or rewrite code to address reviewer feedback, I take the pull request back to draft. That way reviewers aren't pinged with a flood of incomplete changes. When the code settles again, I flip the status, and GitHub prompts previous reviewers to take another look.
Kindness Builds Trust With Reviewers
People want feedback on their code, and the best way to get more of it is to treat feedback well. That holds even when you disagree. Replying to every comment may not be feasible, but a simple 👍 in agreement or a ❤️ as a thanks goes a long way.
To reassure reviewers that nothing was forgotten, keep them informed by commenting. If you agree with the suggestion but just don't want to balloon the current PR, say so and follow through later. When you eventually implement their idea in a new pull request, come back to the old one and drop a comment like "This addresses @so-and-so's feedback from <previous PR URL>". It gives credit to the original suggestion and provides better searchable context for others. Following through on promises of future fixes is how you build the kind of trust that makes future approvals easier.
Why It's Worth Doing Well
Review is a primary safeguard for code quality—even more so now that AI tools generate a lot of the code in review. A career's worth of incidents could have been avoided with a second pair of eyes. Investing the time to review deeply now beats a costly fix in production later. Whether that time goes into focused reviews, better automation, or mapping out clear processes, the cost is below the inevitable price of an error slipping through.



