I am likely on the minority “agree” end of the non-existent poll for this statement. It clearly is a “thing” to most people but I am sitting here writing this in a state of humble hopefulness that I can convince you, reader, that what software people call tech debt is really no such thing.
The conception of tech debt, I believe, comes from what we as coders/programmers/SWE think we are doing when we are writing our code. The Assembly programmer is hyper-aware of what they are doing. They are telling the computer, instruction-by-instruction, what to do (incredible stuff). The JavaScript programmer cannot even be sure if they are adding two numbers or are concatenating a number and a string. This is not a dig towards JavaScript people, bless our hearts. What I am saying is that the mindset of these two programmers is quite different. When writing in a higher level language like JavaScript the thought process is much more abstracted, uncertain at times, and, yes, even poetic†.
I do not hear many Assembly programmers talking about technical debt and the reason for this is not purely a skills issue (though if you write Assembly professionally I Wayne’s World bow to you, I am not worthy.) I believe a substantial part of it is because writing Assembly in a business context necessitates having good requirements. You must be able to plan ahead and know what your code is supposed to be doing before you start such a time consuming and laborious endeavor. Refactoring is not so easy. In other words, Assembly code is costly to produce so it is treated with more care. However, this is also a reason why it is less common and reserved for situations where ultimate performance is required.
Obviously, that is not to suggest that to avoid “tech debt” we all should be writing Assembly, or that we need exacting requirements before starting any project. What I am saying is that when a cracked front end developer whips up a useful UI in a single afternoon that code is much closer to prose than a list of carefully crafted CPU instructions. Decisions about how the UI should look, what was worth spending time on, what to name things, what to copy from elsewhere, etc. were all made on the fly using intuition.
Proponents of the “tech debt” theory would say that this code is now a liability, a debt that is owed on, because in order to meet the time constraint it is certain that decisions were made or steps skipped that will later come to home to roost as problems for future them. The main problem with this line of thinking is that there is a base assumption that perfect and “debt free” code exists. That the original developer should have foreseen the future and concerned themselves with each possibility. I’ve been doing this for twenty years and I have yet to see code that could not be criticized as a liability in one way or another. You may be able to write beautiful code that is precise, fast, and elegant right now, but give it time and things will rot. Platforms evolve, libraries come and go, architectures change, business carries on, tastes change.
† Before I get emails, I am certain incredibly poetic Assembly exists, but I am trying to make a poetic point myself here.
It Really Tied the Room Together
“Tech debt” is actually the living room rug. A place under which we sweep: time crunches, misunderstandings, non-understandings, difficult conversations, changed minds and hearts, and all other sorts of things we wish to avoid as humans who would rather just talk to the computers. Then, when we are fed up with a project, we pull the rug out from under everyone, exposing what is underneath, claiming a bankruptcy that only a court management ordered rewrite can resolve. With the new code things will be perfect this time.
However, what this does in reality is to undermine the understanding management and other non-technical people have regarding software both in general and in regards to your specific project. It feeds the fallacy that software development is black and white, that there is always one right decision. In fact, engineering is about tradeoffs. Tradeoffs that go beyond the technical but also involve mental and social limitations, as well as time limits and financial limits.
Instead of talking about debt we should talk about tradeoffs. The reason service xyz can’t scale right now isn’t because of our immense load of technical debt. It is because when we built it, for the customer that the sales team was working, we realized we could lose the contract if we took the time to write for the more appropriate but complicated bulk API when the simple, single call REST API worked perfectly fine. Now that we’ve sold the product to a giant new customer we need a new version that is built using the bulk API to handle their traffic level.
That “slow” code that isn’t scaling is actually perfectly fine. It is bug free and it does the same thing today it did 2 years ago. The requirements changed. Calling this tech debt is like saying the contractor who built your home 50 years ago is putting you in debt because he didn’t foresee your third, unplanned, child you will now have to build an addition for.
Another common claim of tech debt is that the code has “smells”, is poorly abstracted, doesn’t follow best practices, and myriad of other buzzwords people use to make digs at other people’s code. While it is annoying to read and update code that uses different conventions, patterns, and abstractions than you prefer, and code that doesn’t follow basic best practices can be downright infuriating, we have many modern tools to navigate and even fix these issues automatically (IDEs, LLMs, etc). It may not be pleasant, but it is rarely so bad that the issues can’t be improved or isolated while completing related work. This is what normal maintenance of a code base looks like. It is not correct, nor healthy to think of it as a debt you are repaying with small amounts of maintenance work.
Messy code that functions and people pay for is still not tech debt. It’s tech profit with a side of inconvenience from time-to-time. An indicator of this is that if you spent the time to make the code well structured and pristine your customers will not notice but they will notice that no new features have appeared in a while and no bugs have been fixed.
A mindset that places the highest value on clean code causes what I like to call technical inflation. It is worse than debt because it takes what you have, devalues it for the benefit of no one but the bureaucrats coders, and you are left with something that is in a worse position than before when it comes to the now outdated feature set and neglected bug backlog. As a software team churns over time this cycle will repeat because of differing tastes and opinions.
I cannot cover every situation and I will admit the viral mobile game your ten year old cousin made with ChatGPT will probably need a rewrite at some point (but even then maybe not). Code doesn’t change unless we coders change it. So don’t be frustrated that it doesn’t work the way you want it to today. It worked for the time and place it was written. And definitely do not blame the authors as you were not there when the incantations were written.
P.S. Your goal should be to make your software so useful and profitable that you can afford to hire a second team to do a rewrite We all know how those can go: digg V4, reddit.com (2018), Friendster, Knight Capital Group.