“Technical debt is sort of a natural phenomenon and seeing it emerge can be a sign that people are finding your software useful”
Technical debt is on the mind of every engineering manager and CTO. ‘Borrowing’ time from the future by doing things the quick and dirty way can cause huge problems later. We caught up with Liran Haimovitch to talk about what really is technical debt, how to differentiate it from legacy code and more.
JAXenter: “Technical debt is a romantic metaphor used to cover up for developers’ own stupidity.” Do you agree with this notion?
Liran Haimovitch: I would frame it like this: Technical debt is a real thing, and can be caused by bad design decisions or rushed development. True technical debt is something we should seek to minimize. However, a lot of what we call tech debt isn’t really tech debt at all; it’s just stuff that we developers don’t understand.
The problem is that “tech debt” has become the ultimate excuse when a developer or team doesn’t want to do something or doesn’t know how to do it with an existing piece of legacy code. Legacy code isn’t the same thing as tech debt. Legacy code can be fast and stable and quietly run for years, even after the developers who wrote it have long since left. Good code doesn’t become true tech debt just because nobody understands it anymore. As software organizations mature, they need to contend with true tech debt but also maintain an understanding of their code to avoid this fake tech debt.
JAXenter: Why is technical debt such an important conversation for DevOps?
Liran Haimovitch: DevOps is ultimately about delivering high-quality software at a fast and sustainable pace. Picking up tech debt is a bit like taking a loan: borrowing from your future self can help you deliver software faster, but it’s not always sustainable. If you take a loan with too-high interest rates and don’t pay down the debt quickly, the repayments can spiral out of control.
The problem is that “tech debt” has become the ultimate excuse when a developer or team doesn’t want to do something or doesn’t know how to do it with an existing piece of legacy code.
But claiming a complicated piece of code as “tech debt” can sometimes be an excuse to avoid understanding someone else’s work. Some developers would rather take the time and energy to rebuild something that works from the ground up to “remove tech debt” instead of learning how the existing code works.
This can be an issue particularly in companies where developer performance is measured by how much new code they write. Experimenting with an old bit of existing code is hard to measure or to demonstrate to management. It’s up to R&D heads to demonstrate that there’s value in understanding the existing codebase and that replacing it isn’t always the right option.
JAXenter: It has been argued that technical debt can also aid projects. What are your thoughts on that?
Liran Haimovitch: Tech debt isn’t helpful on its own, but its existence can be proof you’re doing something right.
Technical debt is sort of a natural phenomenon and seeing it emerge can be a sign that people are finding your software useful. After all, if something isn’t used, it doesn’t have any debt. Tech debt only starts to matter when you want to add features or improvements.
Fake tech debt is also a positive sign of a maturing product and company. As functioning code enters its second decade, we shouldn’t be surprised that the original developers have long since moved on and the current generation can struggle to understand the wisdom of the ancients. Again, though, this should be distinguished from true technical debt
JAXenter: Do you have any dos and don’ts to share? How to remedy technical debt issues or use them to our advantage?
Liran Haimovitch: First, learn to distinguish between true technical debt and stuff you just don’t understand. If a project’s using deprecated frameworks, has become increasingly hard to maintain over time, or if it’s slow or a memory hog, these are some clues that you’re dealing with real technical debt. Often, these are systems that need ongoing maintenance and TLC, so developers actually understand them quite well.
On the other hand, if a piece of code is quietly and efficiently doing its job, it *probably* isn’t technical debt. Perhaps nobody knows how it works because it’s been a decade since it needed any fixes! It may be harder when you do need to make changes, but that’s not the fault of the original developers. The key to remedying this fake tech debt is for developers to learn how the code works.
Ideally, this would be something that could be achieved via good internal documentation, but in reality, internal docs are usually poor or unmaintained – this is sometimes known as “documentation debt” and it’s a problem in itself.
Observability is critical for learning how the code works. APM tools (like Datadog or AppDynamics) and exception managers like Sentry are helpful for providing a good overview. Flame graphs can give visual aid and tracing solutions can help show the application flow.
Another option is debugging. One of our developers likes to play with legacy code by adding a load of breakpoints and seeing which branches are hit until he understands how it all works. Rookout’s non-breaking breakpoints let you experiment with the code as it runs without adding any overhead, making it a good tool for this kind of exploration.
Some true technical debt is inevitable. You can minimize it by making good design decisions, but as code ages, even the best decisions can turn into burdens that need to be replaced. Keeping ongoing maintenance and future needs in mind can help keep on top of tech deb but you never really know what the future holds for your software.
When encountering something that seems like technical debt, ask “Would I still feel like this if I understood the code?” If the answer is “no” then it’s not tech debt; It’s a knowledge deficit – and a learning opportunity.