Glossary · Code health

What is a code smell?

A code smell is a surface symptom in source code that hints at a deeper design problem, without being a bug itself. The term comes from Kent Beck and Martin Fowler's 1999 book Refactoring. Examples are a long method, a large class, duplicated code, feature envy and shotgun surgery. Smells tell you where to look, not what is broken.

Last reviewed: November 2026

Also called Bad smell, Design smell, Anti-pattern

How a code smell is measured

A smell is a judgment, but most have a measurable proxy:

SmellTypical proxyCommon starting threshold
Long methodLines of code (NLOC) per function50 to 60 lines
Complex methodCyclomatic complexity10
Deep nestingMaximum nesting depth4
Large classLines or method count per class200+ code lines
Duplicated codeMatching token sequences across files6+ lines in a clone
Long parameter listParameter count5
Shotgun surgeryFiles that co-change with many othersfrom git history
Feature envyCalls to another class vs own classneeds a call graph

Take a method of 140 lines, CCN 18, nesting 5, with 7 parameters. That one function trips four proxies at once: long method, complex method, deep nesting and long parameter list. The refactoring that fixes one (Extract Method) usually fixes the rest, which is why smells cluster and why counting them as separate problems overstates the work.

Thresholds are conventions, not laws. Fowler and Beck deliberately gave no numbers; the book says that no set of metrics rivals informed human intuition.

Why code smells matter

Smells matter when they sit in code that keeps changing. A smell makes each edit slower (the reader must untangle the code first) and riskier (more behavior is coupled in one place). A god class or a duplicated block that nobody touches is not worth a refactoring sprint. The same smell in a file changed every week is a recurring cost, and that is where technical debt accrues interest. Smells also differ in how strongly they predict defects. In repowise's own validation, low cohesion, duplicated code and broad error handling fire often but predict bugs weakly, so they are down-weighted in the defect score and counted in full only in maintainability.

How to measure code smells yourself

  • Multi-language rule engines: SonarQube (or SonarLint in the editor) and PMD for Java and others.
  • JavaScript and TypeScript: ESLint rules such as complexity, max-lines-per-function, max-depth and max-params.
  • Python: Pylint (too-many-arguments, too-many-locals), Ruff's complexity and argument-count rules, radon cc for complexity.
  • Duplication: jscpd works across many languages.
  • Change coupling and churn: plain git log, or a code-hotspot tool, because shotgun surgery is visible in history, not in a single snapshot.

For rule-based smells on one snapshot, these linters are the right pick and are free. They do not rank smells by how often the file changes.

How repowise measures code smells

repowise treats smells as scored findings from deterministic detectors (no LLM) and folds them into the per-file code health score. The smell-like ones, with thresholds read from the source:

Classic smellrepowise detectorFires when
Long methodlarge_method60+ code lines and CCN 3 or more; critical at 200
Complex methodcomplex_methodCCN 9 or more
God class / large classgod_class200+ code lines, 15+ methods and a brain method (NLOC 70+, CCN 9+)
Brain methodbrain_methodNLOC 70+, CCN 9+, in a central file (advisory, not scored)
Divergent change / low cohesionlow_cohesionLCOM4 of 2 or more with 5+ methods
Duplicated codedry_violation8% of a file duplicated with a 6-line clone, across files; hidden from default surfaces
Long parameter listprimitive_obsession5+ parameters (7 for constructors), mostly primitive types
Shotgun surgeryco_change_scattertop fifth of the repo by co-change breadth, 3+ commits in 90 days
Deep nestingnested_complexitynesting depth 4 or more
Complicated conditioncomplex_conditional3 or more boolean operators

Feature envy is covered by the Move Method refactoring plan, which proposes moving a method to the class it works with. A low score means look here first, and the file's change history decides the order.

Where to see them: repowise health, repowise health --file <path> and get_health over MCP, or the code health feature page. Refactoring plans (Extract Method, Extract Class, Move Method, Split File, Break Cycle) name the exact symbols; generate_refactoring_code is an opt-in MCP tool that uses your LLM, and repowise never applies an edit itself. Related: temporal coupling is the history signal behind the shotgun-surgery row.

FREQUENTLY ASKED

Code smell: questions

What are examples of code smells?

Long method, large class (a god class), duplicated code, long parameter list, feature envy (a method that uses another class's data more than its own), shotgun surgery (one change forces edits in many places) and primitive obsession. Fowler and Beck's Refactoring catalogued 22 of them in 1999.

Is a code smell a bug?

No. Smelly code usually works. A smell is a sign that the design makes bugs more likely or changes more costly. Some smells, like swallowed exceptions, sit closer to bugs than others, like long parameter lists.

How do you detect code smells?

Run a static analyzer: SonarQube, PMD, ESLint, Pylint or Ruff for rule-based smells, and a clone detector such as jscpd for duplication. Rule-based tools find shape problems; some smells, like feature envy, need judgment or a call graph.

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

A smell is an observable sign in the code. Technical debt is the accumulated cost of leaving such problems in place. Smells are how you notice debt, but a smell in code nobody changes costs little.

See it on your own repository.

Index a repository free and read the result for your own code and history. Rolling it out to a team? We will walk you through it.