Technical debt

main points:

Definition of Tech Debt

  1. A concept in software development that reflects the implied cost of additional rework

  2. Known ways I've seen people repay technical debt

  3. The problem

  4. The light at the end of the tunnel

  5. First: Stop calling it Technical Debt: this is good for internal communications within the team or purely as a metric to understand at a glance how "good" are the solutions we implement and the status of the code base. Don't use it for anything else.

  6. for the existing tickets:

  7. group them by topic (NOT called TECHNICAL DEBT) as initiatives

  8. decide how vital each initiative is

  9. In the process, review the tickets and make sure these are clear.

  10. submit this to the AL and make sure everything is transparent in terms of priority

  11. make sure the initiative is clear to all stakeholders

  12. Can we avoid it?

  13. Sure, just avoid creating technical debt.

  14. Accept you will eventually create poor solutions or "good enough" solutions.

  15. Rather have a solid testing strategy.

  16. Make sure you keep track of any technical debt you have in the code by topic and see if these are going to be a problem over time (as an agreement at the team level)

  17. Ingest relevant problems as a team and tackle them either in an isolated way or as part of a product initiative.

  18. Use investigation time for product initiatives to assess possible future solutions and how they are impacting existing issues.

We live in a world based on technical debt.

I cannot stand technical debt.

After all these years working in software engineering, "Technical Debt" started to sound like it doesn't mean anything, at least in practical terms.

The term was coined in 1992 by Ward Cunningham. It is a metaphor that equates software development to the financial world: the idea being that every time we ship first-time code, we accrue debt. It's the price to pay to ship code fast, and it's a tolerable debt as long as it's repaid immediately.

Somehow the current situation is much more complicated than this, and debt has become intrinsic and constant, not just a problem with shipping code fast.

Some examples off the top of my head include:

  1. Work that didn't make the cut
  2. Suboptimal implementations
  3. Insufficient or not clear implementation details
  4. Inappropriate architectural implementation (e.g. implementing a feature without understanding/looking at the context where this feature sits in)
  5. Lack of tests (or testing strategy)
  6. Lack of alignment to standards
  7. Last-minute changes (potentially)

To add to this list, let's not forget that software and the system it resides in evolve over time. So it was surprising and stressful that many project managers I worked with in my career did not understand this basic concept.

Behind the scenes, most modern software abstracts many complexities to dependencies that help solve some niche and specific problems. These dependencies will cause rippling effects as they and their own dependencies will evolve over time.

On the surface, the debt of user-facing products will be affected by the evolution of usability patterns and user needs: the problem you have solved today might not be the same problem you'll find tomorrow.

And as you can imagine, ignoring any of the above can only cause problems. Knowing how to handle it is the key to psychological safety for a team and the success of its product.

Donts

I have witnessed first-hand a lot of teams dealing with technical debt in either one of the following ways:

  1. By not looking at it
  2. By "ingesting" some of the tickets every sprint (or, more likely, when there's time for that)
  3. By agreeing to spend X% of the time addressing it

The last two also meant knowing what constituted "Tech Debt".

Unless the team is "in a good place" (e.g. the speed they create technical debt is lower than the speed to deliver anything), any of the above solutions won't work.

Even then, it can be a tedious process and will need discovery, discussions, refinements, and ownership of the codebase. Especially when it starts touching code areas that other teams share and use.

This usually leads to someone saying:

  • "There is too much technical debt" or "The team is swamped with technical debt."
  • Sometimes, this is paired with "The Stakeholder Y does not understand why the team has so much technical debt."

So let's see a few things that worked for me to avoid suffering further from these problems.

Team process and handling debt

First: Stop calling it Technical Debt: this is good for internal communications within the team or purely as a metric to understand at a glance how "good" are the solutions we implement and the status of the code base. Don't use it for anything else.

for the existing tickets:

  1. group them by topic (NOT called TECHNICAL DEBT) as initiatives
  2. decide how vital each initiative is
  3. In the process, review the tickets and make sure these are clear.
  4. Share this with engineering and product leads and make sure everything is transparent in terms of priorities.

make sure the initiative is clear to all stakeholders

The most significant shift in attitude and engagement I've seen in teams has been with the removal of technical debt. Of course, I'm not talking about paying off technical debt! Can you imagine? I would be the most famous person in the world.

No, I'm talking about calling technical debt what it is:

  • Dependency X upgrade (and correlated refactoring since it's a major release)
  • Addressing the memory leakage
  • Increase of parsing performance of X%
  • Modularisation of the code to allow Feature X and Y to be released without creating bottlenecks in the delivery
  • etc.

The idea is to remove the concept of Technical Debt entirely and make sure the team owns the system/product/infrastructure.

Stakeholder management

While talking about tech debt is OK for well-informed technical stakeholders, relating it to more concrete actions as defined above can only help.

The main problem I've faced over time has been how the work on technical debt can be understood and how we can make sure we communicate what this work solves in terms of company needs.

An example I can bring relates to the work of a team I joined a while ago. The initial assessment of the code made clear there was no architectural plan or organisation (big ball of mud type of thing), making any expansion of the code in the direction product wanted to take it extremely painful and lengthy. This was also exacerbated by many old dependencies that nobody took care of updating in ages, which resulted in a difficult situation: the need to update due to security vulnerabilities was hindered by a series of breaking changes due to Major release updates.

The team was frustrated as they were highly conscious of working on outdated code while the rest of the world was evolving and solving some of the problems they faced (think in terms of well-known bugs). Furthermore, any additional feature work asked by Product meant they were likely never to hit any deadline, if not by shipping more and more first-time code.