Why Do Code Review and What Does It Actually Find? From Bug Hunting to Knowledge Sharing
The main output of code review is not bugs but code that stays understandable and knowledge that spreads through the team: only 14 percent of 570 review comments studied at Microsoft were about defects, and the largest group was code improvements. The post covers the Microsoft and Google studies, the four goals of review, alternatives such as pair programming and Ship/Show/Ask, and the Bookstore team's review agreement kept in the repository.
Version note: This post is conceptual; the research findings come from Bacchelli and Bird's ICSE 2013 paper, Sadowski et al.'s ICSE-SEIP 2018 paper and Mäntylä and Lassenius's 2009 study, and the review principles from Google Engineering Practices as of November 2026.
Guess First
The team behind Bookstore, the online bookstore used as the shared example across this site's series, is in a sprint retrospective. Selin, the Product Owner, asks a question: "Pull requests wait a day and a half on average. What does that wait buy us? How many of the bugs that reached production did we catch in review?" Emre and Ayşe look at each other. Both have the same answer in mind, "we catch bugs", but neither has a number.
A guess for you. In a study at Microsoft, 570 review comments, sampled at random from real reviews, were read one by one and sorted by type. What share of them pointed at a defect, something that would make the program behave wrongly? Sixty percent, forty percent, less? Second question: when the same study asked developers why they do code review, what was the most common answer?
What Does Research Say About Review?
The review most teams do today is different from the code inspections of the 1970s, where people went through code line by line in a meeting room: it is tool-based, asynchronous and lightweight. The literature calls it modern code review, and the two most cited studies on it come from Microsoft and Google.
In their ICSE 2013 paper, Alberto Bacchelli and Christian Bird observed 17 developers at Microsoft while they reviewed, surveyed 165 managers and 873 developers, and classified 570 comments from 200 review discussions. Here is the answer to the guess: 44 percent of developers marked "finding defects" as the number one reason for review, yet only 78 comments, about 14 percent, were about defects. That put defects fourth out of nine categories. The largest group, at 29 percent, was code improvements: using a better practice, removing unnecessary code, improving readability. Most of the defect comments were not deep design problems either, but small logic errors such as a missed corner case or a wrong condition.
The second important finding of the same study is about understanding. 91 percent of developers said reviewing files they do not know takes longer, and 82 percent said a reviewer who knows the changed files gives different feedback; judging by their examples, that feedback is deeper and about algorithms and design rather than style. In other words, what determines review quality most is how well the reviewer understands the code. The researchers also list the unexpected benefits of review: knowledge transfer, the team staying aware of what changes, and alternative solutions to the same problem being discussed.
Mika Mäntylä and Casper Lassenius reached a similar conclusion in their 2009 study in IEEE Transactions on Software Engineering: roughly three quarters of the defects found in reviews did not affect the software's visible behaviour. They were evolvability issues, problems that make the code harder to understand and change.
On the Google side, Caitlin Sadowski and her co-authors studied 12 interviews, a survey of 44 people and the logs of about 9 million reviewed changes in 2018. The engineer who brought review to the company early on explains that the main goal was to force developers to write code others could understand and to make sure more than one person knew each piece of code; finding bugs was a welcome side effect. The numbers describe a light process: the median change is 24 lines, more than 35 percent of changes touch a single file, more than three quarters have a single reviewer, the first feedback on small changes arrives in under an hour at the median, and the whole process takes under four hours at the median. Changes from developers who joined in the past year get more than twice as many comments as those from experienced colleagues, and the number drops with tenure. The paper reads this as evidence of the educational effect of review.
None of these studies says "review does not find bugs". What they say is that most of the value review produces comes not from hunting bugs but from keeping code understandable and spreading knowledge through the team. Trying to answer Selin with "how many bugs we caught" means judging review by the wrong measure.
The Real Goals of Review
Turning the research into a team decision gives four goals.
First, improving code health over time. Every change leaves the code base a little better or a little worse. Review is where small steps in the wrong direction stop piling up. Google's Engineering Practices states the bar clearly: reviewers should "favor approving a CL once it is in a state where it definitely improves the overall code health of the system" (Google Engineering Practices, "The Standard of Code Review"). Read CL, Google's term for a change list, as pull request. The bar is not perfection but being better than the current state. A reviewer who expects the code they would have written breaks that bar.
Second, shared ownership. If only Emre knows how the cart is priced, every cart bug waits while Emre is on holiday. Review guarantees that at least two people read every change. The bus factor, the number of people who could leave before the project stalls, goes up with review.
Third, learning. Review is a school that works both ways: the junior learns the code base's rules from the senior's comments, and the senior learns what is unclear from the junior's questions. A "why is this like this?" question pays off when its answer goes back into the code as a comment or a better name.
Fourth, consistency. Names, error handling and layer boundaries staying the same across the team. The mechanical part of this (indentation, naming format) is a job for tools; we covered it in detail in the Coding Conventions and Team Standards series, in "What Are Coding Conventions and Why Leave Them to Tools, Not People? Sources, Levels and Team Decisions". What is left for people is about meaning: does this name say the right thing, is this class in the right module?
What Review Is Not
Review is not the only gate of quality assurance. One complaint from Bacchelli and Bird's interviews will sound familiar: a reviewer who does not know the code looks at what is easy to find, formatting mistakes and obvious problems. Expecting a person to run every edge case in their head across a 400-line diff is not realistic. Behaviour is checked first by tests, rule violations by analyzers, known vulnerability patterns by scanners. Review comes on top of these and looks at what they cannot see: intent, design, the meaning of names, behaviour that is not tested. Which test protects what at which level is covered in the Test Strategy series, the quality gates in CI in the CI/CD Fundamentals series in "Testing in the Pipeline: Fast Feedback, Quality Gates and Flaky Tests"; analyzers and quality gates are the subject of the Static Analysis series.
Review is not an approval ritual either. Writing "looks good to me", LGTM for short, and moving on, approving without opening the diff, keeps the review step on paper and empties it. Google's speed guide strikes the balance well: responding quickly matters, but a quick response does not mean a lower standard; an approval should mean the code really meets the standards.
Finally, review is not a display of seniority. A rule like "nothing merges without a senior's approval" is well meant but has two side effects: seniors become the bottleneck and juniors lose the practice of reading other people's code. A junior reviewing a senior's code is the fastest path to the educational effect the papers describe.
Alternatives and Complements to Review
Review before merge through a pull request is not the only form of review. Depending on the team's context, the following can be used alongside it or instead of it:
| Form | When the review happens | Where it helps most | Cost |
|---|---|---|---|
| Pull request review before merge | After the code is written, before merge | Teams working asynchronously or across time zones | Waiting time, context switching |
| Pair programming | While the code is written, continuously | Hard design decisions, onboarding a newcomer | Two people on one task at the same time |
| Mob programming | While the code is written, whole team | Critical changes that affect everyone | All of the team's time |
| Ship / Show / Ask | Depends on the change: never, after merge or before | Teams with strong CI and trust | Depends on team discipline |
| Review after merge | After the change is in main | Teams doing trunk-based development with feature flags | A separate fix if a problem is found |
In pair programming a second pair of eyes is already there while the code is written, so the pull request review of a paired change is often a short check. Some teams do not ask for a second approval on code written in a pair.
Ship / Show / Ask is a model Rouan Wilsenach published on martinfowler.com in 2021. You put every change into one of three groups. Ship: it goes straight to main without waiting for review, like a small fix made with a known approach. Show: you open a pull request but merge it without waiting for approval; the team is informed and comments come after the merge; it suits showing a new approach or an interesting refactoring. Ask: you open a pull request and do not merge until feedback arrives; it is for when you are unsure about your approach. The model assumes main is releasable at all times and a strong chain of automated checks. Wilsenach often sees a mandatory approval on every change as a sign of a trust problem; he also notes that regulated industries may require every change to be approved.
In teams doing trunk-based development (covered in the Git & GitHub series in "Teamwork with Git: Branching Strategies, Rulesets and Conventional Commits"), review sometimes happens after the merge. Unfinished work goes into main behind a feature flag, a teammate reads the commit later, and if there is a problem a small fix follows. The precondition of this model is that everything entering main passes the automated tests and that exposing it to users is controlled by the flag.
Bookstore is an application that handles payments and orders; the team is two developers, and the people who know each other's code best are those two. So we stay with Ask for all code going into main, but instead of "two days of waiting for everything" we put the following agreement in place.
The Bookstore Team's Review Agreement
The agreement lives in the repository, in docs/code-review.md. A wiki page is forgotten; a file next to the code that changes through pull requests stays current:
# Code review at Bookstore
We review to share ownership of the code, spread knowledge and keep the code base easy to change.
Finding bugs is welcome but it is not the main goal: tests and CI are the first line of defence.
## Who reviews
- Every pull request into main needs one approval from someone other than the author.
- Changes to migrations, authorization and payments also need an owner from CODEOWNERS.
- Juniors review too, including seniors' code. Their approval counts like anyone else's.
## How fast
- First response within one working day: a review, a question, or a time when you will look.
- Authors keep pull requests small: about 400 changed lines at most, generated files excluded.
Bigger changes are split or agreed with the reviewer before the work starts.
## What we leave to tools
- Formatting, naming style and analyzer rules: .editorconfig, dotnet format, ESLint, Prettier.
- Build, tests and vulnerable packages: CI is green before a review is requested.
## What reviewers look at
- Does the change do what the description says? Edge cases, error paths, tests that check behaviour.
- Design: does the code belong here, will the next change be easy?
- Security and data: authorization, input validation, personal data in logs.
## Approving
- The bar is "better than before", not "as I would have written it".
- Small leftovers can be approved with comments the author fixes before merging.
The file's first paragraph is this post in short: the goal of review is shared knowledge and code that is open to change; catching bugs is first the job of tests and CI. That sentence is there to turn the question "why didn't the reviewer see it?" after a production bug into "which test or check should have caught it?".
The number of approvals is one. A two-approval rule is impossible in a team of two; in growing teams it spreads responsibility thin, and we come back to that in the fifth post. For risky areas (migrations, authorization, payments) the area owner's approval is required as well; on GitHub that is CODEOWNERS, also the subject of the fifth post.
The response time is one working day. The number comes from Google's speed guide: it recommends answering without breaking focused work but by the next morning at the latest, and says the answer does not have to be a full review. "I'll look at it at 3 pm" is an answer too. What matters is that the person who opened the pull request is not left waiting in uncertainty.
The 400-line limit is based on SmartBear's review study at Cisco: there, reviewing more than 200 to 400 lines at once clearly lowered the share of defects found. Google's guide sets no hard limit; it finds about 100 lines usually reasonable and 1000 lines usually too large. We wrote the limit as "generated files excluded", because the designer file of a single EF Core migration can exceed 1000 lines on its own. We will see this on a real pull request in the second post.
"Approve with comments" in the last section is a practice from Google's guide too: a reviewer who is confident the author will fix the small remaining comments does not hold back the approval. When the two developers work at different hours, this one rule can remove a day of waiting.
In Production
Once the agreement is in place, you need to see it working. Three signals are worth tracking. Time to first review tells you how well the one-working-day goal holds. Pull request size: if the pull requests over the limit always come from the same person or the same kind of work, the problem is not discipline but how the work is sliced. Number of review rounds: pull requests that take three or four rounds usually show that the design was not discussed before the pull request was opened. We will see how to get these from GitHub data, and which numbers must not become targets, in the fifth post.
If part of the team generates code with AI coding agents, the review load grows, because the amount of code written grows while the number of people reading it stays the same. We covered the risks specific to AI-written code and where AI reviewers fit in the AI-Assisted Development series, in "Reviewing and Verifying AI-Written Code: Typical Failure Modes, a Checklist and AI Reviewers"; in this series we only mark their place.
In regulated areas (payments, health, finance) "every change was approved by someone else" can be an audit requirement. Then Ship and Show are off the table, but keeping pull requests small and responding quickly still lowers the cost of waiting.
Common Pitfalls
Making review the only quality gate. If the first question after a production bug is "who approved this?", the team soon starts reviewing defensively: dozens of comments on every pull request, every approval hours late. A bug is a gap in a process; the fix is usually a missing test or a missing automated check.
Turning review into a sign of seniority. Giving approval rights only to seniors ties the bottleneck to a single person and cuts the juniors' reading practice. A junior's approval should count the same; they can ask about the parts they are unsure of.
Measuring value by bug count. "How many bugs did review find this quarter?" pushes reviewers towards what is easy to find. According to the research, most of the value comes from readability and knowledge transfer; neither shows up on a counter.
Commenting on formatting. If you see a human comment about indentation or whitespace, what is missing is a formatter. A reviewer's attention is limited and belongs to meaning.
Saving the big change for the end. Someone who brings three weeks of work in a single pull request cannot expect a quick review. The design is shared before the code is written, through a short conversation or a draft pull request; a design objection raised in review is the most expensive objection.
A Small Experiment
★☆☆ Read the review comments on your team's last 20 merged pull requests and put each one into one of three groups: defect, code improvement/readability, question or information. Do the ratios look like Bacchelli and Bird's finding?
★★☆ Draft a one-page review agreement for your own team, similar to Bookstore's. One sentence each for the number of approvals, response time, size limit and the rules left to tools is enough. Open the draft as a pull request and put it up for your team's review.
★★★ Sort your pull requests from the last month into Ship, Show and Ask. Which of them really needed to wait for approval? For the ones that could have been Ship or Show, which automated checks keep main safe and which are missing?
We talked about why review is done and the agreement it runs on in a team. The most demanding item in that agreement is keeping pull requests small. In the next post the ball goes to the pull request author: splitting a large coupon feature into a refactoring and a behaviour change, stacked pull requests, a good description and the self-review done before asking for a review.