Yashveer Singh
Connect
<- All posts
Tech Debt and Refactoring12 min read

Code Smells That Predict Tech Debt

Code smells are patterns in code that suggest deeper problems. Not all smells matter. The ones that reliably predict tech debt are specific. Functions that grow without breaking up. Files that everyone has touched. Tests that are skipped. Try catch blocks that swallow errors. Configuration that lives in code. The teams that treat these specific smells as warnings and address them early avoid the larger debt that they predict.

Written by Yashveer Singh, founder of Yashveer Labs.

What you actually need to know

  • A handful of specific smells reliably predict tech debt.
  • Files that everyone has touched are the strongest predictor.
  • Long functions that grow over time. Swallowed exceptions. Magic numbers. Configuration in code. Skipped tests.
  • Treat smells as warnings, not preferences.
  • The cost of treatment compounds. Early is cheap. Late is expensive.
SmellWhat it predicts
File touched by everyoneJunction box failures
Function that grows over timeRefactoring debt
Swallowed exceptionsHidden bugs
Magic numbers and stringsBugs from name confusion
Configuration in codeInflexibility at scale
Skipped testsRegression risk
Comments explaining workaroundsBrittle dependencies
Duplicated logic with slight differencesFuture divergence

The core argument

Code smells are noisy as a category. Some smells are real warnings. Many are matters of style. The teams that treat every smell as urgent burn out on cleanup work. The teams that treat no smells seriously accumulate debt that eventually requires a major refactor or rewrite.

The discipline is to learn which smells reliably predict actual pain. The list is shorter than the textbook list. Files that everyone has touched. Functions that have grown without decomposition. Try catch blocks that swallow errors. Magic numbers without names. Configuration that lives in code. Skipped or commented out tests.

Each of these has a high signal to noise ratio for predicting future pain. The file that the whole team has touched is the next regression site. The function that has grown is the next bug source. The swallowed exception is the next hours long debugging session. The magic number is the next time a behavior changes mysteriously and nobody can find where.

The cost of treating these smells when they appear is small. A few hours per occurrence. The cost of treating them after they have compounded is large. Days to weeks of refactoring. The math favors the early treatment.

The smells and their fixes

SmellFix
File touched by everyoneDecompose along the actual concerns
Function that grew over timeExtract methods. Apply single responsibility
Swallowed exceptionLet it propagate. Handle it deliberately at the right level
Magic numberNamed constant or enum
Configuration in codeExternalize to env var or config file
Skipped testFix the underlying issue or delete the test
Comment explaining workaroundAddress the workaround if possible
Duplicated logicExtract the shared part or commit to divergence

How much does this cost

The cost per smell treated is small. A few hours to refactor a function. An hour to externalize configuration. A few minutes to name a constant. The ongoing cost is the discipline to treat them as they appear rather than as they accumulate.

The savings show up later. The bug that did not happen. The refactor that was small instead of large. The investigation that took minutes instead of days.

Features the smell discipline must have

  • Linter rules for the smells that can be detected.
  • Code review checklists that include the priority smells.
  • Quarterly tech debt audits.
  • A budget for tech debt work in every sprint.
  • A clear distinction between style and signal smells.
  • A list of approved exceptions where the smell is acceptable.

Expert opinion

The teams that ship the cleanest code do not treat every smell as urgent. They learn which smells reliably predict pain and treat those as warnings. The discipline is selective and ruthless. The result is a codebase that ages well because the genuine problems were caught early and the noise was ignored. The teams that treat every smell as urgent burn out and stop treating any of them.

>

Yashveer Singh, founder of Yashveer Labs

How this played out on a real project

A client codebase had accumulated technical debt that was slowing the team. The founder wanted a cleanup pass. We started with the smells that reliably predict debt rather than the textbook list of all smells.

The audit found four hot files that the whole team had touched in the previous quarter. Each was a junction box for multiple concerns. We decomposed them into focused modules. The regression rate in those files dropped dramatically over the next quarter.

We found seventeen try catch blocks that swallowed exceptions. Most of them were silent for years. We let the exceptions propagate to a central error handler. Three new bugs surfaced in the first week because the team could finally see them. All three were fixed quickly.

We found roughly forty magic numbers in critical paths. Each got a named constant. The codebase became readable in a way it had not been before.

The total cleanup took six engineer weeks across three engineers. The velocity improvement over the next quarter recovered the investment within months. The team adopted the smell discipline as ongoing practice.

For more on the related work, see the cost of tech debt a founders worst bill and when to refactor an MVP and when to throw it away.

Common mistakes teams make

  1. Treating every smell as urgent.
  2. Ignoring the smells that reliably predict pain.
  3. No quarterly tech debt audit. Debt accumulates.
  4. No budget for cleanup work. Sprints are pure features.
  5. Treating style preferences as smells.
  6. Letting the file that everyone touched become the architecture.
  7. No linter for the smells that can be automated.
  8. No documented list of acceptable exceptions.

A 30 day plan to put smell discipline in place

  1. Week one. Audit the codebase for the priority smells. Score the hot files.
  2. Week two. Set up linter rules for the smells that can be automated.
  3. Week three. Refactor the three worst hot files.
  4. Week four. Establish the quarterly audit cadence and the per sprint budget.

For more on the related work, read the cost of tech debt a founders worst bill and adding tests to a legacy codebase without going mad. On the broader refactor side, big bang vs gradual migration a decision map is the natural next read.

FAQ

Frequently asked

Author

The person behind Yashveer Labs

Yashveer Singh, founder of Yashveer Labs. I build full stack systems for clients who care that the thing actually works two years later, not just on launch day. The arc I am on points at machine learning, AI engineering, and cybersecurity. Everything I write here comes from the codebase, not from a content brief. That is the difference and it shows.

Related reading