The Real Costs Of Putting Off Technical Debt
May or may not have been inspired by real events
The most dangerous tech debt is one that has been written many years ago. Nobody understands how that piece of code actually works and why it was written as it was. There's no way of contacting the person who wrote it. And issues with it pop up right before a huge release that has been in the works for many months. Even worse if you have a hard deadline that has only very little room to shift.
Now you're in a position of solving issues that have been lying there for years without anyone noticing or caring. And you need to fix them fast as each day of delay has a real monetary (or even worse, legal) cost. It's likely also an issue that you cannot simply throw developers at and solve faster.
Let me list some risks that I consider to be major ones.
Risk #1 — Engineers Will Get Frustrated And Leave (Engineers Are People Too)
For me, this is a major one. I've worked with many engineers over the years, and one thing was true about most of them. They really cared about what they were delivering. It might've been a personal pride, or they just really cared about the product (or the company itself) and wanted it to succeed. But at the end of the day, they're the experts in their field. They know best what the real implications are. So if they are forced (even by external forces that nobody can really change) to deliver even over piles of tech debt, they'll not be happy.
If you force an engineer to deliver a product no matter what, you may be satisfied with the facade of the product, but the engineer is perfectly aware of all the things that are wrong with it. The engineer understands that they did not have the resources to deliver their best, and now all the tech debt accommodated in the codebase is there with their names attached to it. Any new engineers can look through the code and see who is responsible for that specific code.
As said in the title of this point, engineers are people too. And now the engineer was forced to have their names on a piece of code that they know how to design better, but they didn't have the resources to. So they're left to justify their decisions to every person who reaches out to them. And even if they did their best in a bad situation, they still may end up feeling guilty for it. And that's not a healthy place to be at.
Every now and then, I get asked about a certain line of code that I wrote 3 years ago while working very hard on delivering on a deadline. And it's okay to question things; that's how things get better. But it does have a real emotional cost when an engineer isn't able or has not enough resources to fix what they know is wrong.
All of which will result in either of two things. Either the engineer will leave the company for something better. Or the engineer will break and stop caring about delivering their best as they already know it's no use. If you're running a company, you don't want either of those things. Because either way, you're losing talent and money. And your product is suffering with it even if you might not see that yet underneath that good-looking facade.
Risk #2—Delivering A Product Full Of Bugs And Unexpected Behaviours
Even if you manage to keep your engineers happy and satisfied, you still have the product to consider. The tech debt lives below the surface of it. You may not even know about it for a long time. But it re-surfaces now and then and creates ripples. If it stays at the ripples, you may be okay with it, it's just an occasional annoyance, but nothing breaks so far. But as with anything, the longer it's ignored, the bigger it will grow. You'll end up with a hurricane of things going wrong.
That can eventually put you in a dangerous position. When you give your product to the user, they have the freedom to do whatever the product allows. Which could be something you did not intend to. In some cases, it may allow them to access features they shouldn't be allowed to (either paid features or features that have not yet been released and are supposed to be hidden). Or you'll show them something in the interface that will end up behaving very differently than expected. In either case, you're putting your user in a position of having an experience that's inconsistent with what they expect.
The user may even not understand where their frustration with the product is coming from exactly. But they'll know perfectly well that they're dealing with a product that wasn't built well. Now it's up to the value & cost ratio for each individual user. Is the product really that necessary for them that they're okay with dealing with all the frustrations it contains? And again, here it's up to the balance between the two. Building a perfect product is an impossible task. That's made even harder if you have internal problems to deal with like tech debt.
Risk #3-New Features Take Longer To Build; Bugs Take Longer To Be Fixed
And as you keep delivering while ignoring tech debt, each new feature is going to take longer to build. The added time may be minuscule initially, but the larger you go with your projects and the more you have to rely on old code *just* working, the more risk you're adding to any new projects or features you try to take on.
And as your projects grow, your team will likely grow also. Engineers know well enough that dealing with legacy code is very often a frustrating experience. Especially if it was written in a hurry and lacks good documentation. This code will take longer to understand for any new people who've never seen it before. And even for the person who wrote it, it will take more time to jump back on it and be productive with it.
This will eventually manifest in longer time estimations for even the smallest changes and features. If building one thing would take a week before, after a year the estimation may shift to be two weeks and a half or even longer. This can go unnoticed for a long time. It may even make it seem that the team is becoming less productive and unless it's identified that the reason for it is technical debt, the team may take the blame. That's a very unpleasant position to be in and may lead back to mentioned Risk #1.
If this becomes the problem, everybody will be dissatisfied. Engineers may end up angry at the fact they didn't have the resources to fix what they knew was wrong. And everyone else will be bothered by the fact that even the smallest of features get delivered very slowly.
Risk #∞ — Uncertainty
That's what it really comes down to. Uncertainty. You may have assessed all the risks of tech debt, and you may have done so well and responsibly. What if there's a tech debt that wasn't considered at all? As I mentioned at the beginning of this article, there are many cases where you don't have access to someone who wrote some code that is now breaking. And you can't ask them why they wrote that code in that particular way. Or there's a design decision that doesn't seem to make sense. But what if it was intentional and seems odd only because you don't have access to the whole context?
It's generally better to be on top of things. Understand how things in your product work and be aware even of the uglier aspects of it. Even if there's a bad technical solution in your codebase, it's better to have it in the back of your head instead of ignoring it completely.
When you clearly identify the possible risks, it will also be easier to communicate them to anyone who needs to hear about them. Whoever that may be.
With that, we get to the solution. That's the most uncertain thing about all this. There's no single solution to tackling tech debt and each scenario you face will be different. There are only ways to minimize the risks and try to do your best when it comes to communication. Especially if ignoring tech debt is an internal decision, communication will be the key.
There are even situations where accumulating tech debt is the only way to go forward and therefore necessary to mitigate other risks. Potentially business risks. That could be uncomfortable but desirable from the business point of view. But it's important to understand completely that you're opening doors and windows to other risks that you probably want to describe as clearly as you can before accepting them.
In conclusion, many forms of tech debt were not mentioned here. For example, there's poor tech design that exists just for the sake of speed. Lack of testing or documentation is certainly a form of tech debt as well. There may even be a tech debt in the lack of structure in the team. Each one of which would deserve a very cautious consideration on its own. My aim here was to outline what I see as some of the main risks from my personal experience. I hope this will help somebody assess their decisions on the risks.
Whether you agree or not, I'll be happy to hear from you and keep the conversation going. This is a big topic, and I cannot handle all of it in an article; it has to be handled in a conversation. In the best-case scenario, in a very open conversation with your team directly.