Everyday Programmer
Field Notes

The Highest-Impact Fix Isn't Always the Ugliest Code

Technical debt should be prioritized by user impact and operational risk — not by which file looks worst in review.

2 min readfield notes, technical debt, refactoring
Illustration for "The Highest-Impact Fix Isn't Always the Ugliest Code" — Everyday Programmer

The ugliest file in the codebase is rarely the most expensive one.

When I inherited a sprawling business dashboard, the obvious candidate for refactoring was a 1,400-line React component everyone complained about. But before touching it, we listed every defect and complaint the product had accumulated over two quarters and traced each back to its source.

The 1,400-line component? It caused one bug. A boring, 60-line filter utility — the kind of code nobody ever opens unless something breaks — caused a third of them.

Visible debt versus expensive debt

Debt you can see (long files, copy-pasted JSX, legacy patterns) is easy to point at and satisfying to fix. Debt that costs you something — incidents, support tickets, slow releases, lost conversions — hides in ordinary-looking code.

The distinction matters because refactoring capacity is always finite. Every week spent beautifying a stable monolith is a week not spent eliminating the thing that pages you at 2am.

What actually determines impact

Four factors, roughly in order:

  1. User impact — how many users hit the code, and how badly it hurts them when it misbehaves
  2. Operational risk — blast radius of failure: does a bug annoy, block, or corrupt?
  3. Change frequency — hot code accumulates debt faster than frozen code
  4. Remediation cost — what the fix costs in time and regression risk

A scorecard you can reuse

Score each debt candidate 1–5 on every dimension and multiply:

debt-scorecard.txt
text

The mobile checkout UX scored highest despite looking perfectly fine — it just quietly cost conversions. The famous 1,400-line component scored lowest. We fixed the scorecard order, not the eyeball order.

Stabilize first, structure later

When the top item is structurally awful, resist rewriting it in one heroic PR. Stabilize with tests around current behavior, then migrate boundaries incrementally. That pattern is exactly how I'd approach the big component — which is its own story: How I Would Rescue a 1,400-Line React Component.

The scorecard won't make debt disappear. It makes the order defensible — which is what senior engineers are actually paid for.

Keep reading

Related articles