Skip to main content
Code Smells

Code Smells: Static Analysis Tools vs. Human Review

Static analysis tools catch mechanical issues, but human review finds design problems. Here's how to balance both for better code health.

Imagine you're reviewing a pull request. The diff is 200 lines. You spot a typo in a comment, a missing semicolon, and a variable named foo. You're about to leave a comment about the typo when you realize—you've spent two minutes on trivialities and haven't looked at the actual logic. This is the trap of manual review. The fix isn't to stop manual review; it's to let machines handle the trivial and reserve human brains for what matters.

The Problem: Human Review Is Wasted on Mechanical Smells

Code smells are symptoms of deeper problems. Some are mechanical—style violations, unused imports, obvious security patterns. Others are architectural—over-engineering, poor design, missing tests. The trouble is that humans are bad at spotting the first kind reliably, and even worse at resisting the urge to comment on them. Google's own guidance says to let linters, formatters, static analysis, secret scanners, and dependency scanners handle style and mechanical checks, so human review focuses on logic and architecture (Google Engineering Practices). Yet many teams still rely on the reviewer's eye to catch a missing space or a hardcoded credential.

This isn't just inefficient. It's counterproductive. When reviewers spend time on nits, they have less energy for the design-level questions that actually matter. Google's research at scale shows that the median change size is about 24 lines, and that more than 80% of reviews finish in a single iteration (Modern Code Review: A Case Study at Google). That means reviews are short. If you waste that brevity on trivia, you've lost the chance to improve the code's overall health.

The Contenders: SonarQube vs. Human Review

Two approaches dominate: automated static analysis platforms like SonarQube, and traditional human review. SonarQube is a widely used platform that analyzes reliability (bugs), security (vulnerabilities), maintainability (code smells), coverage, and duplication (SonarQube GEANT KB). It computes metrics like cyclomatic complexity, cognitive complexity, and technical debt ratio. It even defines a maintainability rating: A if technical debt ratio is under 5%, E if over 50% (SonarQube Server Docs). On the security side, it rates vulnerabilities from A (zero) to E (at least one blocker) (SonarQube Server Docs).

Human review, on the other hand, is about judgment. Google's primary purpose of code review is to make sure the codebase's overall health improves over time (Google Engineering Practices). Reviewers look at design, functionality, complexity, tests, naming, and comments—in that order of importance (Google Engineering Practices). They think about edge cases, concurrency problems, and over-engineering (Google Engineering Practices). A machine can't tell you that a class is over-abstracted or that a function is trying to do too much.

Here's the head-to-head:

CriterionSonarQubeHuman Review
SpeedInstant feedback on every commitMedian time to first feedback under 1 hour for small changes (Google case study)
CoverageCatches mechanical issues, security hotspots, duplicationCatches design flaws, over-engineering, missing edge cases
ScalabilityWorks on every line of code, every timeLimited by reviewer attention and time
False positivesCan flag non-issuesCan miss obvious bugs due to fatigue

The table oversimplifies, but the point stands: they're complementary, not competing. The mistake is treating them as either/or.

The Sweet Spot: Automate the Mechanical, Humanize the Design

Here's my recommendation: let SonarQube (or a similar tool) be the gatekeeper for mechanical health, and let humans focus on design. Concretely, that means integrating SonarQube into your CI pipeline, with a quality gate that blocks merge if new issues are introduced or if new code test coverage drops below 80% (SonarQube Server Docs). That's a strict bar, but it's mechanical. The machine can check it in milliseconds.

Then, when a human reviews, they should skip the nits. If a comment is a nit, label it as such and don't block on it. Google's “LGTM with comments” technique lets you approve a change while leaving minor comments, trusting the developer to address them (Google Engineering Practices). This keeps review moving. And when you do comment, be specific—file paths and line numbers—and offer solutions, not just problems (Google Engineering Practices).

The evidence backs this split. At Google, even with heavy automation, human review remains central. Their case study found that developers' top expectations from review were education, maintaining norms, gatekeeping, and accident prevention—not just bug finding (Modern Code Review: A Case Study at Google). That's human stuff. Meanwhile, SonarQube's technical debt ratio gives you a numeric handle on maintainability, but it can't tell you if a design is over-engineered. Only a human can.

Why Most Teams Get It Wrong

Most teams either rely on human review for everything or trust automation too much. The first leads to slow reviews and burnout. The second leads to a false sense of security—a quality gate passing doesn't mean the code is well-designed. SonarQube's quality gate is a set of conditions measuring code during analysis, answering “is my project ready for release?” (SonarQube Server Docs). But “ready for release” is not “good design.” A 200-line function with 20 branches can pass a quality gate but be a nightmare to maintain.

Consider a concrete example: you're reviewing a Python change that uses eval on user input. Bandit, a security linter, would flag that instantly (Bandit Docs). But if you rely on human review, the reviewer might miss it—especially late in the day. Conversely, a change that adds an unnecessary abstraction layer might pass all static checks but be exactly the over-engineering Google warns about (Google Engineering Practices). Only a human reviewer, asking “is this the simplest thing that works?”, will catch that.

The solution is a two-stage pipeline: automated checks first, human review second. SonarQube runs on every commit, catching the mechanical smells. Then a human reviews the diff, focusing on design and logic. This isn't my invention—it's how Google and other high-performing teams operate. Their research shows that peer review discussions are usually short and changes are small (Rigby & Bird, ESEC/FSE 2013). If you spend that short time on nits, you lose the opportunity for meaningful feedback.

Bottom Line

Stop using human reviewers as linters. Let SonarQube handle the mechanical code smells—security, duplication, complexity—and reserve your human reviewers for what they're uniquely good at: design, edge cases, and over-engineering. That's the only way to keep code health improving over time.

Sources

  • Google Engineering Practices (code review) - https://google.github.io/eng-practices/review/
  • SonarQube (GEANT KB) - https://kb.pert.geant.net/pages/viewpage.action?pageId=412221495
  • Modern Code Review: A Case Study at Google (ICSE-SEIP '18) - https://www.papercache.org/papers/mlsys/system/2026/03/25/modern-code-review-a-case-study-at-google
  • SonarQube Server Docs - Understanding measures and metrics - https://docs.sonarsource.com/sonarqube-server/user-guide/code-metrics/metrics-definition
  • Bandit (PyCQA) Docs - https://bandit.readthedocs.io/en/latest/
  • Convergent Contemporary Software Peer Review Practices (Rigby & Bird, ESEC/FSE 2013) - https://dl.acm.org/doi/10.1145/2491411.2491444

Share this article:

Comments (0)

No comments yet. Be the first to comment!