A code smell, a term popularized alongside the refactoring catalog discussed elsewhere on this shelf, describes a surface-level pattern in code that doesn't necessarily indicate a bug or incorrect behavior, but correlates strongly enough with deeper design problems to be worth investigating. A long function, duplicated logic, a class that seems to know too much about another class's internals — none of these is automatically wrong, but each shows up disproportionately often in code that turns out to have a real underlying problem. Common warning signs are organized in the Refactoring.Guru code-smell catalog.
Why “smell” is a deliberately soft word
The word choice is doing real work: a smell is a signal worth investigating, not a violation to automatically flag and fix. This distinguishes code smells from lint rules or style violations, which are typically binary and mechanically enforceable. A smell asks for judgment — is this specific instance of duplication actually a problem, or is it two pieces of code that happen to look similar today but represent genuinely different concepts that will diverge tomorrow, in which case eliminating the duplication would create an incorrect coupling that wasn't there before. Measurement systems invite gaming when the proxy becomes the target; here catalogs common examples in time tracking.
This is the most common misapplication of the concept: treating a catalog of named smells as a checklist to mechanically eliminate everywhere they appear, rather than as a set of prompts for judgment about a specific piece of code in its specific context. Two files with similar-looking code aren't automatically a duplication problem; whether they should be unified depends on whether the similarity reflects a real, shared concept or a coincidental resemblance.
A few smells worth knowing by name
Some of the most commonly cited smells earn a place in a shared vocabulary because they're genuinely common and genuinely worth a second look: Long Method (a function that's grown to do too many distinct things, making it hard to test or reason about in isolation), Feature Envy (a piece of code that seems more interested in another object's data than its own, suggesting the logic may belong elsewhere), Shotgun Surgery (a single conceptual change that requires touching many different files, suggesting the concept is scattered across the codebase rather than concentrated in one place), and Primitive Obsession (using raw strings, numbers, or booleans to represent concepts that deserve their own explicit type).
- A smell is a prompt for investigation, not an automatic defect — the judgment call about whether to act on it is the actual skill.
- Named smells are useful primarily as shared vocabulary — they let a team discuss a specific concern precisely instead of vaguely.
- Duplication should be evaluated by whether it reflects a shared concept, not just visual similarity — coincidental similarity is a trap, not a smell worth fixing.
- A smell that shows up repeatedly in the same area of a codebase is a stronger signal than a single, isolated instance — frequency and clustering matter as much as the individual case.
The limit of smell-based thinking
Code smells are a diagnostic vocabulary, not a design philosophy on their own — they're good at flagging where to look, and much less useful for deciding what to do once you're looking, which is where the broader design and architecture ideas discussed elsewhere on this shelf actually come in. Treating smell elimination as an end goal in itself, disconnected from a broader sense of what good structure looks like for the specific problem at hand, tends to produce code that satisfies a checklist without actually being easier to work with.
The lasting value of the vocabulary is that it turns a vague unease (“something about this code bothers me”) into a specific, discussable, and searchable concept — which is most of what makes a code review comment useful instead of just a feeling.