All code is tech debt.
So goes the saying goes. I mean, sure, it’s a glib way of making a point to avoid not-invented-here and adding code for its own sake, but upon close inspection makes no sense as you can just avoid debt by…never writing any code at all.
But, it is true that all technical debt, at least in software, exists in code in some shape or form. Software engineers are familiar with the persistent tension between investing in product advancement, versus investing in technological sustainability and paying down some of that debt. I can even see how the analogy to financial debt and accuing interest kinda, sorta works.
One particularly bad anti-pattern that I see and have experienced a couple of times is this:
- Engineer gets excited about a piece of technology, a language or framework or design pattern that they have to implement.
- They get the okay from their manager and/or other senior engineers to try using it in a self-contained fashion, figuring that at worst, the blast radius is limited.
- The engineer builds the app/service/platform, and proves to themselves the efficacy of their technology choice.
- They go around trying to get others excited about this tech and want to see it applied across the organization, only to be met with a collective ¯\_(ツ)_/¯ and general apathy; people are too busy to want to rebuild their codebase for tangential benefits.
- Frustrated, the engineer leaves, convinced that their colleagues just don’t appreciate their technical chops.
- The app/service/platform built with new-fangled tech is inherited by the team, who want nothing to do with the thing and are happy to let it hum along, as long as it doesn’t break too much.
- Months to years later, someone asks about this thing that’s completely decoupled from the rest of the codebase, and amidst collective sighs, the team starts scoping the work to rewrite it in something they can actually support.
Incidentally, I’ve seen this happen primarily with mid-level engineers, cursed with just enough knowledge and confidence to do maximum damage. Though I guess you can argue that in this case, with a predictable fate of deletion as its denouement, that the code could be categorized as tech debt as it was being written.
The central problem is one of overfitting to a specific problem domain; if a piece of new tech is the preverbial hammer, then some will be drawn to an all-nails view of the world. The disconnect is assuming that code, once deployed and utilized, can be effectively managed from afar—and that may even be true for a while—but eventually succumbs to changing development environments or product requirements. Of course, the most frustrating part is having to clean up someone else’s mess.
Lest I come off high-and-mighty here, I committed this exact sin when I was a mid-level engineer: I wrote a module to write out metadata to disk with COM with TDD methodologies, back when COM was on its way out while TDD wasn’t well-understood. That module ran for a number of years by itself after I left the company and I was strangely proud of having it around, but in hindsight I may have just encumbered my former colleagues with deferred technical debt.
Things like this have made me more conservative over the years, seeing how enabling someone’s technical indulgences can cause frustration down the road. One solution I try to employ now is insisting that an engineer get buy-in for their tech from the get-go, making sure that approval is contingent on multiple viable use cases around the codebase, ideally creating advocates along the way.