Post·technical
Diving Deeper into Tech Debt, Part Two
A deeper dive into tech debt: how to talk about it and manage it

In the first installment of this deep dive, we defined tech debt and (hopefully) convinced ourselves that tech debt is inevitable. We analyzed the different types of tech debt to understand that not all debt is created equal. While this classification may be helpful off the bat, more often teams (especially junior teams) simply don’t have enough exposure to tech debt to be able to manage it well.

Raise awareness

I tell teams that if only they didn’t have to hide or apologize for tech debt, they would gain important allies in reducing it. It all starts with creating some awareness of the concept. A good technique is for teams to offer past examples where specific technical debt caused issues that affected the customers or stakeholders. There are more such examples than one thinks!

Another technique for raising awareness is to work with stakeholders to help them find aspects of their own work where “technical” debt was present. For example, overly complex spreadsheets with way more tabs than needed that have accumulated over time; or complicated processes that are no longer efficient but that don’t “hurt enough” to change; or even more simply, a legacy folder structure and naming convention that make it hard to find files.

With engineering teams, have them recall times when they successfully managed tech debt. Engineers like to share war stories, so perhaps you can organize a brown bag lunch where one engineer or a group walks others through the most gnarly instances of tech debt they had to deal with. It’s important to connect the technical details to the costs of the debt. Before embarking on the mission to reduce the tech debt, in what ways did this make the engineers’ life harder? What defects happened? What couldn’t the engineers do?

Another exercise that can create more awareness and start equipping the team with a vocabulary to talk about tech debt is analyzing their own codebase and coming up with the “Hall of Fame”.

  • What is the most notable tech debt in our codebase? Here engineers often note that there are multiple dimensions along which they can assess debt. Hopefully teams will talk about the impact that this debt has on the business, or on their productivity (and thus, indirectly, on the business).
  • How did it come about? This may require more tenured engineers to share the context, or someone doing a little code archaeology. It’s also a good opportunity to connect to the types of tech debt we discussed in the previous part.
  • What makes it hard to address? Does tight coupling mean that it’s not possible the address it in isolation? Does it require us to fundamentally rethink our solution? Is the “right” solution simply hard to come up with? Connect the answer here to some estimate of effort involved to address the tech debt item. If an item comes with much technical uncertainty, what tech spike can the team do to reduce this uncertainty?
  • Now the teams should have enough information to start reasoning through the “ROI” of addressing a particular piece of tech debt

Various teams often work on codebases with vastly different levels of tech debt. Does one team deliver comparable functionality in half the team? Does one product show much higher defect rates? An astute leader can leverage this fact and have the teams share their experiences without attributing blame (often, teams inherit codebases or consist of more junior engineers; and some codebases are more complex than others, or requirements less mature, thus making the code prone to high levels of tech debt). This sharing exercise can help teams take a mental trip outside of their codebases, which sometimes helps them understand just how much tech debt exists in their own code.

A more structured way to raise awareness about teams’ tech debt levels is to take an inventory of their technology. This is a good exercise for aspiring tech leads or new team managers, and it usually brings about surprising insights. Given the following prompt, teams should rate each category on a 1-10 scale and, more importantly, write down factors that could make it a 10 (Don’t accept a “it’s already 10” as an answer; if needed, challenge the team to find something wrong).

  • Starting with lowest level, code legibility and quality of documentation
  • Code structure (the right amount of reuse? Easy to navigate the codebase? Does the structure reflect how the team thinks about the system?)
  • Abstractions / data model (is it easy to describe behaviors and interactions? Is complex functionality needed to perform seemingly simple tasks?)
  • Code patterns (is there a lot of boilerplate? Are methods awkward or confusing to call? Are there lots of code optimizations that make it harder to understand?)
  • Data access (is it clear how data flows through the system? Is caching confusing the flow?)
  • Data architecture (is the right data framework, e.g. NoSQL, chosen for the system?)
  • System architecture (is the solution structured into intuitive services?)
  • Product (are requirements convoluted? Do they change a lot? Are there lots of assumptions that need to be made by engineers?)
  • Process (is the SDLC complicated? Does the code need to be aware of the build/test/deploy process?)

Hopefully after these conversations, the team will appreciate the problem and will be eager to launch into solutions.

Manage tech debt

Manage tech debt the way you would manage features.

The above is probably the most valuable piece of advice I always give leaders – but it’s also one of the hardest to heed. Most leaders don’t incorporate this into their process.

What does it mean to manage tech debt the same way as we manage features? Simply put, all work furthers business outcomes, regardless if it’s a feature that the users have been begging for, or work that reduces tech debt deep inside the codebase. All too often teams arrive at a shared understanding that feature work helps the business, while tech debt work makes the engineers happy. The truth is that tech debt can affect the product, and the business, just as much as features do. Often, the impact has a longer time horizon (e.g. tech debt which makes the product unmaintainable once it hits certain scale), or is more indirect (e.g. tech debt makes all development work take twice as long), or is about preventing an issue rather than creating a capability. It is true that by this token, it’s not as easy to talk about tech debt, but if teams invest in the vocabulary and context needed to discuss the merits of various tech debt items, they will be able to make better product prioritization decisions.

| As an aside, it is often said that nobody gets credit for what did not happen. There is some truth to this – humans, and especially our users and stakeholders, will respond stronger to some new piece of functionality than “boring” work that increases stability or enabled scalability. But with the right amount of persistence, and through enough conversations, the stakeholders can be trained to spot and value second-order consequences, averted risks, and longer-term value. Hopefully the dialog between the stakeholders (who tend to undervalue the future) and engineers (who tend to undervalue today) will yield the right prioritization decisions.

Managing tech debt and features in the same way means that teams should have a single backlog and compare tech debt items to features. Many teams arrive at some sort of “shadow process” where they agree on some – often arbitrary – percentage of the team’s bandwidth that is dedicated to tech debt, and the PMs/stakeholders “leave the team be”; or tech leaders schedule a whole lot of tech debt work in a burst after the team mutinies or after the product reaches an unacceptable level of quality. Instead, tech debt should be analyzed for ROI and slotted in with other work, like the first class citizen that it is.

How should we enable our stakeholders to assess and prioritize tech debt items? Start by doing an exercise together with your stakeholders, presenting various examples of work – contrasting actual product work that team did or hypothetical features with technical and tech debt work. Ask your stakeholders to simply point out the more valuable item. Their bias may be clear, but they will likely not mark every feature more important than any tech debt item. Use these cases to start reasoning through the value of tech debt.

Fnd someone on the business side who cares about each particular piece of tech debt. This could be a stakeholder who’s frustrated at the product’s defect rate, a technical product manager who understands why tech debt work is important, or a customer service agent who has noticed the product slowing down and is worried about what this mean for the future. Turn them into an evangelist – have them do some work for you explaining why tech debt is important. You will be surprised how knowledgeable people are willing to make themselves if there is something at stake for them.

Plan how you’ll address tech debt

Usually, tech debt is best addressed incrementally, not through large refactoring efforts. Part of this pattern is an outcome of how tech debt is treated – teams are starved out of work and have to rush to do as much as they can in a single phase (often after a very large release). This yo-yo tech diet isn’t healthy and distorts the value and cost of tech debt.

Moreover, when tech debt work is done in large chunks, its benefit is almost always overstated, and its cost – understated. This is because teams imagine themselves eliminating all tech debt of a particular type, and find it hard to visualize how the new solution will need to fit in within the existing constraints.

Doing work incrementally doesn’t mean it can’t be ambitious. My advice to teams that have great ambitions is to sequence and structure the work so that it provides incremental value in chunks/milestones. A common retort is that it won’t be as efficient. That’s right. But the benefits of sequencing the work far outweigh the small efficiency gains of trying to do everything at once. Teams often fear that by being asked to work incrementally, they won’t really be allowed to solve the whole problem. I assuage their concern by telling them that all of the milestones are “funded” today, and that they exist for the team to course correct themselves as needed.

The strategy behind the launch of the new work is often as important as the work itself. Can the team launch incrementally in a way that reduces the surface area of tech debt as we go? Can the team gradually sunset the old code, or do we need to maintain two solutions for an extended period of time? Again, a solution that is 20% less efficient but that eliminates tech debt as we go is superior to the hyper-optimized one.

Measure and Assess

Measure how successful your tech debt work has been. How it given you the benefits? If not, what can the team learn about their codebase, their assumptions, or their ability to design solutions? Needless to say, it helps immensely to write down success criteria ahead of time, so that the team members can be honest with themselves about the benefit of the work they’ve done.

Final observations

Tech debt scales not just with the age of the code, but also with the size of the team and the surface area of the product/complexity of the offerings. It may be helpful to think about company-level tech debt, as well individual-level in addition to the team-level.

  • Company-level debt exists across group boundaries and is often revealed when teams try to test and release their code. Pay close attention to work that multiple teams have to collaborate on
  • Individual-level debt pertains to assumptions and knowledge gaps that a particular individual has, which causes them to write code with particular weaknesses in mind. Spend time looking at each engineers’ contributions to identify themes and figure out how you can help them reduce their own debt

Finally, while I focused my deeper dive on technical debt specifically, there are other types of debt that teams tend to neglect. The benefit of thinking through non-technical debt is that it is a conversation you can (and should) have with other functional leaders, who likely will see instances of this type of debt on their teams. This includes:

  • Organizational debt – teams that are not structured in ways that allow them to be effective
  • Knowledge debt – lack of knowledge (or, worse still, incorrect assumptions) that slows the team down
  • Process debt – process that’s inflexible, too heavy-handed, built on exceptions, or optimized for the wrong objective (e.g. for visibility for executives rather than velocity of team)
  • Team debt – frictions or mistrust between team members which lowers their effectiveness as a team

Just like tech debt, these categories can accumulate debt over time (often through inertia and the path of least resistance, e.g. process being added to satisfy an executive but which makes everyone else’s work a little bit harder), which gradually decreases the team’s output. Addressing the debt requires an investment of time and effort. My advice to leaders is to be a bit post-technical and think about these categories just as they consider how to recognize and manage tech debt proper.