Some engineers believe they have to go to great lengths to eliminate every single piece of technical debt in their codebase. This focus on perfection ignores the cost of fixing debt, the risk of introducing new bugs and contagion (the chances of debt spreading).
As is with real-life decisions; not everything is black and white; there are a few grey areas. And experienced engineers are always making judgement calls.
That time I needed to borrow
A long time ago I was in a fix: I needed to make two huge capital expenses simultaneously: my first car and an expensive trip abroad. Alas, I only had liquid funds to cover about 75% of the total capital outlay required.
I initiated a sale of some of my non-liquid assets to raise the balance but I needed to make quick payments before the sale went through. Ultimately I had no choice but to borrow until the sale finalized.
You might be forced to borrow
Ideally, I wouldn’t have borrowed the money but I had a valid pressing need. Similarly, sometimes software projects have to borrow from the bank of technical debt. This is fine provided you immediately pay off the debt as soon as possible.
But not all nits need to be fixed. I used to be quite fastidious about small issues in code but over time, I have come to realize that not everything niggle has to be refactored.
To refactor or not to refactor: that is the question
I recently had to fix a minor issue in some old codebase, a benign exception was causing errors to be logged in our pipeline. These red-herring errors, which required investigations, had become a drain on our on-call engineers.
After fixing the nit; I looked around the code and wanted to make more changes. The code was bloated, relied on a few deprecated libraries and could be refactored. However, the 1-year-old codebase was extremely stable, used by every single code path and worked reliably all the time.
Thus, it came down to a Pro/Con evaluation.
Pros
- Cleaner code
- Maybe a small performance gain
Cons
- The possibility of breaking the entire product completely coupled with a slow turn-around time since this is a shared library.
- Expensive follow-up work to adopt the new version (new interfaces, new signatures etc.)
- Little or no extra code benefit to customers
The risks outweighed the benefits significantly. Moreover, since that code base wasn’t in active development; there was little chance of the bloat spreading around. Consequently, I shelved my cosmetic refactoring plans: those hours could be spent more effectively on higher-impact bugs/issues.
Conclusion
Before you fix that nit; consider the following:
- Cost
- Risk
- Contagion
- Return on Investment
✌️
You might also enjoy this excellent article: A Taxonomy of Tech Debt
In my brief, annoying phase as a COBOL programmer, I ran into tons of stuff that needed work – even apparently dead code. I learned very quickly to let sleeping dogs lie! Many systems are so complicated (I was going to say complex,but remembered your other article ;) ), it’s almost impossible to know if refactoring might subtly alter the semantics and cause unforeseen problems for some corner case (that would then be *my* problem – that I might have no idea how to fix!)
I laughed when I saw that “old” meant over a year! Some of the stuff I had to deal with was many years old with none of the original authors around any more.
BTW, I had to look up “technical debt”. The concept was quite familiar, but I had never seen the term before. It’s a good one.
Nit: Your second paragraph “nothing everything” should probably be something like “not everything”.
LikeLike
You wrote COBOL! Amazing!! I really like your phrase: “let sleeping dogs lie”; that does cover the theme of this blog post aptly.
Thanks for pointing out the typo too. 🙂
LikeLike