code-smell-detector
Installation
SKILL.md
Code Smell Detector
A smell is not a bug. It's a structural property that makes bugs more likely later. The code works today; the smell is about tomorrow.
Smell catalog — ranked by how often they actually matter
| Smell | Detection heuristic | Why it matters | Fix |
|---|---|---|---|
| Long method | > 40 lines, > 3 levels of nesting | Can't hold it in your head; every change risks the whole thing | Extract method |
| God class | > 15 methods, > 10 fields, or depends on > 8 other classes | Every change touches this file; merge conflicts; nobody understands it all | Split by responsibility |
| Feature envy | Method reads 3+ fields of another object, 0 of its own | The method is in the wrong class | Move method |
| Shotgun surgery | One conceptual change → edits in 5+ files | High coupling; change is expensive and error-prone | Consolidate the scattered concern |
| Primitive obsession | Three strings passed together (street, city, zip) everywhere |
The missing type is the abstraction you need | Introduce parameter object / value type |
| Boolean blindness | Method takes 3+ booleans; call sites look like f(true, false, true) |
Nobody knows what true means at the call site |
Named parameters, enum, or config object |
| Speculative generality | Abstract class with one concrete subclass; interface with one impl; hook method nobody overrides | Complexity paid for, never used | Inline it → dead-code-eliminator |
| Data clump | Same 3+ variables always appear together in signatures | Missing type (same as primitive obsession, across methods) | Introduce a class |
| Message chain | a.getB().getC().getD().doThing() |
Caller knows the entire object graph; any link change breaks it | Tell-don't-ask; hide the chain |
| Duplicated code | Two regions > 6 lines, > 80% similar | Bug fixed in one, not the other | Extract; but see FP note below |