guide

What Are Code Smells? 12 Common Smells With Examples (2026)

A practical catalog of code smells with real code snippets, why each one hurts, the refactor that fixes it, and the tools that detect them automatically.

Published:

Last Updated:

Direct answer

A code smell is a surface characteristic in source code that signals a deeper design weakness without being a defect - the code compiles, the tests pass, and it is quietly becoming expensive to change. The twelve canonical smells come from Fowler’s Refactoring. The critical caveat most pages omit: smells are heuristics with real false-positive rates, so gate new code only and never block a merge on a total smell count. Verified 2026-10-19.

What is a code smell?

Direct answer: A characteristic in source code that does not break anything but indicates a design weakness that will make future change harder. Coined by Kent Beck, popularized by Martin Fowler’s Refactoring. A smell is not a bug: behaviour is correct, tests pass, and the cost is deferred into every subsequent edit. It is a heuristic, not a finding. Verified 2026-10-19.

Think of smells the way a mechanic thinks of a rattle. The car still drives, but the rattle tells you something is loose and worth investigating before it becomes a breakdown. In software, that breakdown is technical debt - the accumulated cost of shortcuts and eroding design. Smells are the early, visible symptoms.

This guide catalogs the twelve you will meet most often, shows each in real code, maps each to the tools that catch it, and then spends real space on the part almost every other page skips: smells are heuristics, and a tool that reports them without context produces technically-correct uselessness.

Why code smells matter

Software spends most of its life being modified, not written. A codebase riddled with duplication and 400-line methods is not dangerous on the day it ships. It is dangerous six months later when somebody needs to change a business rule and cannot find all five places it lives.

The good news is that smells are the most fixable category of code problem, because the fix is almost always a known refactoring that preserves behaviour. The hard part is spotting them consistently and - much harder - deciding which ones are worth the regression risk.

12 common code smells with examples

1. Duplicated code

The most common smell. The same logic appears in multiple places, so a fix must be applied everywhere, and inevitably one copy gets missed.

// Smell: the same discount math copied in two places
function checkoutTotal(cart) {
  return cart.items.reduce((s, i) => s + i.price * (i.vip ? 0.8 : 1), 0);
}
function invoiceTotal(order) {
  return order.lines.reduce((s, i) => s + i.price * (i.vip ? 0.8 : 1), 0);
}

Extract the shared rule into one function. Caveat worth naming: not all duplication should be removed. Two blocks that look identical today but belong to domains that will diverge tomorrow are better left apart - premature deduplication creates coupling that is harder to undo than the duplication was. See our guide to duplicate code checker tools and the code duplication glossary entry.

2. Long method

A method doing too much. If you cannot see the whole thing without scrolling, or you need comments to mark its sections, those sections want to be separate methods.

# Smell: one function doing validation, transformation, persistence and notification
def process_order(data):
    if not data.get("email"):           # validation
        raise ValueError("email required")
    if data["qty"] <= 0:
        raise ValueError("qty must be positive")
    total = data["qty"] * data["price"]  # transformation
    total = total * 0.8 if data.get("vip") else total
    row = db.insert("orders", {**data, "total": total})  # persistence
    mailer.send(data["email"], f"Order {row.id} confirmed")  # notification
    analytics.track("order_created", row.id)
    return row

Four responsibilities, four reasons to change, one test that has to mock all of it. Extract validate_order, compute_total, persist_order, notify.

3. Large class (god object)

A class that has accumulated dozens of fields and responsibilities becomes the place every change has to touch. Split it along its responsibilities so each class has a single reason to change. The reliable signal is not line count but how many unrelated features’ pull requests touch the same file - which is why change-coupling analysis beats a size threshold here.

4. Long parameter list

# Smell: seven positional parameters, easy to pass in the wrong order
def create_user(name, email, age, country, plan, referrer, is_admin):
    ...

# Better: the related fields travel together and the booleans are named
def create_user(profile: Profile, plan: Plan, *, is_admin: bool = False):
    ...

More than three or four parameters usually means several belong together in an object. Keyword-only booleans are a cheap partial fix even without a refactor.

5. Feature envy

A method that reaches into another object’s data more than its own. It envies the other class and probably belongs there.

// Smell: Invoice is doing Customer's job
class Invoice {
  double shippingCost(Customer c) {
    if (c.getCountry().equals("US") && c.getTier() == Tier.PRIME) return 0;
    if (c.getCountry().equals("US")) return 4.99;
    return c.getTier() == Tier.PRIME ? 9.99 : 19.99;
  }
}

Every branch reads Customer state and none reads Invoice state. Move it to Customer. This is the smell automated tools detect worst, because the rule needs to compare feature-access ratios across types rather than count a threshold.

6. Primitive obsession

Using raw strings and integers where a small type would carry meaning and validation - money as a float, a phone number as a string, a currency as a bare code. Introduce small value types that encapsulate the rules. The classic consequence is the same validation regex copied into eleven files.

7. Magic numbers

// Smell: what is 86400?
if (session.ageSeconds > 86400) { logout(); }

// Better: the constant explains itself
static final int SECONDS_PER_DAY = 86400;
if (session.ageSeconds > SECONDS_PER_DAY) { logout(); }

Unexplained literals hide intent and invite inconsistency. Name them. Note that tools over-flag this one: 0, 1, 2, -1, 100 and HTTP status codes are almost always fine, and a rule that flags them is generating noise.

8. Deeply nested conditionals

// Smell: four levels of nesting, happy path buried at the bottom
func handle(r *Request) error {
    if r != nil {
        if r.User != nil {
            if r.User.Active {
                if r.Payload != nil {
                    return process(r)
                }
            }
        }
    }
    return errors.New("invalid request")
}

// Better: guard clauses, happy path at the end and unindented
func handle(r *Request) error {
    if r == nil || r.Payload == nil {
        return errors.New("invalid request")
    }
    if r.User == nil || !r.User.Active {
        return errors.New("inactive user")
    }
    return process(r)
}

This smell overlaps directly with high cyclomatic complexity, and it is the one most reliably caught by tooling because it reduces to a nesting-depth integer.

9. Dead code

Code that is never executed - unreachable branches, unused functions, commented-out blocks kept just in case. It adds cognitive load and misleads readers about what the system does. Delete it; version control remembers. See the dead code glossary entry. The one real exception: code reachable only through reflection, dependency injection, or a dynamic plugin registry. Static analysers flag it as dead and they are wrong. This is the single most common false positive in the whole catalogue.

10. Shotgun surgery

A single conceptual change forces edits across many unrelated files. The mirror image of a god object - responsibility scattered too thinly. Consolidate so one change lives in one place. Detectable from git history (files that always change together) rather than from the source.

11. Data clumps

The same group of fields travels together everywhere - always startDate, endDate, timezone side by side. That clump is asking to become a DateRange type. Data clumps are the upstream cause of most long parameter lists, which is why fixing one usually fixes the other.

12. Speculative generality

Abstractions, hooks, interfaces and parameters added for a future that never arrived. A strategy pattern with one strategy. A plugin interface with one implementation. Unused flexibility is a cost, not an asset. Remove it until a real requirement demands it. This is the smell senior engineers introduce and junior engineers get blamed for.

Are code smells always worth fixing?

Direct answer: No. A smell in code nobody has edited in two years charges almost no interest, and fixing it spends review attention and accepts regression risk for zero velocity gain. Fix smells in code that changes often, because that is where cost compounds. If you have only one prioritisation signal, use git change frequency rather than smell count. Verified 2026-10-19.

This is the single most important thing on the page and the thing most code-smell content gets wrong. A smell is a heuristic, which means it has a false-positive rate that nobody publishes.

SmellDetection reliabilityCommon false positive
Deeply nested conditionalsHigh - it is a nesting-depth integerRare; occasionally a state machine reads better nested
Long methodHigh - a line countGenerated code, big switch tables, data fixtures
Long parameter listHigh - a countConstructors in languages without named arguments
Duplicated codeMedium-highStructurally similar code in domains that must diverge
Magic numbersMedium0, 1, -1, HTTP status codes, well-known constants
Large classMediumFramework-mandated god classes, generated clients
Dead codeMediumReflection, DI containers, dynamic plugin registries
Primitive obsessionLow-mediumBoundary code that must speak the wire format
Data clumpsLowFields that co-occur coincidentally
Feature envyLowDeliberate separation of policy from data
Shotgun surgeryLow from source, higher from git historyCross-cutting changes that genuinely belong in many places
Speculative generalityLowAn abstraction with one implementation today and a committed second next quarter

The reliability ranking is roughly the inverse of the usefulness ranking. The smells tools catch best are the ones that matter least, and the smells that matter most are the ones tools catch worst. That asymmetry explains most of the frustration teams have with code quality dashboards.

Why does my AI reviewer flag smells on legacy code nobody wants fixed?

Direct answer: Because it is answering correctly in a context where the answer is useless. An AI reviewer reading a three-line bugfix inside a 4,000-line legacy file will note the file is too long, the method is too long and the parameters are too many. All true. All unactionable. This is the fastest way to train a team to ignore the bot. Fix it with configuration, not tolerance. Verified 2026-10-19.

We named this pattern technically-correct uselessness, and it is the dominant failure mode when an AI reviewer meets a mature codebase. The bot has no concept of “this structure predates the PR and is not up for discussion in a hotfix,” so it says the true thing at the worst possible moment.

The configuration that fixes it:

  1. Scope structural commentary to new or substantially rewritten code. Most reviewers support instruction files for this. CodeRabbit accepts custom review instructions in natural language and reads guideline files - and notably its knowledge_base.code_guidelines.filePatterns defaults include **/REVIEW.md, **/CLAUDE.md, **/AGENTS.md, **/.cursorrules, .github/copilot-instructions.md, **/GEMINI.md and **/.windsurfrules, so it will read its competitors’ rule files by default (verified 2026-10-18).
  2. Suppress smell categories, not severities. Turning the severity threshold up loses real bugs. Turning off “file length” specifically loses nothing you wanted.
  3. Separate nit from blocker explicitly. A smell comment that is not labelled as optional reads as a change request. See what is a nitpick in PR reviews and CodeRabbit reduce noise.
  4. Baseline the structure. The ratchet applies here exactly as it does to linting: gate new code, baseline the rest.

Our full treatment of this is in AI code review on legacy codebases, which is the companion page to this one. The short version: a reviewer that comments on pre-existing structure in every PR has negative value, because the cost of reading past it is paid on every review forever.

Can an AI reviewer detect smells better than a static analyser?

Direct answer: For threshold smells, no - a rule is deterministic, free to run and auditable, which an LLM cannot match. For structural smells like feature envy, shotgun surgery and speculative generality, plausibly yes, because those need intent rather than a count. No independent benchmark measures smell-detection precision for any AI reviewer as of 2026-10-19. Verified 2026-10-19.

The architecture that the serious vendors actually ship reflects this split rather than replacing one with the other. DeepSource runs 5,000-plus deterministic analyzers across 30-plus languages before its AI agent engages, and CodeRabbit pairs an LLM with 40-plus open source linters and static analysers (verified 2026-10-18). Neither is betting the threshold smells on an LLM, because there is no reason to.

What the independent evidence does and does not say:

  • No party without a commercial stake has published a false-positive rate, precision figure or noise measurement for any shipping commercial AI code reviewer (checked 2026-10-19). SWE-PRBench and CR-Bench both publish false-positive data, but for bare models in fixed harnesses rather than products you can buy.
  • No benchmark we can find measures code-smell detection specifically. The benchmarks that exist - SWE-PRBench, CR-Bench, c-CRAB, CRBugBench, GitHub ReviewBench - measure bug or review-comment detection, not design-smell identification. c-CRAB’s headline is that across four agentic tools, 97 of 234 executable review tests were passed by at least one tool, 41.5% (arXiv 2603.23448). Disclosure: one c-CRAB author lists SonarSource as his affiliation; Sonar owns SonarQube, acquired Gitar in May 2026, and Gitar is a paid sponsor of this site.
  • The widely circulated “40 to 70% false positive rate for AI reviewers” figure attributed to c-CRAB is not in that paper. No false-positive rate is reported for any reviewed tool. Do not repeat it.

How code smells map to detection tools

Consistent enforcement across a team needs tooling. Here is how the major platforms cover the catalogue above.

ToolThreshold smellsDuplicationStructural smellsPrioritisation signalPrice point (verified 2026-10-18)
SonarQubeStrong, first-class “code smell” issue typeStrongPartialRemediation-time estimate, quality gate on new codeCommunity Build free but main branch only, no PR analysis; Cloud free tier does include PR analysis to 50k LOC
DeepSourceStrong, 5,000+ analyzers, 30+ languagesStrongPartial, plus an AI agent on topAutofix availabilityTeam ~$24/dev/mo; AI review billed separately at $8 per 10K LOC Standard, $15 Advanced
SourceryStrong on PythonMediumProposes concrete refactorsRefactor suggestion qualityPro $12/seat/mo, Team $24, annual
CodacyStrong across 40+ languagesStrongWeakQuality gatesDeveloper free forever; Team from $18/dev/mo yearly
CodeSceneMediumMediumStrong via change couplingChange frequency from git historyQuote-based
CodeRabbitVia 40+ bundled lintersVia bundled lintersLLM reasoning over the diffDiff relevanceEssentials $24/dev/mo annual, 1 linked repo; Team $48, 5 repos
SonarQube static analysis tool homepage screenshot
SonarQube homepage

SonarQube treats “code smell” as a first-class issue category distinct from bugs and vulnerabilities, with rules for duplication, method length, class size, complexity and magic numbers across 35-plus languages. Its quality gates can block a merge when new smells cross a threshold, and it estimates the remediation time each smell adds. Precision point that matters: SonarQube Community Build cannot analyze pull requests - Sonar’s own docs state Developer Edition is the minimum for branch and PR analysis - while SonarQube Cloud’s free tier does include PR analysis up to 50k lines on private projects (verified 2026-10-18). See SonarQube pricing and SonarQube Community vs Developer.

DeepSource code quality platform homepage screenshot
DeepSource homepage

DeepSource flags anti-patterns and structural smells among its 5,000-plus analyzers and offers Autofix for many, turning “here is a smell” into a one-click fix PR. Two 2026 facts most comparisons miss: DeepSource became a Harness product on 9 September 2026, and its AI review is billed separately from the seat at $8 per 10K processed lines (Standard) or $15 per 10K (Advanced), with a $100 annual AI credit per user (verified 2026-10-18). See DeepSource pricing.

Sourcery specializes in exactly this problem - it detects long methods, duplication and nested conditionals in pull requests and proposes the concrete refactor, with the deepest Python support, at Pro $12/seat/mo and Team $24 billed annually. Codacy aggregates duplication and complexity detection across 40-plus languages with quality gates on top.

CodeScene is the differentiated one and the reason this section exists. It combines code health with how often each file changes, ranking debt by business impact so you fix the complex file everyone touches daily rather than the complex file nobody has opened in a year. That behavioural prioritisation is the single most useful upgrade to raw smell counting, and it is the only commercial implementation of the “use git history, not a count” principle. For a focused comparison see best code smell detection tools.

How to fix code smells without breaking things

The cardinal rule is that behaviour must not change. That is what makes it refactoring rather than rewriting.

  1. Make sure the code is under test first. If the smelly code has no tests, add characterization tests that pin down its current behaviour - including the behaviour you think is wrong - before you touch it.
  2. Apply one small refactoring at a time. Extract a method, rename a variable, introduce a parameter object. Run the tests between each.
  3. Commit each safe step. Small green commits make it trivial to back out.
  4. Keep the refactor out of the feature PR. A diff that mixes behaviour change with structural change is far harder to review, and it is the main reason reviewers rubber-stamp refactors. Our dataset of 2,896 merged PRs found that inline review threads per 100 changed lines fall from 1.55 on PRs under 50 lines to 0.085 on PRs over 1,000 lines, an 18-fold drop in scrutiny density, and 52% of merged PRs over 1,000 lines carried zero inline review comments (harvested 2026-10-18, published in how big should a pull request be). A big refactor PR is a PR nobody reads.
  5. Let the tool re-scan. Confirm the count actually dropped and you did not push the problem elsewhere.

Fix smells opportunistically, not in a grand cleanup sprint. The campground rule - leave each file a little cleaner than you found it, whenever you are already editing it for another reason - works because the context is already loaded in someone’s head and the regression risk is already being accepted.

Common mistakes

  • Treating a smell report as a defect list. Smells are heuristics with unpublished false-positive rates.
  • Gating on total smell count. It fails on day one against a mature codebase and gets disabled by day three. Gate new code only.
  • Letting an AI reviewer comment on pre-existing structure. Technically-correct uselessness, paid on every review forever.
  • Deduplicating too early. Coupling two domains that must diverge is harder to undo than the duplication was.
  • Trusting dead-code detection on a DI-heavy or reflection-heavy codebase. It is the catalogue’s most common false positive.
  • Bundling refactors into feature PRs. Scrutiny density collapses as diffs grow, so the refactor goes unreviewed.
  • Prioritising by count instead of change frequency. The complex file nobody edits charges no interest.
  • Treating the remediation-hours number as money. It is a sum of per-rule constants, useful for trending in one codebase and close to meaningless as an absolute.

How we verified this

Checked on 2026-10-19: internal link targets against the live content tree in this repository; the absence of any published benchmark measuring code-smell detection precision for AI reviewers; and the absence of any vendor-published per-language precision data for smell detection.

Carried from the 2026-10-18 verification pass, read from vendor documentation and pricing pages:

  • SonarQube treating code smell as a distinct issue category; Community Build’s inability to analyze pull requests (Sonar’s own wording: Developer Edition is the minimum for branch and PR analysis) versus SonarQube Cloud’s free tier including PR analysis up to 50k LOC on private projects.
  • DeepSource at 5,000-plus analyzers across 30-plus languages, the Harness acquisition on 9 September 2026, and AI review billed separately at $8 per 10K LOC Standard / $15 Advanced with a $100 annual AI credit per user.
  • CodeRabbit pairing an LLM with 40-plus linters, its Essentials tier covering 1 linked repository at $24/dev/mo annual, and the knowledge_base.code_guidelines.filePatterns defaults that read competitors’ rule files.
  • Sourcery at Pro $12 / Team $24 per seat per month annual; Codacy Developer free forever and Team from $18/dev/mo yearly.
  • c-CRAB’s dataset (184 PR instances, 67 repositories, 234 validated review comments) and the 41.5% union figure, plus the correction that the widely quoted “40-70% false positive rate” is not in that paper.

Our own data: the scrutiny-density figures (1.55 to 0.085 inline threads per 100 changed lines; 52% of 1,000+ line merged PRs with zero inline comments) come from our own harvest of 2,896 human-authored merged PRs across 10 repositories via the GitHub GraphQL API on 2026-10-18, with 104 bot accounts removed, PRs created 17 April to 17 October 2026. Published in how big should a pull request be. Honest counterpoint from that dataset: absolute comment counts rise with PR size (Spearman rho +0.355), so large PRs are not ignored, just reviewed far less per line.

What we could not verify:

  • No published false-positive rate exists for code-smell detection by any tool, commercial or open source. The detection-reliability table in this article is our own ranking based on what each rule measures, not a measured precision figure. We present it as reasoning, not data.
  • No independent benchmark measures smell-detection precision for any AI code reviewer (checked 2026-10-19).
  • No vendor publishes per-language precision or recall for its own smell detection.
  • DeepSource’s historical “sub-5% false positive rate” claim is vendor-stated and unreplicated; we have removed it from the body of this page rather than repeat it as fact.
  • The attribution of the term “code smell” to Kent Beck and its popularisation by Fowler’s Refactoring is well-documented industry record, not something we verified against a primary source.

Disclosure: Gitar is a paid sponsor of aicodereview.cc. Sonar acquired Gitar in May 2026 and also owns SonarQube, which is recommended on this page on the evidence. One c-CRAB author lists SonarSource as his affiliation. We disclose this wherever c-CRAB is cited.

Recommendations

Criteria: detection reliability on the smells that matter, prioritisation quality, and whether the tool can gate new code without drowning you in old code.

If you want one tool and run multiple languages: SonarQube Cloud, with the quality gate configured on new code only. It is the reference implementation of smell categorisation and the gating model is the right one out of the box. Do not pick Community Build if you need PR analysis - it cannot do it.

If you are Python-heavy: Sourcery at $12/seat/mo, because it does not just report the smell, it writes the refactor, and that is the difference between a dashboard and a change.

If your problem is “we have 40,000 findings and no idea where to start”: CodeScene. Change-frequency weighting is the only prioritisation signal that reliably correlates with where the cost actually lands, and it is the one capability nobody else ships.

If you already have an AI reviewer and it is noisy: do not buy another tool. Configure the one you have to stop commenting on pre-existing structure, suppress the file-length and method-length categories on legacy paths, and require nits to be labelled as nits. See AI code review on legacy codebases and CodeRabbit reduce noise.

What not to do: do not put a total-smell-count gate in CI, do not schedule a cleanup sprint, and do not treat a remediation-hours estimate as a budget figure. All three fail for the same reason - they ignore that a smell is a heuristic about future cost rather than a measurement of present damage.

Further reading

Sponsored Why?
Gitar logoGitar

Comments are not enough

Gitar applies the fix, validates it in CI, and clears the queue.

See it on your repo Read our independent Gitar review

Frequently Asked Questions

What is a code smell?

A code smell is a surface indication in source code that usually points to a deeper design problem. The code compiles and the tests pass - a smell is not a bug. It is a warning sign, like a duplicated block or a 300-line method, that the code will be hard to change, test or extend later. The term was popularized by Kent Beck and Martin Fowler in the book Refactoring. The word usually is doing real work in that definition: a smell is a heuristic with a known false-positive rate, not a defect, which is why gating a build on smell counts goes badly.

Are code smells the same as bugs?

No, and conflating them wastes review attention. A bug produces wrong behavior now. A code smell produces correct behavior but signals fragile design that makes future bugs more likely and future changes more expensive. You fix bugs because the software is broken. You address smells because the software is becoming hard to work with. Static analysis platforms report them as separate categories with separate severities for exactly this reason - SonarQube treats code smells as a distinct issue type from bugs and vulnerabilities, and conflating the three in a quality gate is how teams end up blocking a merge over a long parameter list.

What are the most common code smells?

The most frequently flagged are duplicated code, long method, large class or god object, long parameter list, feature envy, primitive obsession, magic numbers, deeply nested conditionals, dead code, shotgun surgery, data clumps and speculative generality. Duplicated code and long method are by far the two most common in most codebases and the two automated tools catch most reliably, because both reduce to measurable thresholds. The structural smells - feature envy, shotgun surgery - are the ones tools detect worst, because recognising them requires understanding what the code is for rather than how long it is.

How do you detect code smells automatically?

Static analysis platforms parse code into an abstract syntax tree and apply threshold and structure rules for size, duplication, complexity and coupling. SonarQube, DeepSource, Sourcery and Codacy all report smells as a distinct category with severity levels and suggested refactors, and can fail a pull request when new smells cross a configured threshold. The important configuration decision is to gate new code only and baseline everything that already exists, because turning a full rule set on against a mature codebase produces thousands of findings and one predictable outcome: somebody sets the job to non-blocking and nobody reads it again.

Are code smells always worth fixing?

No. A smell in code that nobody has edited in two years charges almost no interest and fixing it is a net loss - you spend review attention and accept regression risk for no change in future velocity. The smells worth fixing are the ones in code that changes often, because that is where the cost compounds. CodeScene's whole thesis is this: combine code health with change frequency so you fix the complex file everyone touches daily rather than the complex file nobody opens. If you only have one prioritisation signal, use git history rather than a smell count.

Why does my AI reviewer flag code smells on legacy code that nobody wants fixed?

Because it is doing exactly what you asked, on a codebase where the answer is not useful. An AI reviewer looking at a diff inside a 4,000-line legacy file will correctly observe that the file is too long, the method is too long, and the parameter list is too long - all true, all unactionable in a three-line bugfix PR. This is technically-correct uselessness and it is the fastest way to teach a team to ignore the bot. The fix is configuration, not tolerance: scope smell commentary to new or substantially rewritten code and suppress it on pre-existing structure.

Can an AI code reviewer detect code smells better than a static analyser?

For structural smells, plausibly yes. For threshold smells, no, and it is the wrong tool. Method length, parameter count, duplication and nesting depth are deterministic measurements - a rule returns the same answer every time at zero marginal cost, which an LLM cannot match on either determinism or price. But feature envy, shotgun surgery and speculative generality require understanding intent, which is where an LLM has a genuine structural advantage over a threshold rule. As of 2026-10-19 no independent benchmark measures smell-detection precision for any AI reviewer, so treat that advantage as plausible rather than proven.

What is the difference between a code smell and technical debt?

A code smell is a symptom; technical debt is the accumulated cost. Smells are the visible, local indications - the duplication, the 400-line method - while debt is the aggregate interest you pay on them in slower future changes. Most tools conflate the two by converting smell counts into a remediation-time estimate and calling the sum technical debt. That conversion is an estimate built on per-rule constants, and it is useful for trending in one codebase over time but close to meaningless as an absolute number or a cross-team comparison.

Should a quality gate block merges on code smell count?

Gate on new smells in changed code only, never on total count. A total-count gate against a mature codebase fails on day one and gets disabled by day three. A new-code gate - the ratchet - is politically cheap because it asks nothing of anyone except that they not make things worse, and it makes the metric monotonically non-increasing without a cleanup sprint. Also keep the severity tiers honest: a smell should rarely block a merge on its own, while a bug or a vulnerability should. Mixing all three into one threshold is how quality gates lose credibility.

What tools are best for code smell detection in 2026?

SonarQube treats code smell as a first-class issue category with rules for duplication, method length, class size, complexity and magic numbers across 35-plus languages, and its quality gates can gate new code specifically. DeepSource runs 5,000-plus deterministic analyzers with Autofix for many structural findings and is now a Harness product following the 9 September 2026 acquisition. Sourcery proposes concrete refactors in pull requests with the deepest Python support at $12/seat/mo Pro. CodeScene is the differentiated one - it ranks debt by change frequency rather than count. Codacy aggregates duplication and complexity across 40-plus languages.

Explore More

Free Newsletter

Stay ahead with AI dev tools

Weekly insights on AI code review, static analysis, and developer productivity. No spam, unsubscribe anytime.

By subscribing you agree to receive the weekly newsletter. Unsubscribe in one click, any time. See our privacy policy.

Join developers getting weekly AI tool insights.

Related Articles