Post·technical
Diving Deeper into Tech Debt, Part One
A deeper dive into what tech debt is

In my earlier discussion on tech debt, I connected the concept to some real-life analogs and offered techniques to talk about it and manage it. Over time, I realized that the subject is both a lot deeper and more in-demand as I frequently end up spending time with teams talking about tech debt. Noticing that there isn’t good depth to the topic in the literature, I am following up with this deeper dive.


It’s not surprising that tech debt is a common discussion topic. It is not universally understood by business and product stakeholders – and even technologists themselves. It is often not well managed by teams (or at least not intentionally managed), and tends to be universally disliked, yet is key to many engineers’ job security. Finally, it seems to be a common “boogeyman” to push problems onto.

Acknowledge reality

To help teams manage tech debt, it’s critical to anchor oneself to reality.

Tech debt exists and always will.

It is as inevitable as wear and tear on machines or the obsolescence of technology. Teams that don’t think they have tech debt are either inexperienced, or, candidly, are lying to themselves. In the former case, this usually happens with teams that lack senior enough members who have seen a technical product through enough of its lifecycle to witness the evolution and impact of technical debt. In the latter case, deeper challenges may be at play – it could be the team’s insecurity over its abilities, an (often embarrassing) lack of depth or familiarity with the code, or a dysfunctional culture that punishes teams for what may be perceived as quality “issues”.

In the teams’ defense, tech debt is not always intuitive to engineers, and it’s fuzzy – it’s hard to see and measure, and it’s not trivial to manage. Unlike direct business metrics such as user counts, transaction volume or even engagement, tech debt is often only visible through the ways in which it interacts with the product’s features, rather than directly.

Tech debt is part of the art of engineering, that is, it presents teams with trade-offs, which the teams can manage explicitly, or which can lead teams to some unpleasant surprises and excessive costs and risks down the road, if not managed with intentionality. For this reason, both technical teams and their stakeholders (and non-technical counterparts that partner with them) should embrace the fact that tech debt exists and become comfortable with it, demystifying it in process.

What to do, exactly? First of all, teams should convince themselves and others to care. Asking directly if tech debt matters isn’t that productive. Instead, I advise teams to take a walk down memory lane and make tech debt tangible through all the circumstances where it has imposed a cost on the team and the product. Did an unusual amount of tech debt cause a defect? Did it cause frustration trying to implement what should have been an easy feature? Is there an “open secret” on the team that all estimates need to be doubled because of the state of the code?

Team leaders need to be bought into the importance (and presence) of tech debt. Invest in your leaders thinking about their codebases, and tech debt more generally. Do they know what it actually means? How would they measure it? How would they be able to show which areas manifest smaller amount of tech debt relative to other areas? How are they managing tech debt today? Are they intentional about it or do they expect it to be reduced organically, through the engineers’ initiative and the natural process of code rewriting that happens all the time? The latter is not necessarily a bad outcome; in fact, engineering teams are heavily time-constrained and so the most common way to manage tech debt will be to let natural processes reduce it over time, but tech debt in codebases often follows a pareto law – there are relatively few areas where tech debt that has a disproportional impact on the product. These may be worth managing more intentionally.

Define it and its sources

Just as important as teams connecting with tech debt is teams helping their stakeholders decode it. Investing time in communicating about it specifically is the best first step: help your stakeholders understand what it is, why it happens, what its impact is. I use the following stakeholder-friendly definition:

Tech debt is a tax on current and future work, and a risk factor for the product

It’s not an obvious concept, because people who are non-technical tend to think of software engineering as theoretically more precise and often final (the way a math theorem would be), so it’s helpful to repeat oneself here.

There are various causes of tech debt and it may be helpful to enumerate them to help communicate and manage it.

Inevitable causes

Inevitable causes include assumptions that the team made in the past that ended up being wrong or that no longer apply. It’s important to explain to stakeholders that engineers make hundreds of assumptions, some small and some large, in the face of uncertainty (unknowable requirements, future use cases, third-party systems evolving in ways that we cannot predict, etc.), and if these assumptions don’t pan out, code may end up being more complex or less legible than is ideal. Another inevitable cause is the fact that the engineering process isn’t perfect. For example, engineers are not all 100% familiar with the entire codebase, their coding styles are different, some code is harder to write for some of them, engineers face constraints from third parties, etc. This fundamentally stems from complexity: it is really no different than any human process, not necessarily related to engineering, but engineers work on projects that have much greater levels of “per capita” complexity than most non-engineering teams, so the tech debt is correspondingly more visible.

Intentional causes

These are essentially consequences of the trade-off nature of engineering work. I remind teams and stakeholders that

Engineering is the art and science of managing technical trade-offs

While it may seem that anything is possible with technology, even bits are subject to the laws of physics. Specifically, engineers have to decide which components of the systems they build should become bottlenecks and how to dedicate limited computation and storage. At other times, engineering teams intentionally decide to write less robust software in order to make a deadline; often, both the teams and the stakeholders promise to “go back” to these weak spots, but in reality new priorities often take over, and often that is a rational, utility-maximizing choice.

Manageable causes

Manageable causes are the most important ones, if you are responsible for the quality of the engineering solutions. You can manage these factors, and with it push out the “efficient frontier” of development. These factors include the team’s experience (the ability to design technical solutions, ability to spot tech debt, and the awareness of the trade-offs involved), their knowledge of the business problems and the product, and the discipline to go back to problem spots soon after a deadline. As an engineering leader, it’s your job to handle these factors, but often it’s not clear how they connect to tech debt and what impact overall they may have on your team’s outcomes. I usually advise a deeper analysis.

**

Sometimes just understanding these factors helps the teams take a step back and rethink their solution, or gives them a blueprint for where to look to improve the quality of their code. But more often, the understanding is not enough. Teams need to make tech debt more front and center – they need to be more aware of it. More about that in the next installment.