# Code smells

> Surface signs — long functions, data clumps, feature envy, shotgun surgery — that hint at a deeper design problem worth refactoring.

Concept · Code design · https://levelcode.org/concepts/code-smells

A **code smell**, a term coined by Kent Beck and popularised in Martin Fowler's *Refactoring*, is a surface feature of code that usually indicates a deeper problem. It's a prompt to look closer, not a rule: sometimes a long function is the clearest way to express a long algorithm.

## The smells you'll meet most

| Smell | Looks like | Usual refactoring |
| --- | --- | --- |
| Long function | Comments labelling sections; scrolling to read | Extract function |
| Long parameter list | `f(a, b, c, d, e, true)` | Introduce parameter object |
| Flag argument | A boolean that switches behaviour | Split into two functions |
| Duplicated knowledge | The same rule in several places | Extract and give it one owner ([DRY](https://levelcode.org/concepts/dry)) |
| Data clumps | The same fields always travel together | Extract a type |
| Primitive obsession | Money as `float64`, IDs and emails as bare strings | Introduce a [value object](https://levelcode.org/concepts/value-objects) |
| Feature envy | A method uses another type's data more than its own | Move the method |
| Message chains | `a.B().C().D()` | Hide the delegate ([Law of Demeter](https://levelcode.org/concepts/law-of-demeter)) |
| Shotgun surgery | One change edits many files | Move related code together |
| Divergent change | One file changes for many unrelated reasons | Split by responsibility |
| Repeated switch on type | The same `switch kind` in several places | Replace with polymorphism |
| Speculative generality | Hooks, parameters and interfaces nobody uses | Inline or delete ([YAGNI](https://levelcode.org/concepts/yagni)) |
| Dead code | Unreachable branches, unused functions | Delete it |
| Comments explaining confusing code | `// this is tricky because...` | Rename and restructure until the comment is unnecessary |

Many smells are [coupling and cohesion](https://levelcode.org/concepts/coupling-and-cohesion) problems seen from a different angle: shotgun surgery is low cohesion, feature envy is behaviour living away from its data.

## Responding to a smell

1. **Confirm it matters.** Is this code changed often? Is it causing bugs? A smell in code nobody touches can wait.
2. **Get it under test** — characterization tests if necessary.
3. **Refactor in small, behaviour-preserving steps**, running tests after each one.
4. **Keep the refactor separate** from feature or bug-fix commits.

Linters catch some smells mechanically — long functions, too many parameters, cyclomatic complexity, unused code (golangci-lint in Go, ESLint in TypeScript). The rest need a reviewer's judgment. The [refactoring lesson](https://levelcode.org/roadmaps/software-engineer/refactoring) works through several in Go.
