Code Smells

Heuristics that point at a possible design problem, each with the case where it is genuinely fine — because a smell is a question, not a verdict.

What a Code Smell Is

A named pattern that raises a question about the design. Roughly half the time the honest answer is "this is fine", and a smell that cannot say when is just taste with a job title.

Q · When a piece of code looks wrong, how do I tell whether it actually is wrong?
God Object

One type with a huge API, a dozen dependencies and a dozen unrelated reasons to change. The finding is the reason count, not the line count — and the fix is rarely a six-way split.

Q · One class is 3,000 lines and everyone touches it. Is that the problem, or a symptom of one?
Shotgun Surgery

One requirement, seven modules, none of which is about that requirement. The code is not badly written — the knowledge has no owner, so every consumer had to learn it.

Q · Why does a one-sentence business change reliably touch six unrelated packages, none of which is named after it?
Divergent Change

One module, many unrelated reasons to change. The exact dual of shotgun surgery: there the knowledge had no home, here one home holds knowledge that does not belong together.

Q · Why is this one file in every pull request, no matter what the pull request is about?
Feature Envy

A function that reaches into another module's data far more than its own. Sometimes the behaviour is in the wrong place; sometimes the other module is a value type and this is exactly right.

Q · This method uses six fields of another object and none of its own. Does the behaviour belong over there?
Primitive Obsession

Money as `number`, email as `string`, a user id as `int`. Meaningful types move a class of mistake from runtime to compile time — and not every string needs a wrapper.

Q · Which of these strings and numbers deserve a type of their own, and which are fine as they are?
Long Parameter List

Eight arguments, four of them booleans. Bundling them into a parameter object makes the call site tidier and changes nothing — the finding is usually a concept that has no name.

Q · This function takes nine arguments. Is the fix a parameter object, or is something missing from the model?
The Utility Dumping Ground

`utils.ts` is not a module, it is the absence of one. Its contents are the pieces of the domain nobody could find a home for, and it grows because it never says no.

Q · Why does every codebase grow a `utils`, `common` or `shared` module, and what is actually wrong with it?
Duplicate Knowledge

Two identical blocks may not be the same concept, and two blocks that look nothing alike may encode the same rule. Textual similarity is the wrong test, and it is the one everybody uses.

Q · These two blocks are identical. Should they be one — and what about the two that are completely different but always change together?