Back
Why I Stopped Doing Code Reviews

Why I Stopped Doing Code Reviews

/7 min read/
Engineering CultureCode Quality

I need to say something that might sound heretical coming from a CTO who has spent years preaching engineering rigor: I stopped doing traditional code reviews. And our code quality went up.

Before you close this tab, hear me out. I am not saying code reviews as a concept are worthless. I am saying the way most teams practice them — asynchronous pull request approvals with a thumbs-up emoji and a "LGTM" — is theater masquerading as quality control.

The Problem with Pull Request Culture

For years, I ran a standard code review process. Every pull request needed at least one approval before merging. We had checklists. We had guidelines. On paper, it looked rigorous.

In practice, here is what actually happened.

Reviews became bottlenecks. Engineers would open a pull request and then wait. Sometimes hours, sometimes days. The context switch alone was brutal. By the time a reviewer got to the code, the author had moved on mentally to something else entirely. The feedback loop was so slow that it actively discouraged small, incremental changes — the exact opposite of what you want.

Rubber-stamping was rampant. I audited our review data over a six-month period and found that 68% of pull requests were approved within three minutes of being assigned. Three minutes. That is not enough time to read the code, let alone understand the implications of the changes. People were approving to unblock their teammates, not to ensure quality.

Nitpicking replaced substance. The reviews that did contain feedback were overwhelmingly focused on style and formatting — variable names, bracket placement, import ordering. Things that a linter should catch. Meanwhile, architectural concerns, edge cases, and performance implications sailed through unnoticed.

Knowledge transfer was minimal. One of the supposed benefits of code reviews is spreading knowledge across the team. But skimming a diff in a web UI does not build understanding. It gives you surface-level familiarity at best.

I tracked these patterns for a year. The data was clear: our code review process was consuming significant engineering time while delivering minimal quality improvement. Something had to change.

What Replaced Code Reviews

We did not just remove code reviews and hope for the best. We replaced them with three practices that address the actual goals code reviews are supposed to serve.

1. Pair Programming Sessions

The most impactful change was making pair programming a first-class practice. Not mandatory for every task, but strongly encouraged for anything non-trivial.

Here is why pairing works where async reviews fail: the feedback happens in real time, while both engineers have full context. There is no waiting. There is no context switch. When one engineer spots a potential issue, the discussion happens immediately, and the code gets better in the moment.

We structured it loosely. Engineers self-organize into pairs based on the work. For complex features, we encourage rotating pairs — one engineer stays on the feature for continuity while different partners cycle in. This actually achieves the knowledge transfer that code reviews promise but rarely deliver.

The pushback I got initially was predictable: "Two engineers on one task is half the throughput." The data tells a different story. Paired code has 40% fewer production defects in our measurements, and the time saved on debugging and rework more than compensates for the pairing overhead. A study from Microsoft Research backs this up — paired programming increases development time by about 15% but reduces defect rates by over 60%.

2. Automated Quality Gates

Everything that can be checked by a machine should be checked by a machine. This is not a novel insight, but the depth to which we implemented it was transformative.

Our CI pipeline now enforces:

  • Static analysis and linting with zero tolerance for warnings. No human should ever comment on code style in a review — that is a tooling failure.
  • Test coverage thresholds that are contextual. Core business logic requires 90%+ coverage. UI components have different standards. The thresholds are configured per-module based on risk.
  • Security scanning that catches dependency vulnerabilities, hardcoded secrets, and common vulnerability patterns before code reaches any human.
  • Performance regression detection that runs benchmarks against the previous release and flags anything outside acceptable variance.
  • Complexity analysis that flags functions exceeding cyclomatic complexity thresholds, forcing engineers to decompose before merging.

The key insight is that these gates are not advisory — they are hard blocks. If the pipeline fails, the code does not merge. Period. This removed an enormous category of "review feedback" that was really just catching things automation should have caught.

We invested roughly three engineering-months building out this pipeline. It paid for itself within the first quarter in reduced review cycle time alone.

3. Architecture Reviews

Here is the part most teams miss when they think about code quality: the most consequential decisions are not at the code level. They are at the architecture level. And those decisions are nearly invisible in a line-by-line diff.

We instituted a lightweight architecture review process for any change that meets certain criteria: introduces a new service or module, changes a public API contract, modifies data schemas, or alters system boundaries. Engineers write a brief design document — usually one to two pages — that explains the what, why, and trade-offs of their approach.

These documents get reviewed in a weekly architecture session attended by senior engineers and tech leads. The discussion is synchronous, focused, and high-leverage. We are not debating variable names. We are debating whether this service boundary will hold under 10x traffic growth, or whether this data model will support the features on our six-month roadmap.

This is where the real quality gains come from. A misnamed variable costs you minutes to fix. A poorly drawn service boundary costs you months.

The Results

After running this new system for eighteen months, here is what the data shows:

Defect rate in production dropped 35%. Not because we review more code, but because we catch problems earlier (pairing), catch mechanical issues automatically (quality gates), and catch structural issues before they are built (architecture reviews).

Time from code-complete to production decreased by 60%. Eliminating the review queue was the single biggest factor. Code that passes automated gates and was written in a pair can merge immediately.

Engineer satisfaction scores on "development process" increased significantly. Engineers report feeling less blocked, more collaborative, and more confident in their code.

Knowledge distribution improved measurably. We track "bus factor" — how many engineers can confidently modify each part of the codebase. After a year of pairing, our average bus factor per module went from 1.8 to 3.4.

When We Still Do Traditional Reviews

I want to be honest about the exceptions. We still use asynchronous code review in specific situations:

  • Open source contributions from external contributors who cannot pair with us.
  • Solo work during off-hours when no pairing partner is available, though we keep this to a minimum.
  • Extremely sensitive changes to authentication, encryption, or financial transaction code, where we want both a pair and an independent review.

These cases represent maybe 10% of our total code changes.

What This Requires to Work

I will not pretend this is a drop-in replacement. It requires a few things that not every organization has.

First, you need engineers who are willing and able to pair effectively. This is a skill, and not everyone has it naturally. We invested in coaching and made pairing effectiveness part of our engineering growth framework.

Second, you need strong CI/CD infrastructure. If your pipeline takes 45 minutes and fails intermittently, automated quality gates will not work. Invest in fast, reliable builds.

Third, you need leadership buy-in. The first time someone asks "who reviewed this code?" and the answer is "nobody, it was pair-programmed and passed all automated gates," there needs to be organizational trust backing that answer.

The Bigger Lesson

The reason traditional code reviews persist is not that they work well. It is that they are a visible, legible process that makes organizations feel safe. An approved pull request is an artifact you can point to. It is compliance theater.

Real quality comes from investing in the right feedback loops at the right time. Catch style issues with automation. Catch logic issues during pairing. Catch architectural issues before code is written. Stop pretending that an asynchronous diff review is the right tool for all three jobs.

I stopped doing code reviews. The code got better. And I would make the same decision again.