You've heard it a hundred times: "That's a code smell." And half the time, it's just someone's opinion. Maybe they don't like the function length. Maybe they've read one too many blog posts. But here's the thing: code smells aren't subjective. They're measurable. And if your code review is arguing about taste, you're doing it wrong.
The question this article answers is simple: How do you make code smell discussions objective in a code review? The answer isn't to memorize a list of smells and play whack-a-mole. It's to use the tools that quantify smells, set a standard, and then let the reviewer focus on what actually matters: design and logic.
Code Smells Have Numbers
Take cyclomatic complexity. SonarQube defines it as the number of paths through your code: 1 plus the number of conditional branches. That's not a vibe; it's a formula. If your function has a score of 50, that's not "kinda complex" — that's objectively hard to test and maintain. Similarly, technical debt ratio is a number. SonarQube computes it as the cost to fix all your maintainability issues divided by the cost to write the code from scratch. A ratio under 5% gets an A; over 50% gets an E. That's not a gut feeling.
So when a reviewer says "this function is too complex," they should be able to point to a number. If they can't, they're just pushing a preference. And preferences are fine, but they shouldn't block a merge. What should block a merge is a function that's objectively a tangle of branches, because it's a breeding ground for bugs and a nightmare for the next person who has to touch it.
Static Analysis Is Your Objective Reviewer
This is where static analysis tools come in. They don't have opinions; they have rules. ESLint, for example, is completely pluggable — every single rule is a plugin. You decide what matters, and the tool enforces it. Bandit processes Python files, builds an AST, and runs plugins to find common security issues. gosec does the same for Go, scanning the AST and SSA representation for SQL injection, path traversal, and unsafe deserialization. These tools don't care about your ego. They just report.
And they should be the first line of defense. Google's engineering practices are explicit: linters, formatters, static analysis, secret scanners, and dependency scanners should handle the mechanical checks so human reviewers can focus on logic and architecture. If your review is spending time on style or a missing semicolon, the tools have already failed you. Set them up, and then the human review is free to ask the real questions: Is this design sound? Does this change make the codebase healthier?
Set a Quality Gate, Not a Wish
But tools only help if you have a threshold. SonarQube's built-in quality gate, called Sonar Way, has four conditions: no new issues, all new Security Hotspots reviewed, new code test coverage at least 80%, and duplication in new code under 3%. That's a standard. You either meet it or you don't. No debate.
Now, you don't have to adopt that exact gate. But you need something. A quality gate answers the question "is my project ready for release?" and it can block a merge or fail CI. Without a gate, you're relying on the reviewer's mood that day. With a gate, you have a contract. The reviewer's job becomes checking the things the gate can't: overall design, edge cases, and whether the tests actually test the right behavior. That's a much more valuable use of human time.
Design Is Still King
Don't mistake this for saying static analysis replaces the human. It doesn't. Google's review checklist puts overall design first — before functionality, complexity, tests, naming, and comments. And the primary purpose of review is to ensure the codebase's health improves over time, not to catch every bug. That's a human judgment call.
Here's a concrete example. Say you're reviewing a Python change that adds a new endpoint. The linter passes, the complexity is fine, coverage is at 85%. But the design puts the database query inside the view function. That's a design smell. A static analyzer won't catch it. A human reviewer should. And they should say something specific: "This query belongs in a repository layer, not the view." That's not a nit; it's a design improvement that will pay off in maintainability.
So the reviewer's role is to catch the smells that tools can't. But they should use the tools to establish a baseline of objectivity. When a reviewer says "this is too complex," they can point to the metric. When they say "this needs a comment," they can point to the code's incomprehensibility. That's the sweet spot: tools handle the mechanical, humans handle the conceptual.
Small Changes Make Smells Obvious
Finally, keep changes small. Google's data is striking: the median change size at Google is about 24 lines, and over 35% of changes touch only one file. Google suggests that 100 lines is usually reasonable, and 1000 lines is usually too large. Why does this matter for code smells? Because a 500-line PR is a fog. It's hard to see the design through the noise. A 24-line change is crystal clear. You can spot the smell immediately.
Google's research also shows that small changes are reviewed more quickly and more thoroughly, and they're less likely to introduce bugs. When you split a large PR by concern, you give each review a single focus. That's how you make code smell discussions objective — you isolate the change so the smell is undeniable.
Bottom Line
Stop arguing about taste. Set up static analysis, define a quality gate, and keep changes small. Then the reviewer's opinion is backed by data, and the codebase gets healthier with every merge.
Sources
- Google Engineering Practices (code review) - https://google.github.io/eng-practices/review/
- SonarQube Server Docs - Understanding measures and metrics - https://docs.sonarsource.com/sonarqube-server/user-guide/code-metrics/metrics-definition
- SonarQube Server Docs - Understanding quality gates - https://docs.sonarsource.com/sonarqube-server/2026.1/quality-standards-administration/managing-quality-gates/introduction-to-quality-gates
- Google Engineering Practices - Small CLs - https://google.github.io/eng-practices/review/developer/small-cls.html
- Google Engineering Practices - What to look for in a code review - https://google.github.io/eng-practices/review/reviewer/looking-for.html
- 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
Comments (0)
Please sign in to post a comment.
Don't have an account? Create one
No comments yet. Be the first to comment!