People ask me for a lot of advice on what to do about technical debt. Here some things I’ve learned about how and when to prioritize fixing bad code:
1. Distinguish global vs local problems.

Local problems are things like a poorly-implemented module—it slows you down if working on that module, but is fine otherwise. Global problems are things like “we use database transactions wrong” that infect everything.
2. Fix local problems the next time they get in your way.

(i.e. trust that they’ll get solved eventually by a “make the change easy, then make the easy change” process.) Leave TODOs in the code, deprecate methods, etc. as breadcrumbs for anyone else who might want to fix.
3. For global problems, rank by: how fast is it getting worse? (How high-interest is the debt?)

Agree on a time budget (e.g. X% of eng time). Spend that time going down the list in order.

It’s ok to temporarily be over/under budget, as long as it evens out over time.
4. Decouple “stop the bleeding” from “fix everything.”

You can often solve the “gets worse over time” / “causes ongoing pain” parts much more cheaply than fully fixing the problem. Look for these opportunities; they’re great ways to get more leverage out of your time budget.
Wave example: we had a bunch of badly-written unit tests. Instead of rewriting them all at once, we started a second unit test suite with better infra + conventions and set a rule “all new tests go in the new suite.” Then we gradually ported old tests as needed.
At some point you do actually need to finish these migrations, otherwise they impose a confusion tax on everyone forever. But if you fix the bleeding asap first, you’ll lose a lot less blood overall :)
5. For global problems, spend more time than you think on “thinking real hard:” http://benkuhn.net/thinkrealhard/ 

The days you spend on design will determine the outcome of weeks/months of migration effort, so the leverage of additional (productive) hard thinking up front is high.
Two other corollaries:
1. The trickiest part of fixing a global problem is the migration path. This often ends up being the main thing my designs solve for.
2. The most important skill for fixing tech debt is being good at extrapolating the consequences of your design decisions.
Ultimately, of course, avoiding bad code comes down to thinking carefully and putting in the work. But the above framework helps me focus my attention on the few most important problems, without being distracted and overwhelmed by the massive space of potential things to do!
You can follow @benskuhn.
Tip: mention @twtextapp on a Twitter thread with the keyword “unroll” to get a link to it.

Latest Threads Unrolled: