Skip to main content
Code Smells

Why Blocking Every Code Smell Is Killing Your Codebase's Health

I argue that obsessing over code smells during review is a trap. The real goal is code health, not perfection. Learn why you should approve that 'smelly' code.

The Contrarian Claim: Code Smells Aren't the Enemy

You've been told to hunt down every code smell—that duplicated block, that overly complex method, that 'God object' lurking in the shadows. But I'm here to tell you: fixating on code smells during review is actively harming your codebase's health. The golden rule of code review is to critique the code, not the author, but we've twisted that into a crusade against anything that smells. We've forgotten that the primary purpose of code review is to make sure the overall code health of the codebase is improving over time (Google Engineering Practices - Standard of Code Review). And sometimes, approving a smelly change is the healthiest thing you can do.

What Are We Really Afraid Of?

Let's define our terms. Code smells are those subjective, often stylistic indicators that something might be wrong—high cyclomatic complexity, excessive duplication, or a maintainability index that makes you wince. Tools like SonarQube quantify these into metrics, and we treat them like gospel. But here's the dirty secret: a code smell is not a bug. It's a hint, a suggestion, a starting point for conversation. The OWASP Top 10 lists real security risks like broken access control and injection—those are concrete threats. A duplicated switch statement? That's a smell. It might indicate a design issue, but it might also be perfectly fine for the context. We've conflated 'smell' with 'sin', and that's a costly mistake.

The Real Cost of Smell-Hunting

When you block a change because of a smell, you're not just delaying a merge—you're adding friction to the entire team. Google's research on code review speed is clear: slow reviews decrease team velocity and make developers protest the review process (Google Engineering Practices - Speed of Code Reviews). And what do you gain? Maybe a slightly cleaner method. But you've also delayed a feature, frustrated a developer, and burned goodwill. The DORA metrics show that speed and stability are not tradeoffs—top performers do well on both (DORA - Software delivery performance metrics). By obsessing over smells, you're sacrificing speed without necessarily gaining stability. You're also ignoring the real benefit of review: knowledge transfer. Studies at Microsoft found that reviews provide benefits like knowledge transfer and team awareness, not just defect detection (Modern Code Review: Expectations, Outcomes, and Challenges). When you nitpick a smell, you're missing the chance to discuss the design, the edge cases, the concurrency issues—the things that actually matter.

When a Smell Is Actually a Symptom

Now, I'm not saying all smells are harmless. Some are red flags for real problems. But the key is to distinguish between a smell that's a symptom of a deeper issue and one that's just a stylistic preference. For example, high cyclomatic complexity—a metric that counts the number of paths through code (SonarQube Server Docs - Understanding measures and metrics)—can indicate a method that's trying to do too much. But it could also be a complex business rule that's inherently branchy. Blocking it without understanding the context is lazy. Instead, ask: 'Is this complexity necessary? Is there a simpler way to express this?' That's a design conversation, not a metric threshold. Similarly, duplicated code might be a sign that you need to extract a function, but it might also be a case where duplication is cheaper than abstraction. The point is, a smell should trigger a discussion, not an automatic 'Request changes'. Google's own guidance says to be especially vigilant about over-engineering—code made more generic than it needs to be (Google Engineering Practices - What to look for in a code review). Sometimes, the smelly code is actually the pragmatic choice.

How to Decide: A Pragmatic Framework

So how do you decide when to block and when to approve? I propose a simple framework, based on Google's senior review principle: approve a change once it definitely improves the overall code health of the system, even if it isn't perfect (Google Engineering Practices - Standard of Code Review). Ask yourself three questions:

First, does this smell introduce a known security risk? If it's something like a SQL injection vulnerability or a hardcoded credential, that's not a smell—it's a critical bug. Block it. The OWASP Top 10 is your checklist here. Second, is the smell likely to cause a maintenance nightmare in the near future? If it's a deeply nested if-else that will be impossible to modify next month, that's a legitimate concern. But if it's a slightly long method that's well-named and tested, let it go. Third, will fixing the smell add significant complexity or delay? If the fix is trivial, suggest it. If it would require a major refactor, maybe it's not worth it right now. The goal is to keep the codebase healthy over time, not to achieve perfection in one review.

Let's apply this to a concrete example. Say a developer submits a change that adds a new feature. The code works, tests pass, but SonarQube flags a cognitive complexity of 15 in a new method. The technical debt ratio is 6%, just above the 5% threshold for an 'A' rating (SonarQube Server Docs - Understanding measures and metrics). Do you block? I say no. The method is a bit complex, but it's readable. The tests pass. The change improves the codebase. Approve it, and maybe leave a non-blocking suggestion to refactor later. Google's 'LGTM with comments' technique is perfect here: give approval while leaving unresolved comments when you're confident the developer will address them or when they're minor (Google Engineering Practices - Speed of Code Reviews). That's how you keep reviews fast and maintain team morale.

The Automation Trap

Another reason we've become smell-obsessed is that we've automated the detection. Tools like SonarQube, ESLint, and Semgrep will happily flag every smell in a pull request. But remember: these tools are meant to handle style and mechanical checks so that human review can focus on logic and architecture (Google Engineering Practices - code review). When you let the tool make your decisions for you, you're abdicating your judgment. You're also creating a situation where developers game the metrics instead of thinking about the code. I've seen it happen: a developer adds a `// NOSONAR` comment to suppress a warning, and the smell remains, but the metric looks clean. That's worse than having the smell. Instead, use the tools as a starting point, not a verdict. A quality gate can block a merge if the new code coverage is below 80% (SonarQube Server Docs - Understanding quality gates), but that's a hard rule, not a smell. For smells, you need human judgment.

Quick Tip: When in Doubt, Approve

Here's a quick tip: if you're on the fence about a smell, and it's not a security issue, and the code is tested and understandable, approve it. You can always refactor later. Blocking a change over a smell is a waste of everyone's time. Remember, Google's data shows that the median change size is about 24 lines (Modern Code Review: A Case Study at Google), so most changes are small. If you're blocking a 24-line change because of a smell, you're probably overthinking it.

Bottom Line

The next time you're reviewing a pull request and you see a code smell, take a breath. Ask yourself if it's a security risk, if it's a maintenance nightmare, or if it's just a minor imperfection. If it's the latter, approve it. Your job is to improve the codebase's health, not to enforce a style guide. As Google says, 'there is no such thing as perfect code, there is only better code' (Google Engineering Practices - Standard of Code Review). So approve the smelly but healthy change, and save your blocking for the things that truly matter.

Sources

  • Google Engineering Practices - Standard of Code Review - https://google.github.io/eng-practices/review/reviewer/standard.html
  • Google Engineering Practices - Speed of Code Reviews - https://google.github.io/eng-practices/review/reviewer/speed.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
  • SonarQube Server Docs - Understanding measures and metrics - https://docs.sonarsource.com/sonarqube-server/user-guide/code-metrics/metrics-definition
  • DORA - Software delivery performance metrics - https://dora.dev/guides/dora-metrics-four-keys/

Share this article:

Comments (0)

No comments yet. Be the first to comment!