Technical debt: How to recognize, understand + manage tech debt
Technical debt is the cost of prioritizing short-term solutions over accuracy and quality during the development process, intentional or not.
Feb 7, 2024 • 20 Minute Read
- Engineering Leadership
- Software Delivery Process
When we talk about “technical debt,” it’s easy to draw parallels to different kinds of financial debt—be it healthy debt (like a mortgage) or problematic debt (like credit card debt). No matter the type of debt, it needs to be paid down consistently or else you risk declaring bankruptcy, having to wipe the slate clean and start over from scratch.
Yet understanding technical debt isn’t always as straightforward as that. The financial analogy only gets us so far in understanding what technical debt is, why it matters, and how we can prioritize addressing it. To understand and act on our technical debt, we need to shift how we think about it.
In this guide, we’ll break down what technical debt is, what causes it, and how you can effectively manage technical debt.
What is technical debt?
Technical debt, also referred to as tech debt or code debt, occurs when developers rush through a project and prioritize near-term development time or shortcuts over long-term consistency or quality, increasing the costs and challenges of new work later on. Put simply, technical debt prioritizes speed over accuracy and pushes the costs of that choice out to future development cycles.
Is technical debt bad?
Your team may need to quickly release a minimum viable product (MVP) to gain an advantage over competitors. That product may not need to be perfect, but it needs to get to market quickly, so your team might intentionally accrue technical debt to get the product into customers' hands faster.
This is a reasonable decision: gathering early user feedback can be invaluable for finding product/market fit and meeting customer needs. In this case, technical debt isn’t necessarily a bad thing, and going into debt isn't necessarily a bad decision. Like financial debt, it just means you've taken on some debt to get something that's important to you sooner.
You never want to take on debt you can't pay down, but often taking shortcuts and expediting the development process can be a smart strategic decision. But it should be a decision!
Can we avoid technical debt?
Technical debt has a wide range of causes, some as a result of intentional decisions and some merely the result of change over time. Sometimes technical debt arises from poorly written code, lack of training, or unclear project guidelines, but it may also arise from perfectly well-written code that simply doesn’t serve its function as well as it used to.
We can rarely avoid technical debt completely, but by understanding what it is and how it arises we can more often make deliberate decisions about when to take it on.
The technical debt quadrant
A common perspective on technical debt is that it stems from engineers’ hastiness or sloppiness in an attempt to achieve results faster. While technical debt can result from recklessness (inadvertently or not), it can also be leveraged deliberately.
This is what the credit card and mortgage analogies speak to—engineering teams are borrowing efficiency now in exchange for having to do more work mending the code later.
Development expert Martin Fowler argued that at a high level, the causes of tech debt can be broken down into four categories that he called the technical debt quadrant: just as one can borrow capital responsibly or carelessly, teams can create technical debt strategically or recklessly.
Deliberate and reckless: Occurs from deliberately making shortcuts to speed up delivery time but not fully understanding the future implications
Deliberate and prudent: Occurs when you have a clear understanding of the future impact and are willing to take the risk
Inadvertent and reckless: Occurs unintentionally from a lack of understanding or knowledge or from rushing through a project, often causing extreme future consequences
Inadvertent and prudent: Occurs when unavoidable and unexpected issues arise, often from an experienced development team
This perspective brings us closer to a healthy, empathetic understanding of technical debt—it’s not necessarily (or even frequently) a result of a character flaw or personal shortcoming.
Types of technical debt and their impact
Unaddressed technical debt might get a team by for a while, but eventually, the issues will start to affect greater areas of the production process and the codebase.
There are also human considerations on top of organizational ones. Agile coach Declan Whelan shared some ways that technical debt impacts engineering companies on the individual, team, and organizational levels:
Of course, managers don’t want to wait to address technical debt until they start seeing the worst of these symptoms. But no matter what, an engineering team already has technical debt. A saying expressed by several tech leaders is that the second a team ships code, it becomes technical debt. Even though there are times when technical debt is intentional and teams decide to expedite a project knowing they may have to deal with the consequences later.
As a leader, the key becomes learning to recognize and categorize technical debt, so you can effectively decide how to pay it down.
Beyond Fowler's argument about risk and intentionality, in 2014 a group of researchers created a taxonomy of tech debt types, useful terminology for describing not just the debts themselves but how those costs can show up in the development process as the interest on them starts to accrue:
Code debt occurs when developers take shortcuts to expedite code production in the near term, resulting in code that's difficult to understand or change later. This kind of debt is most keenly felt in your product's most important features or in its core differentiator.
The impact of code debt varies, but the drag it can represent on product velocity as the cognitive burden even small changes gets out of hand can make it increasingly difficult to meet customer needs or adapt to new market opportunities.
Documentation debt occurs when the development process is rushed and not carefully documented, or when documentation is deprioritized in favor of iterating on the product. The impact of doc debt won't be felt until your product is in your customers' hands, and they start asking questions only to find that the answers are outdated or wrong or both, leading users to have the impression of a substandard product.
When testing is delayed or deferred during the development process, you can easily end up with a false sense of confidence in the quality of your product. Worse, over the longer term it might become difficult or impossible to know if your efforts to create new features aren't breaking the old ones, or if you're accidentally re-shipping long-solved bugs to your customers.
Process debt occurs when ineffective and outdated processes accumulate over time, becoming a set of unoptimized rituals rather than solutions to real problems. When this happens, the organization can find itself struggling to ship code even if the code is well-written and well-understood. Process debt often accumulates in reaction to previous failure and organizations that become sufficiently risk-averse can also struggle to ship high quality software on a reasonable schedule.
This can happen when proposed design changes are only partially implemented before directions change, and can easily be compounded when follow up efforts to address a product's inconsistencies suffer the same fate. The result is confusing inconsistencies, errors and half-finished or missing features in the user experience that, like doc debt, can leave users with the sense that the product is half-baked regardless how well-executed the underlying software might be.
How technical debt shows up in practice
Let’s return to the definition above that technical debt is anything that creates friction in the development process. The most widely and easily understood forms of technical debt are those that manifest themselves in the codebase itself. But technical debt can also take on forms that aren’t necessarily tied to a line of code.
To give you a better understanding of technical debt in the real world, here are a few examples:
Code debt: automation and cognitive load
The absence of automation and the existence of cognitive load are both friction points that can slow development teams. This is because every process that they have to complete manually to do their jobs effectively ultimately slows their progress.
Of course, all engineers will stash some concepts in their minds, and everyone has to do certain things manually. But just as a laptop is created to handle a certain processing load with ease, it will start to bog down with too many programs running.
Technical debt that stems from a lack of automation or too much cognitive load can ultimately reveal itself in the code as well.
Complex codes and unclear guidelines are just two examples of this:
- Complex codebase: If a codebase grows too complex and interwoven, it becomes hard for engineers to understand all the ripple effects of the changes they make. That’s not information they can reasonably bear cognitively while completing new code.
- Vague requirements: With unclear requirements and end goals, developers may have to account for too many contingencies and possibilities to move forward with any clarity.
Documentation debt: absence of context
In the same vein, the absence of context is a form of technical debt. We break this form of debt into two types: breadcrumbs and daily practices.
- Breadcrumbs: If a developer needs to dive into a piece of the codebase, it’s helpful if the code is self-revealing or the developer can reference clear documentation. The code itself may be functional, but if it lacks commit comments or other trails of the original developer’s thought process, then a later developer can’t easily and promptly comprehend the code’s purpose.
- Daily practices: For daily practices, engineers can improve the breadcrumbs they leave by asking questions like, “Am I using clear variable names and function names? Am I using solid coding principles and do I know what those are?” Individual practices can build significant contextual understanding down the line for other engineers.
Process debt: human factors
Then there are the completely non-technical human factors that contribute to technical debt. Many developers work on relatively small, often cross-functional teams, and technical debt can accrue when those teams aren’t able to work autonomously and accomplish their targets.
Human factors can often impede a team’s ability to fully change, operate, maintain, and own their domain.
It’s impossible to list every single iteration of technical debt in any of these forms. Every codebase and every team will experience its unique version, but if there is a generalization to be made, it’s that instances of technical debt are often invisible.
Addressing technical debt
Software is made by organizations, and the leadership of our organizations — how they set their goals, values and metrics, how they establish their processes and recognize success — matters. This is true as much in the creation of new products and ideas as it is in the maintenance and support of those already in the market.
Blame often follows discussions of technical debt, which can be incredibly toxic to a working environment. Instead of viewing tech debt as a fault, managers can reframe tech debt as both a success, and as the price of that success: The technical debt a team accrues also has gotten them to where they need to be. Even if that debt is a splendid mess right now, a team can still celebrate its progress thus far.
Andrea Goulet compared paying down technical debt to remodeling a house. No matter how well you build a house, you’re going to need to replace the roof eventually. Other features or appliances may not age well and will need to be replaced down the line, but that doesn’t mean the original roof or appliances were faulty at all. You’re simply doing the work that your house needs to continue to last.
The same goes for a codebase and a team’s processes, especially as your team gets better over time. Strategies and approaches that worked well at one time may simply be outdated or inefficient. Newer methods can replace worn-out ones, and quick, inexpensive solutions can be swapped out for higher-quality replacements as resources allow.
Few engineers will deny the existence of technical debt and the need to pay it down, but the specific tangible adjustments on the ground are needed to manifest as practical changes in processes and workflows.
These are some approaches suggested by industry leaders to aid in altering attitudes and approaches to technical debt within an engineering team.
1. Get buy-in from engineers
Engineering teams need to be aligned on the importance of addressing technical debt before pitching the idea to other departments and stakeholders.
Engineers need to be on board to make any debt initiative matter. Making sure they understand the need for such a project, that they will be supported in and recognized for its outcomes (even if not everyone relishes the refactoring work that goes into it) will be invaluable once the team gets buy-in from everyone else.
Besides, your engineering team may have menders already in its ranks—those developers who thrive on the challenge of addressing technical debt.
2. Redefine the term “technical debt”
Yvette Pasqua offered a strategy her organization has used before, which is to remove the term “technical debt” from their vocabulary and replace it with “continuous product health.”
“When we talk about technical debt, it’s as if everyone’s shoulders slump,” Pasqua said.
“So we tried calling it continuous product health, and it’s helped us so much to get people thinking and talking about it as just a healthy, happy part of what you do every day.”
Teams can consider this long-term strategy as self-care because it resembles a long-term focus on health, like going to the gym or eating healthy. You don’t just do “healthy” two weeks out of the year; it’s an everyday habit. The same goes for product health.
3. Prioritize debt maintenance
Carrying the above concept further, making technical debt maintenance a routine practice makes this approach part of the status quo.
This means dedicating time to clean up code or ensure existing products are functioning properly should be baked into your ongoing tasks. After all, a team’s culture regarding daily and regular functions can have a significant impact on technical debt on an ongoing basis. Recognizing the daily need to maintain product health will make the technical debt more manageable down the line.
4. Create a dedicated debt support team
One of the reasons technical debt accumulates in the first place is that very few organizations have teams or individuals whose purpose is reducing that debt. Everyone has a mission oriented around developing products, enhancing the customer experience, and bringing in sales, but it’s not often that someone fully owns the technical debt.
So once engineering leaders have buy-in from upper-level stakeholders to tackle technical debt, the next step is to enlist those same stakeholders to offer organization-wide support for engineering initiatives. High-level support can give engineering teams the greater leverage they need for dedicating time and resources to meaningful debt reduction.
5. Plan debt initiatives
One way to accomplish buy-in from upper-level stakeholders is to plan larger technical debt initiatives at the same time and in the same way that a company plans its product strategy and roadmap. Whether that’s monthly, quarterly, or every half year, doing that hand-in-hand streamlines the process for the organization and increases visibility for the efforts.
3 tips for managing technical debt
Whatever form it takes, technical debt impacts the development process and overall user experience. Because you create technical debt the moment you ship code, strategizing how to address it can seem overwhelming.
Teams can’t just drop everything else to clean up the entire codebase. So how can managers be practical in prioritizing the technical debt that needs to be addressed while also continuously shipping new and exciting value to customers?
Below, we’ll cover a few quick tips to help you and your team effectively manage technical debt.
1. Treat technical debt like financial debt
While the actual process of cleaning up or fixing technical debt may not be as clear as a number in a bank account, the goal is primarily the same as it is with financial debt: Staunch the bleeding, pay off the high-interest loans first and plan to pay it all off incrementally.
- Fix bad habits: Teams can’t dig their way out of technical debt if they continue following the same behaviors and practices they used in the past. Find a way to stop detrimental habits, patterns, or processes—in the code or outside of it—to prevent future debts from piling up.
- Pay down debt in increments: During sprint planning, integrate tasks into every sprint so it becomes a dedicated part of the development process. Teams are more likely to get ahead of their debt by allocating dedicated periods toward it than only allocating time once a year.
2. Use metrics to quantify the impact
Use software metrics that indicate when and where your team is slowed by technical debt. This information will help leaders identify the business impact of these problems and better manage technical debt initiatives moving forward.
“A lot of this is about identifying what’s the technical debt that’s most useful for us right now,” Pasqua said. “If we want to iterate in a certain area that we think will bring the business really high value and help us hit our company, it probably would be most impactful for us to pay down a lot of the technical debt in that area first.
“It’s not about the worst debt, but rather, what’s the debt that would be most impactful to tackle first, given your company roadmap and strategy?”
3. Asses product lifecycles
The considerations for working on technical debt come down to the product lifecycle. It’s useful to conduct a risk analysis for both creating and addressing technical debt.
“If you’re starting an initiative or launching something and you don’t have very many users, the risk of trying something or accumulating the technical debt is much less,” Goulet said.
“But when you then have something that is a mission-critical system that is going to impact tens of thousands of users and your company will lose money because of it, it becomes more important. So you always have to weigh the business factors.”
Creating technical debt is inevitable, but addressing technical debt doesn’t have to come at the cost of forward progress.
In fact, by prioritizing debt by risk and reward—which areas of the codebase are most critical or most valuable to the organization’s purpose—you can start improving your organization’s functionality and effectiveness almost immediately.
Manage technical debt with Pluralsight Flow
In software development, technical debt is sometimes bound to happen, but knowing how to properly manage tech debt and make it an ongoing part of your development process will help your team successfully pay down your debts.
If your team needs better metrics to help bolster your technical debt reduction plan, try Pluralsight Flow, a comprehensive tool for managing and optimizing software delivery.