Smell (Code Smell)
“A code smell is a surface indication that usually corresponds to a deeper problem in the system.” — Martin Fowler
Context
At the heuristic level, a code smell is a recognizable pattern in source code that suggests (but doesn’t prove) a design problem. Kent Beck and Martin Fowler popularized the term while working on refactoring in the 1990s. Smells aren’t bugs. The code compiles and the tests pass. Something about its structure still makes it harder to understand, change, or extend than it should be.
Code smells matter in agentic coding because agents generate code prolifically, and not all of it is well-structured. When you review agent output, you need a fast vocabulary for naming structural issues. Recognizing a smell lets you say “this function is too long” or “these classes are too tightly coupled” and direct the agent to refactor, without having to articulate a full design critique.
Problem
How do you identify design problems before they become bugs or maintenance crises?
Design problems rarely announce themselves. A function that’s slightly too long works fine today. A class with one too many responsibilities passes all its tests. The damage is cumulative: each small compromise makes the next change slightly harder, until the codebase becomes resistant to modification. By the time someone says “we need to rewrite this,” the cost is enormous. Smells are the early warning system.
Forces
- Working code resists criticism (“if it works, why change it?”).
- Subjectivity makes smell detection feel like opinion rather than analysis.
- Volume of agent-generated code can overwhelm a reviewer’s ability to notice structural issues.
- Refactoring cost discourages addressing smells before they cause pain.
Solution
Learn the common smells and develop the habit of noticing them during code review, whether the code was written by a human or an agent. Fowler’s Refactoring catalogs more than twenty. The ones below come up most often:
Long Method / Long Function. A function that does so many things you can’t hold it in your head. Break it into smaller, named pieces.
Feature Envy. A method that uses more data from another class than from its own. It probably belongs in the other class.
Shotgun Surgery. A single change requires edits in many files. The related logic is scattered and should be consolidated.
Primitive Obsession. Using raw strings, integers, or booleans where a domain type would be clearer. See Make Illegal States Unrepresentable.
Duplicated Code. The same logic in two or more places. When one copy gets fixed, the others don’t.
God Class / God Object. A single class that knows too much and does too much. It violates Separation of Concerns.
Smells are heuristics, not rules. A long function that reads clearly and does one conceptual thing may not need refactoring. A small amount of duplication may be preferable to a bad abstraction. The smell tells you where to look; your judgment decides what to do.
When reviewing agent-generated code, check for these common smells: overly complex class hierarchies (the agent defaulted to enterprise patterns), duplicated validation logic (the agent didn’t extract a shared function), and primitive obsession (strings used where enums would be safer). Agents rarely produce god classes on their own, but they frequently produce long methods and feature envy.
How It Plays Out
A developer reviews an agent’s pull request and notices a 200-line function. The function works (all tests pass) but the developer recognizes the Long Method smell and asks the agent to refactor it into smaller functions with descriptive names. The refactored version is easier to test, easier to read, and reveals a subtle boundary between two responsibilities that the long version had blurred.
A team notices that every time they add a new payment type, they must change code in seven files. They recognize the Shotgun Surgery smell and consolidate the payment logic into a single module with a clear extension point. Future payment types require changes in one place.
“This function is 200 lines long. Refactor it into smaller functions with descriptive names. Each function should do one thing. Run the tests after each extraction to make sure nothing breaks.”
Consequences
A shared vocabulary of smells makes code reviews sharper. Instead of vague discomfort (“something feels off”), you can name the issue and point to a known remedy. Smells caught early are cheap to fix; smells ignored compound over time.
The risk is smell-driven refactoring without purpose. Not every smell needs fixing. Refactoring code that’s stable, rarely changed, and well-tested may not be worth the effort. Use smells to prioritize: focus on smelly code that’s also frequently modified. That’s where the return on refactoring is highest.
Related Patterns
- Refined by: Smell (AI Smell) — AI smells are a newer category of smell specific to model-generated output.
- Uses: KISS — many smells are symptoms of unnecessary complexity.
- Uses: Separation of Concerns — concern violations produce many common smells.
- Enables: Make Illegal States Unrepresentable — primitive obsession is a smell that this pattern resolves.
- Enables: Local Reasoning — fixing smells often restores the ability to reason locally.
- Related: Premature Optimization – optimized code nobody understands is a smell.
- Related: Technical Debt – smells are visible indicators of underlying debt.
- Enabled by: Coding Convention — convention violations are often the first smells a reviewer notices.
- Contrasts with: Best Current Practice – yesterday’s best current practice can become today’s code smell when the context changes.
- Used by: YAGNI – speculative generality is a recognized code smell that YAGNI cites when pushing back on unnecessary features.
Sources
- Kent Beck coined the term “code smell” in the late 1990s while helping Martin Fowler with Refactoring. The metaphor — something that doesn’t look wrong but smells wrong — gave developers a shared vocabulary for structural intuition.
- Ward Cunningham’s WikiWikiWeb (c2.com, also called WardsWiki) is where the concept was first discussed publicly. The CodeSmell page there served as the community’s working notebook through the late 1990s and early 2000s and seeded much of the refactoring vocabulary that later appeared in print.
- Martin Fowler and Kent Beck catalogued twenty-two code smells and their remedies in Refactoring: Improving the Design of Existing Code (Addison-Wesley, 1999; 2nd ed. 2018, with contributions from William Opdyke, John Brant, and Don Roberts). Chapter 3, “Bad Smells in Code,” co-authored with Beck, remains the canonical reference for the concept.
- Martin Fowler’s bliki entry “CodeSmell” (martinfowler.com, 2006) is the source of the epigraph’s surface-indication definition and the short-form treatment most practitioners quote today.
- Arthur Riel formalized the “God Class” anti-pattern in Object-Oriented Design Heuristics (Addison-Wesley, 1996), identifying the tendency of procedural-minded developers to concentrate behavior in a single controller class.
Further Reading
- Sandi Metz, 99 Bottles of OOP (2018) — a practical demonstration of identifying and addressing smells through incremental refactoring.