Code Smell

Concept

A sign that the structure of some code has gone bad even though nothing is broken, used to decide which part to open up first.

Why it exists

A bug can be proven. Show someone the sequence of clicks that freezes the screen and they see the same freeze. A claim that the structure is bad comes with no such evidence. The code is running fine right now, so there is nothing to point at, and for a long time the whole subject stayed a matter of taste.

The same exchange kept repeating in code review. One person writes "this part seems off," the reply is "off where," and the answer is "it's just hard to read." The conversation ends there. The reviewer can't produce evidence and the author isn't convinced. Code that merges in that state becomes, six months later, a place nobody volunteers to touch.

Code smell is the name given to that vague discomfort. Calling it a smell rather than a defect is the substance of the idea. A smell doesn't say stop; it says open this up and look. By naming a clue instead of a conclusion, it turned a remark people couldn't back up into shared vocabulary.

How it works

A smell works as a clue, not a verdict. The shapes that recur have individual names, so a reviewer can say the name instead of "this seems off" and the author sees the same thing. Five common ones:

  1. Long function — one function has grown to 400 lines. If you can't count at a glance how many different jobs happen inside it, everyone who edits it has to read the whole thing again first.
  2. Duplicated code — the same calculation is copied across four files. When the tax formula changes, all four have to be found and updated, and in practice three get updated and one gets missed. This is what the DRY principle exists to prevent.
  3. A name that doesn't match the behavior — a function called validateUser that also saves. Anyone who trusts the name and calls it triggers a write they didn't intend.
  4. Too many parameters — calling a function requires passing nine values. The caller gets the order wrong easily, and that mistake surfaces as a wrong result rather than an error, so it's found late.
  5. Shotgun surgery — changing one thing means editing seven files. Miss one and that spot alone stays on the old behavior.

Having names doesn't make the boundaries crisp. There is no universal line for how many lines count as a long function, so teams set their own. Put that number into a linter or a static analysis tool and the machine flags candidates ahead of any human, but not everything flagged is worth touching.

What decides that isn't how strong the smell is, it's how often the file gets edited. A 300-line function in a file nobody has opened in a year stays as it is. A 200-line one in a file edited twelve times this quarter is worth the work. A smell charges its price at the moment someone reads or changes the code, and code nobody reads never sends a bill. Which is why edit frequency, not the machine's warning count, is the number worth sorting by.

Where it shows up

The most frequent place is code review. Writing "this is duplicated code, the same calculation appears in three places" instead of "this is hard to read" turns the comment from a preference into an observation, and the author can see what to do about it.

The second is choosing targets for refactoring, the work of changing structure while leaving behavior exactly as it was. The available time is always less than the list of candidates. Named smells turn that into a comparison you can hold a conversation about instead of an argument about whose area feels worse.

The third is inheriting code. When someone takes over an area they didn't build, the first job is working out where the dangerous parts are, and smells serve as that map. A few names can flag in an afternoon what would otherwise take a month of reading to notice, and they also give the person handing the area over a way to say what they already know is fragile without sounding like an apology.

The last is ordinary daily work. The boy scout rule says to leave the code you touched a little better than you found it, and smells are what define the "little." No separate cleanup schedule is needed for the places people's hands already reach.

How it sounds at work

"This function smells a bit. Not now — clean it up next time you're in this area."

Registering it as a problem while making clear it isn't blocking this change.

"Don't just write 'smell.' Name which smell you mean."

Asking for the observed shape to be specified so the comment doesn't read as an unsupported opinion.

"I left it alone at three copies, but you're writing the fourth, so let's consolidate here."

Applying a team threshold: the same smell gets handled once the repetition crosses an agreed line.

At Pagedeck the word lives inside the review screen. When Theo raises one, he adds how many times that spot has been edited. "Long function" on its own reads as taste; "long function, and this file changed twelve times this quarter" reads as a reason to act.

Mia uses the word differently. She doesn't apply it to specific code, only to schedules. When two features of similar size take three days in one area and two weeks in another, she looks at which smells Theo has been repeating about the slow area. If the two stories point at the same place, cleanup goes into the next quarter's plan as its own item.

What people get wrong

The most common mistake is reading a smell as a bug. Tools mark them in red, which makes them look like errors to fix. But code with a smell is behaving correctly, and leaving it alone changes nothing a user can see. Mixing the two wrecks prioritization. When a broken payment flow and a too-long function sit in the same list in the same color, the team works down from the top and gets to the outage late.

Assuming every smell should be removed on sight is the other one. A signal seems like something to clear, which makes the impulse natural. But removing a smell also costs something: every edit is a chance to introduce a new fault, and that risk is identical in a file nobody reads. Teams that decide to clear all 800 machine-flagged items at once usually spend two weeks on it and ship more incidents than usual during those weeks. Whether a fix is worth it comes from how often that code will be read going forward, not from the size of the list.

Easily confused with

TermWhat it refers toHow it differs
Technical debtThe cost that builds up from cleanup that was put offA smell is a signal observed in one spot; debt is the accumulated cost of many such spots. The smell is the symptom, the debt is the invoice

Where to go next

  • Code quality

    see which of the four branches of quality work smells belong to

  • Technical debt

    see what smells grow into when they are left alone

Last updated 2026-09-16