Technical Debt

Written by Clement for The Product Manager blog and originally published here. Reposted with permission.

Early on in my career as a newly-minted associate product manager, when I first heard of technical debt (a.k.a. tech debt), I wasn't quite sure what it meant.

Hilariously, I thought it referred to a loan that we had taken out to purchase third-party software, and I confidently misused this term for two or three weeks.

Imagine my embarrassment when my engineers took me aside post-standup to gently correct me!

So, to save all of us some blushing on the job and to help us build street cred with our engineers, let’s dig into what technical debt is and why we as product managers should care.

What is Technical Debt and When Is It a Problem?

Software development is all about balancing the breadth of product functionality against high quality code. Along the way, we sometimes take shortcuts to speed up the development process—these shortcuts are called technical debt or tech debt.

When is incurring technical debt a good idea, and when does it become a ticking time bomb?

To answer this question, we’ll first want to take a look at the history of tech debt.

What is technical debt?

Ward Cunningham, the person who coined the term, likens technical debt to financial debt—it’s okay to borrow against future velocity and stability, but we have to pay off the debt eventually.

It’s a concept every development team should understand, and every product manager should consider when making product decisions.

Tech debt helps us release products ahead of schedule and gets products into the hands of customers faster.

But, we have to eventually “pay down the debt” by investing in the quality of our code base.

And ideally, we should actively decide whether we want to leverage technical debt or whether we want to avoid it.

Similar to financial debt, we don’t want to be surprised with an unforeseen cost later on!

A simplified definition of technical debt

Technical debt (also referred to as code debt in some teams), refers to the implied cost of future rework needed when you choose a short-term shortcut over a better approach that would take longer.

It's like paying interest on a loan—the cost of technical debt increases over time.

One analogy I use is shaving a beard. If I’m pressed for time and do a quick shave, it’s probably not the cleanest shave ever, and I have to come back later to clean it up.

The time and effort required for both shaves—the initial shave and the second clean up shave—is going to be more in total than if I had done a proper shave in the first place.

But sometimes, when we’re running out of time, we have to commit to the quick shave!

Comparing financial debt to technical debt

To bring this concept to life, let’s dive a bit deeper into the comparison between financial debt and technical debt. After all, product managers need to understand both business finance concepts and technical coding concepts!

Pros of financial debt: Financial debt enables leverage. Borrowing money can provide the capital needed to invest in growth opportunities. And, financial debt allows for immediate access to resources or assets without requiring upfront payment.

Cons of financial debt: Financial debt comes with many different kinds of costs. Interest payments on financial debt can accumulate over time, reducing overall profitability. And, failing to manage financial debt properly can result in financial instability.

Furthermore, debt can restrict financial flexibility and prevent us from pursuing particular paths in the future. And, defaulting on financial obligations can harm an organization's reputation.

Pros of technical debt: Technical debt enables faster initial product development, helping to meet tight deadlines or seize market opportunities. And, similar to financial leverage, taking on technical debt can reduce initial development costs.

Cons of technical debt: Just as interest accumulates on financial debt, technical debt compounds as additional features or changes are built upon the existing shortcuts, making future development more complex and costly. And, technical debt often results in suboptimal code quality, leading to higher maintenance costs over time.

Technical debt can hinder a product's ability to adapt to changing market conditions or incorporate new features.

And, unaddressed technical debt can lead to system failures, security vulnerabilities, or performance issues, impacting the product's viability.

What does this mean for us? Well, for both financial debt and technical debt, the goal isn’t to avoid debt entirely. Instead, prudent management is the key.

While some level of debt is strategic for growth, we must carefully monitor and manage debt to minimize long-term negative consequences.

Examples of technical debt

In the realm of software engineering, development teams regularly encounter technical debt. Let’s discuss a couple of the most common examples.

Legacy code: Some teams may use outdated legacy code to push a feature out quickly. This may provide immediate functionality but could need substantial refactoring later on, especially as new features are added. Much like an ancient manuscript, legacy code has been handed down through generations of developers, accumulating the weight of history.

While it may have served its purpose admirably in its prime, time has a way of eroding its adaptability and maintainability. Outages and bugs in production tend to crop up when we rely too much on legacy code!

Hardcoding: Hardcoding refers to the practice of embedding specific values or constants directly into the code rather than using configurable settings. While this approach can offer expedited development in the short term, it often leads to complications down the road.

Imagine a scenario where a hardcoded value, such as a file path or timeout threshold, needs to be changed across a sizable codebase. This can quickly become a time-consuming and error-prone task, jeopardizing the maintainability and flexibility of the software. To avoid this pitfall, developers should opt for configurable options, enhancing the adaptability of their code.

Code Duplication: Code duplication occurs when similar or identical code snippets appear in multiple places across the project. Initially, it might seem like a convenient shortcut, saving time during development. However, as the software evolves and requirements change, maintaining consistency and making updates becomes an intricate dance.

Code duplication not only increases the risk of introducing bugs but also multiplies the effort needed for future enhancements and bug fixes. The pursuit of code reusability and the elimination of redundant code are fundamental principles to counter this problem.

Lack of Documentation: Documentation serves as the guiding thread that illuminates the path for current and future developers. The absence of comprehensive documentation is akin to embarking on a complex journey without a map. It may start with a lack of inline comments explaining the rationale behind certain code choices or escalate to missing user guides and system architecture documentation.

While the initial development phase might proceed smoothly, the long-term consequences can be severe. Debugging becomes a cryptic endeavor, knowledge transfer between team members becomes challenging, and scaling the project often resembles navigating a labyrinth in the dark. Embracing thorough documentation is the beacon that illuminates the way forward in software development.

Lack of Automated Tests: The absence of automated tests is akin to sailing a boat without first checking whether it has any leaks. Automated tests (including unit, integration, and regression tests) are the vigilant guardians of code quality and stability.

When omitted, the consequences may not be immediately apparent. Initially, development might progress swiftly, and the software may appear functional.

However, as the codebase expands and evolves, unforeseen issues start to surface. Regression bugs, where previously working features break with new changes, become commonplace.

Without automated tests to provide a safety net, the development team must rely on manual testing, a time-consuming and error-prone process. Embracing automated testing from the outset ensures a steady course in the tumultuous sea of software development.

What is the role of technical debt in Agile?

Scrum methodologies and principles from the Agile manifesto embrace change and speed. But where does tech debt fit in? After all, technical debt isn’t specifically discussed in the founding documents of Agile.

Well, here’s an analogy from Star Wars: the Millennium Falcon underwent continuous maintenance by Han Solo and Chewbacca to stay in top shape for their endeavors.

Similarly, an Agile team manages technical debt to maintain software quality and enable heroic adventures for their customers! 

How to use the concept of technical debt

In Agile teams, there’s an understanding that sometimes you'll incur some technical debt to meet business needs swiftly. Remember, incurring this isn’t always a bad thing.

Martin Fowler, a thought leader in agile software development, points out that it's about trade-offs. You might accept some debt early in the software product lifecycle to validate a concept or reach a market faster.

The key is managing technical debt. Technical debt should be documented in the backlog, prioritized, and addressed in future sprints.

For this to happen, product managers must lean on strong project management, and they need to have a good understanding of the amount of technical debt taken on thus far.

When is technical debt a problem?

When stakeholders are oblivious to technical debt, or when the development process relies heavily on workarounds, that’s when the alarm bells should start ringing.

  1. It’s Invisible: Without metrics or regular code reviews, hidden vulnerabilities can emerge.

  2. It Impacts User Experience: If underlying issues start affecting the functionality, it's not just a developer's problem; it's a business problem.

  3. It Hinders New Features: Programmers mired in bad code are less productive, and creativity decreases.

  4. It’s Not On The Roadmap: Teams should be aware and have a strategy towards tech debt. Don’t hesitate to lean on external webinars and resources to establish a game plan.

How to measure technical debt

Using tools like DevOps practices and automation, teams can keep an eye on their codebase and keep a pulse on the technical debt that’s been racked up so far. Below, I’ve pulled together twelve different ways you can track technical debt.

You don’t have to use all of them! Instead, think of this list as a jumping-off point. Pick one or two to implement in the next month or so, and then slowly build up your team’s sophistication in tracking and resolving technical debt.

1) Static Code Analysis: Tools like SonarQube, ESLint, or FindBugs can automatically analyze code for various issues, such as code complexity, code smells, and potential bugs. They provide quantitative metrics on code quality and technical debt based on predefined rules and thresholds.

2) Code Coverage: We can assess how much of the codebase is covered by automated tests by measuring code coverage with tools like JaCoCo or Istanbul. Low code coverage can indicate a lack of testing and potential technical debt.

3) Peer Code Reviews: Conducting peer code reviews allows developers to identify and discuss potential technical debt items. And, two brains is better than one—it’s a great way to avoid bad code patterns! Teams can use checklists or guidelines to assess code quality and document identified issues. The number and severity of issues found in reviews can serve as a qualitative measure of technical debt.

4) Manual Code Inspections: Developers and teams can perform manual code inspections or walkthroughs to identify areas of the codebase that may benefit from refactoring. This process often involves experienced developers reviewing code and documenting issues, as they tend to have the best sense of technical design debt. 

5) Technical Debt Backlog: Maintaining a dedicated backlog or list of identified technical debt items is a common practice. Each item in the backlog should include a description, impact assessment, and priority rating. The size and priority of items in the backlog provide a qualitative measure of technical debt.

6) Bug and Issue Tracking: Analyzing the bug and issue tracking system can reveal the frequency and severity of issues related to technical debt. High numbers of bug reports or frequent recurrences of the same issues can indicate underlying technical debt.

7) Estimation and Story Points: When planning new work or user stories, development teams can estimate the effort required to address technical debt items. This effort estimation, often in the form of story points in Agile methodologies, quantifies the work needed to resolve technical debt.

8) Code Complexity Metrics: Metrics like cyclomatic complexity, lines of code, and code churn can provide insights into the complexity and maintainability of the codebase. Higher complexity and excessive changes to certain code areas may indicate technical debt.

9) User Feedback: User feedback and support requests can indirectly highlight technical debt. Frequent user complaints about system performance, reliability, or unexpected behavior can signal underlying issues that need to be addressed.

10) Automated Testing Metrics: Monitoring metrics related to automated testing, such as test execution time, test failure rates, and flaky tests, can help assess the health of the testing infrastructure and identify areas impacted by technical debt.

11) Surveys and Interviews: Surveying and interviewing development teams can provide qualitative insights into the perceived level of technical debt and its impact on productivity and code quality. And, collecting stakeholder feedback can help provide insights into where rework might be necessary.

12) Technical debt quadrant: One particularly useful tool is the technical debt quadrant introduced by Martin Fowler. It categorizes the causes of technical debt into deliberate vs. inadvertent and reckless vs. prudent, helping teams understand trade-offs.

Paying off technical debt

We’ve talked a lot about incurring technical debt, but we haven’t yet covered how to pay it off.

As product managers, it’s our responsibility to guide our teams to decide when to pay off the debt vs. when to incur additional tech debt.

We pay off technical debt when engineers update the code base to address previously-identified technical debt items. This might include redesigning functionality to be more efficient, or implementing automated tests, or providing in-depth documentation on the code.

One of the best ways to pay it down is to reserve time each sprint towards strengthening the codebase and paying down the debt.

Think of this like making monthly mortgage payments—the faster we can pay down the mortgage, the less interest we have to pay overall!

A good rule of thumb is the 80/20 rule. That is, spend about 80% of the time each sprint to build new features, and 20% of the time to prioritize technical investments and improvements.

As you plan for paying down technical debt, consider weaving it into your product roadmap accordingly.

Closing thoughts on technical debt

To wrap it all up, managing technical debt isn’t just a job for the developers. Product managers, agile teams, and business stakeholders play a role.

The end goal? Delivering a high-quality software product that meets business goals without incurring unsustainable debt.

So, whether you're diving into the deep seas of software development or just trying to make sense of why your development team keeps talking about refactoring, understanding and managing technical debt is the compass you need.

And, whether you’re early on in your product career, or whether you’re already a seasoned veteran in product management, you’ll almost always benefit by deepening your understanding of technical lingo.

I hope you’ll avoid making the same mistake that I made early in my career—don’t rely solely on context clues to guess at unknown technical concepts!

Instead, take the time to conduct research, refer to external guides like these, and spend time with your engineers to brush up on valuable knowledge.

Previous
Previous

Q&AI: Handling Difficult Team Members

Next
Next

Reducing Plastic Pollution Through Product Management