The Code Review That Actually Improves Code
Most code reviews catch bugs. The best ones improve the engineer. Here is how to make code review a tool for quality and growth, not just gatekeeping.
Written by Yashveer Singh, founder of Yashveer Labs.
# The Code Review That Actually Improves Code
Code review is the practice of having engineers read each other's code before it merges. Done well, it catches bugs, improves code quality, spreads knowledge across the team, and develops junior engineers faster than any other single practice. Done badly, it is a rubber stamp at best and a political battleground at worst. The difference between these outcomes is not the tool. It is the culture and the specific behaviors of the reviewers.
What you need to know
- The goal of code review is to improve the code, not to demonstrate the reviewer's superiority or to perform thoroughness
- Nit comments (minor style preferences) should be labeled as nits and never block merging
- The reviewer's job is to ensure correctness and quality, not to rewrite the code in their preferred style
- Async code review is more scalable than synchronous review but requires clearer written communication
- The best code reviews for junior engineers include explanations of the why, not just what to change
The core argument
Code review culture is one of the highest-leverage engineering practices for two reasons: it directly affects code quality, and it is one of the primary mechanisms for knowledge transfer and engineering development. A team with good code review produces fewer bugs, shares context more effectively, and develops junior engineers faster than a team with weak review culture. The investment in making code review work correctly pays off across every dimension of engineering output.
The most common failure mode is the review as performance. Reviewers who write long comments to demonstrate their expertise, who identify every possible issue regardless of severity, who block PRs over style preferences, and who treat code review as an evaluation of the author rather than a collaborative improvement of the code. This behavior makes authors defensive, slows the development cycle, and teaches junior engineers that code review is about being criticized rather than about improving their work. The most talented engineers on the team will push back on this review culture or leave. The less experienced engineers will internalize the criticism as an assessment of their worth.
The review that actually improves code has a different character. It asks questions before making assertions: "What was the reasoning behind this approach?" rather than "This is wrong." It distinguishes clearly between correctness issues (must fix before merge), design questions (should discuss, may or may not change), and nits (take it or leave it, never blocking). It explains the why behind significant feedback: "I would use an index here because this query runs on every page load and will be slow at table sizes above 10,000 rows" is more useful than "add an index." Explanations build mental models that carry forward to the author's future work. The comment without explanation changes the code. The comment with explanation changes the engineer.
Common mistakes
- Treating all feedback with equal weight. Not all code review comments deserve equal consideration. A correctness bug is not the same as a style preference. Label your comments: "Bug," "Design question," "Nit." This makes the review easier to parse and prevents nits from blocking merges.
- Reviewing code without running it. Code review in a text editor catches logic errors and style issues. It does not catch integration errors, performance problems, or behavior in edge cases. The strongest reviews combine static analysis with actually running the code and the tests.
- Writing long essays in comments. If a review comment requires a paragraph of explanation, consider whether the conversation should happen synchronously instead. Long comment threads in code review slow down the development cycle and often produce less clarity than a 10-minute conversation.
- Reviewing everything with the same depth. A one-line change in a low-risk utility function does not require the same review depth as a change to the payment processing logic. Calibrate review depth to the risk of the change. Deep reviews for high-risk code; lighter reviews for low-risk changes.
- Not acknowledging good code. Code review is often purely critical. Reviewers who also note what is done well, a clever solution, a clean abstraction, a well-named function, create a review culture that is safer for junior engineers to participate in and that reinforces good habits as explicitly as it corrects bad ones.
Where to start
Step 1: Establish a shared understanding of what code review is for. Write a one-page document with your team that defines: what kinds of issues block merging, what kinds are suggestions, and what the expected response time for reviews is. Agreement on the purpose and the process reduces friction significantly.
Step 2: Adopt a labeling convention for comments. At minimum: "Bug" (must fix), "Question" (author should answer), "Suggestion" (consider this), "Nit" (take it or leave it). This convention makes the review output actionable and removes the guessing game about what the reviewer actually expects.
Step 3: Conduct a review retrospective quarterly. Ask the team: what makes reviews take too long? What feedback formats are most useful? Are there recurring patterns that should become automated lint rules instead of manual review comments? Improving the review process itself is the highest-leverage investment in code review quality.
Related reading
Frequently asked
Why this work lands with me
I am Yashveer Singh. Founder of Yashveer Labs. I take this kind of project because I have done enough of them to know what kills them. The version of me that writes a post like this is the same one who builds the system afterward. There is no handoff to a junior, no agency middleman, no surprise scope. That is the bet I am making on my own brand.
Posts that line up with this one.
- Tech Debt and Refactoring
Test Coverage: A Metric With a Story
Test coverage tells you what percentage of your code runs during tests. It does not tell you whether those tests are meaningful. Here is how to use it correctly.
- Tech Debt and Refactoring
The Critical Path Test Suite: A Founder's Definition
Not every feature needs tests. The critical path does. Here is what the critical path test suite is and how to build one that actually protects your product.
- Tech Debt and Refactoring
Tech Debt in Startups: How It Kills Products and How to Manage It
Tech debt does not announce itself. It compounds quietly until velocity drops to zero. Here is how to manage it before it manages you.
- Tech Debt and Refactoring
Snapshots, Property Tests, and the Modern Test Toolbox
Unit tests and integration tests are not the whole story. Here is what else belongs in a serious test suite.