Tech Debt: Pay Now or Pay More Later

Technical debt is one of the most stubborn issues in software development. How can we deal with it?

Hey there, product development enthusiast!

Welcome to the summer issue of TTIU!

Today I want to talk about an ugly topic: Legacy software or technical debt. This is one of the most stubborn issues in software development. Why does it always slow us down and cost a fortune? And how can we do better?

Let’s get started!

❓️ What is “Technical Debt”?

What does “technical debt” even mean?

First, it has nothing to do with the age of software. 10-years-old software can be in perfect shape while a freshly vibe-coded app can instantly turn into nasty technical debt.

I like to define technical debt by three criteria, of which one would already qualify a piece of software as legacy:

  1. Fitness for purpose: If software doesn’t fulfill its purpose, I consider it technical debt.

  2. Adaptability & reliable operations: Nearly every software does regularly need to be adapted. Be it fixing bugs, complying with changed regulations, or adding new functionality. If you are afraid to change anything in your software because it might break, this is technical debt. Related to that are reliable operations. A software product that works, but is not available because of outages, severely hurts its value. If you cannot operate it reliably, you are in trouble.

  3. Scalability: The last point that could render a software “legacy” is if it is not scalable, but the business requires it to scale. That latter condition is important as not every software needs to scale. But if it needs to scale and doesn’t, that’s tech debt.

Secondly, there are two levels to distinguish in a software product: the micro level and the macro level.

  • Micro level: The micro level is about the implementation of single services. Examples of technical debt on this level can be missing test coverage, poor code quality and necessary refactorings etc.

  • Macro level: The macro level is about the architecture that combines multiple services to systems. On this higher level, technical debt can be around storage of data (wrong technology or location, unclear source of truth), their processing (unclear domain boundaries, suboptimal flow of data), or the design of the system (monolith vs. service-oriented).

On both levels, the three above mentioned criteria for technical debt can occur.

But why?

why would you do that season 1 GIF by BBC

🔍 Are my developers too stupid to do their job right?

I believe there are 4 reasons how technical debt comes to life:

  1. Lacking skills of the developers

  2. Time pressure

  3. Missing understanding of the customer problem

  4. Evolution of the business

The reason for technical debt can of course be lacking skills of engineers. This hampers adaptability, reliable operations, and scalability. But often this is not the problem.

I would say the biggest part of technical debt is created because of time pressure. In order to hit a deadline, functionality is added where it can be achieved the fastest (e.g. where a team has capacity), not where it would be right. Shortcuts are implemented but not cleaned up after the launch. This again affects adaptability, reliable operations, and scalability.

While the first two reasons are kind of common sense, what is often overlooked is a missing understanding of the customer problem. If the solution was designed the wrong way, this might result in the software not being fit for its purpose. Additionally, if a lot of inadequate functionality was built, which is not used or even misused by customers, that can also lead to lower adaptability of the software, complicated operations, and missing scalability.

Lastly, a software can become technical debt, even if you did everything right! Just because the business and its requirements evolve over time, your software might no longer be fit for its evolved purpose. Similarly, the scalability might no longer be sufficient if your business grows significantly. I had a case in Zalando, where a platform that was built well (with the goal of being easily usable), at some point couldn’t scale anymore and the whole data architecture needed to be reworked to focus more on a goal of an order of magnitude higher scalability - just because the business evolved!

🌞 How can we do better?

As we have seen, there is no way to avoid technical debt in general. Therefore, there are a couple of things a product development organisation needs to embrace to prevent and manage it.

If there is a skill issue with your engineers, obviously, you need to hire and train your engineers better and provide them the right tools, e.g. AI coding tools that can detect coding mistakes, add test coverage etc.

The time pressure issue is a more delicate one. The most important thing to understand for everyone about software development is, that there is no such trade-off between speed and quality!

It doesn’t exist. 

The moment you sacrifice quality in favour of shipping faster, you will inevitably be slower from that moment on. Poor quality leads directly to slower adaptability and less reliable operations of the software. Changes get more costly and bugs will keep your team from working on new features. I highly recommend reading the excellent book “Modern Software Engineering” by David Farley on this topic.

Having said that, I am aware that sometimes - due to external factors - you might need to hit a deadline and therefore will take shortcuts. That’s okay - as long as you really take the time to clean up. Systematically, no excuses. I’ll explain more about how to do it below.

If the issue is a lack of understanding of the real customer problem, then you probably have an issue with your product management approach. You might be shortcutting the early phases of discovery and validation. And the possibility of vibe-coding does not render that unnecessary - it even allows you to do that faster!

If your business evolves quickly, even the shiniest software can age overnight. This requires investments in your existing software.

💰️ How to invest in your software to not turn into legacy?

The only way to tackle the issues that arise from the evolution of your business over time, as well as the shortcuts you might take, is a systematic approach. You need to invest in your software to not become obsolete. But how?

Let’s look at the following diagram. It shows the amount of business value created by a software over time and two graphs:

Red graph: focus on feature development without investing in the software itself until it is too late
Green graph: continuously investing in the software

The red graph shows a behaviour that focuses on shipping features fast. As outlined above, this only works very briefly and then the technical debt slows down the value created - further and further. Since it is not addressed, it becomes unbearable at some point. The software becomes so hard to change (“legacy”), that it needs to be replaced entirely: A big migration to rewrite the software from scratch.

This is the scenario to avoid! 

The migration will take a long time, while little or no new value will be added for customers.

The green graph shows what happens if you keep investing in your software like a gym habit to counter tech debt created by cutting corners or an evolving business. The value delivered is not only much more stable, but also in total much bigger than in the red graph scenario.

So how can you reach the green graph scenario? You need a system for that!

To manage technical debt on the micro-level of your software, you should:

  • Regularly dedicate time for refactoring, improving tests or updating dependencies. If you work in sprints, block the last day or two for it. And this needs to be a rule: You do it every sprint. Don’t waste time negotiating this with PMs or stakeholders every sprint - it’s non-negotiable.
    Pro tip: If you fail to do so on the last days of sprints - because this is where it gets hectic and things need to be finished - do the cleanups during the first days of a sprint instead.

  • If you committed to a shortcut implementation to meet a deadline, do the cleanup immediately after (and communicate that from the beginning). If you don’t, you will never get to it.

  • Agree on the Boy Scout Rule: Every code that any developer touches, they have to leave better than they found it. You can even build this into your CI/CD process by breaking the build if some KPIs like test coverage or complexity metrics get worse.

Managing technical debt on the macro-level of software requires more of a plan:

On the macro-level, improvements can normally not be done within a day or two. However, also macro-level investments in the software need to happen continuously.

  1. First, you need to have an architectural vision that is a) informed by both technical needs and product strategy (e.g. to foresee the evolution of the business) and b) regularly updated.

  2. You then need to break that down into work packages that are ordered in a technical roadmap. These will still be big and not doable in days.

  3. The art here is to plan these in over time. Surprisingly often, you can combine upcoming feature work with such work packages that affect the same services. Jackpot!

  4. If that’s not feasible, you’ll need to explicitly put them in the general roadmap. Still way better than a quarter-long death march of a migration.

The overall key is to constantly weave in the tech debt work - in sprints as well as in longer-term roadmap plannings. If you continuously invest like this to avoid tech debt, this will keep your velocity for building features high and prevent you from having to do big migrations.

Happy Season 17 GIF by America's Got Talent

🤖 How does AI change the picture?

As AI enters the software development scene, this affects technical debt as well.

If AI coding tools are used and function well, I assume this to be good news in regards to technical debt. With these AI tools we will be able to re-create bigger software systems that have become technical debt much faster. So if your product doesn’t scale anymore - just rebuild it in no time, at little costs!

This is the optimistic future scenario. We still need to get there.

Today, with all the vibe-coding coming up, I see the opposite risk of creating much more technical debt faster. If “anyone can (and does) code” without knowledge about separation of concerns, scalability, security etc. we create very fast and cheap tons of software that might not be changeable, cannot be operated well, do not scale. AI might become the world’s fastest legacy-software factory.

I think we overvalue how we can build faster with AI, because “faster” often means no tests, bad architecture, no security, no scalability.

At the same time, we undervalue how we can build better with AI. AI can exactly address all of the above. AI can optimise architecture for changeability and reliability. It can identify and fix issues around security, test coverage, or code complexity. I am convinced AI will replace documentation of software - allow any skilled developer to understand and change any unknown software in an instant by talking to it. And it’s just a matter of time until AI can significantly improve software on the macro-level as well. Maybe better than humans could ever do.

So in a few years, if we are lucky, the ugly topic of tech debt might have become a non-topic.

Robot Hyundai GIF by BostonDynamics

Wrap-Up

That’s TTIU for today. I hope you enjoyed it and found it inspiring. Let me know what you think.

📬 I read every piece of feedback - hit reply and let me know your thoughts! Got a topic you want me to cover? I’m all ears.

Thanks for reading,
Jan

Greetings from windy Denmark

💡Jan’s Knowledge Nuggets

The bonus inspiration this week:

  • We are f**ked with Social Media ☠️: A recent study found that social networks are bad for social dynamics even independent of their algorithms.

  • Product Management Festival 2025 🎉: In November this year, the crème de la crème of Product Management will meet in Zurich for the Product Management Festival. The lineup of speakers is already great and more is yet to come. If you want 20% off your ticket, you can use my voucher code: DISCOUNT20JAN

  • “Job hugging” has replaced “job hopping”: As the labor market continues to shrink while uncertainties due to AI and macro-economic conditions rise, people cling to their jobs as CNBC reports for the US. The situation in Europe is comparable, I would say.

  • Local prioritisation is bad prioritisation: Very good examples that show how prioritising locally can easily be a big disadvantage. If you are interested in prioritisation in general, this previous issue of TTIU might be of value to you.

Game Of Thrones Idea GIF by HBO