Skip to content

Reading Code Smells

You now know how to refactor safely. The missing piece is knowing what to refactor and when. The answer is code smells: surface signs that something underneath may be poorly structured. The word smell is deliberate — a smell is a hint that invites a closer look, not a rule that demands action. Sometimes the smell is fine in context. The skill is learning to notice the smell and then decide.

flowchart LR
  S["Code smell<br/>(a hint, not a rule)"] --> J{"Worth it<br/>right now?"}
  J -->|yes| R["Pick a matching<br/>refactoring"]
  J -->|no| N["Note it,<br/>move on"]
  R --> T["Small step → test → commit"]
A smell is a hint: notice it, judge whether it is worth fixing now, then take small steps

Here are the smells you will meet most often, each paired with the refactorings this course teaches to address it. Treat this as your map: when something feels wrong, name the smell, then look up the move.

SmellWhat you noticeWhere this course addresses it
Long FunctionA function that scrolls off the screen and does many thingsComposing MethodsExtract Function
Duplicated CodeThe same fragment appears in two or more placesExtract Function and Moving Features
Mysterious NameA variable or function whose name hides its purposeExtract Variable
Large ClassA class hoarding too many fields and responsibilitiesMoving Features
Long Parameter ListA call with so many arguments you lose trackSimplifying APIs
Feature EnvyA method more interested in another object’s data than its ownMoving Features
Primitive ObsessionBare strings and numbers standing in for real conceptsOrganizing Data
Shotgun SurgeryOne small change forces edits scattered across many filesMoving Features
Tangled ConditionalsDeeply nested or repeated branching that hides the logicSimplifying Conditionals
Temporary Field / Inheritance MisuseState used only sometimes, or hierarchies that fight youGeneralization & Inheritance

Here is Primitive Obsession: a raw number is passed around to mean “money,” but nothing stops a caller from mixing it up with a quantity or a temperature. The smell is the bare primitive standing in for a domain concept. The cure — wrapping it in a small type — lives in Organizing Data, but you should learn to smell it now.

// Smell: a bare number means "money" — easy to misuse
function total(price: number, shipping: number): number {
return price + shipping;
}
// Hint of the cure: give money its own type
type Money = { cents: number };
function totalMoney(price: Money, shipping: Money): Money {
return { cents: price.cents + shipping.cents };
}

The wrapped version makes it impossible to accidentally add money to a quantity — the compiler or the type now carries the meaning that the bare number left to chance.

What is a code smell?
Which refactoring most directly addresses a Long Function?
Which smell is shown in the example?
Why name the smell before choosing a refactoring?