Product Crafter Emilio Carrión

Technical Debt is like gardening

The weeds of software

When we start writing software, everything is always simple to implement. We have an empty field in which to start planting new functionalities. As time goes by, we add more and more code, more and more systems, more and more classes. After months we realize that planting new things starts to cost us a little more, what used to be an empty field is now full of bushes that have been growing without us noticing, and even some weeds have started to appear.

After a year or two, the situation has reached a point that has made it untenable. Adding more functionality or even changing anything is hard and expensive work. In what used to be an open field, now you have to go inside with a machete and sleeping bag, you don’t know when you will be able to get out of there.

That’s technical debt, debt that grows without us realizing it, that we generate at the same time as we grow our software and that, just like complexity, can cause us serious problems.

But one thing is clear, we are the ones who cause it and the ones who have to learn to manage and control it. As Andrew Hunt said in Pragmatic Programmer (though not entirely technical debt-oriented):

Rather than construction, software is more like gardening…

What happens when we don’t prune

We are the ones who usually generate the technical debt. It usually appears when we take shortcuts when implementing the next functionality or change. We don’t do things in the cleanest way or bypass design consensus so that we can deliver the new product to our users as quickly as possible. By doing so, we slowly declutter our software. And that disorder, like the interest on a debt (that’s where the name comes from), grows and accumulates.

However, contrary to what we may imagine, generating technical debt is not a bad thing. It’s actually quite a healthy thing to do. When we’re trying new things, validating new business verticals, or just learning about our users, it’s good to deliver as soon as possible to get that feedback that’s going to move us forward. So, building up a little debt along the way isn’t a bad thing.

The problems come when we never look back and continue to implement functionality after functionality without stopping to prune and clean up the debt we have been generating. To such an extent that it starts eating us up and becomes a problem.

Where do all those weeds come from?

Apart from the problematic debt that comes from the lack of concern for our own plantations, it is common for debt to also appear out of nowhere, like weeds that appear on any given day in your field after watering.

This emerging debt often stems from the very ephemeral nature of the systems we develop. They can be outdated dependencies that start to cause us problems, they can be platforms that become obsolete and have to be migrated to the new ones, they can be third-party systems that disappear or change their conditions.

Weeds that grow and, if we don’t pay them the attention they require, they will get in our way when we want to develop the next new feature.

How to Identify Technical Debt

Identifying technical debt before it’s too late is simple if you pay attention. You can try to look for clues that indicate you have a debt problem. Some of those clues are code smells, taking longer than you had anticipated implementing new functionality, realizing that you have to refactor a large part of your code because it’s so complex and you can’t tackle a change, etc.

Any smell of “this should be easier” indicates that you may have a technical debt problem on your hands.

The best thing to do at that moment is to take note and map out everything you see, why you think it may be a problem and if it is something widespread in the project. Generating a debt backlog that you work on little by little will help you start reducing it.

How to Prioritize Technical Debt

You have to start pruning somewhere. When we talk about debt, the one that hurts the most is always the one that gets in the way when we want to make a change.

The hottest areas of your code, the ones you touch the most, are prone to accumulating debt. And that debt is likely to end up giving you more headaches. Therefore, you have to prioritize cleaning the house you normally live in, those places where you spend most of your time and where accumulating debt can cause the biggest problems.

On the other hand, you’ll eventually touch some old code and acknowledge debt that can be tackled. In those cases, it’s best to avoid temptation. Write down that debt in your backlog to know that it exists and try to continue with the rest, you probably have more important debt to resolve first.

A framework that I really like for prioritizing technical debt is The Technical Debt Wall and that can help you choose which debt requires your most immediate attention and which can wait to be resolved.

How to Avoid Debt

As I have already mentioned, generating debt is not bad, it is a tool we have to advance the delivery of our product to our customers and stakeholders. However, in addition to the conscious debt that we can include to achieve this goal, there is also an unconscious debt that we can inadvertently include in our developments. Whether it’s due to lack of knowledge or bad luck, it’s a problem that affects every team. Some of the ways to avoid it are:

  • Continuous Refactoring: Integrate refactoring into development cycles. It encourages teams to refactor code as they work on new functionality, ensuring ongoing maintenance rather than postponing it to a later stage, when it might be more difficult to tackle.
  • Small steps: Break down projects into smaller, more manageable tasks. This allows for frequent refactors, reducing the chances of accumulating substantial debt over time.
  • Use TDD: Helps keep the focus on code quality, reduces the chances of introducing bugs, and indirectly minimizes technical debt.
  • Code Reviews: Review the code with your colleagues on a regular basis (or better yet, do pairing!). Encourage team members to critique the code not only for its functionality, but also for standards, maintainability, and potential indicators of technical debt.
  • Share knowledge: Facilitates knowledge sharing within teams. This helps distribute expertise and ensures that best practices are followed evenly, reducing the likelihood of accumulating excessive technical debt.
  • Continuous Learning: Encourages continuing education and training for team members. It provides resources and workshops that focus on best practices and strategies for managing technical debt effectively.
  • Technical Debt Awareness: Integrate technical debt discussions into team meetings and product planning sessions. By increasing awareness, team members become more proactive in identifying and addressing potential debt.

It’s everyone’s problem

And finally, don’t just make the technical team aware about the problems and causes of technical debt. Involve all roles on the team. It is essential that members such as designers and product managers know what debt is, how and why it is generated (in the end it is often for the good of the users). That they are aligned with that it is a problem to be taken into account and that it must be managed on an ongoing basis is essential to meet expectations and be all on the same page.

TL;DR

Technical debt reflects the reality where, when developing software, we often make quick decisions or shortcuts that, over time, become obstacles. This debt can appear both from our conscious choices to quickly deliver functionality and from unpredictable external factors, such as outdated platform obsolescence or dependencies.

It’s crucial to identify early signs of this debt, such as signs of problematic code or unexpected difficulties when adding new functionality. Prioritization and debt management become vital, focusing on critical and frequently modified areas of the code, using tools such as the “Technical Debt Wall” to prioritize the most urgent areas.

In addition, we highlight methods to prevent and reduce this backlog, such as continuous refactoring, TDD, frequent code reviews, and knowledge dissemination within the team.

However, it is crucial to recognize that the responsibility for managing this debt does not lie solely with the technical team; All roles must be aware of and committed to its management. Proactive technical debt management is crucial to maintaining quality and efficiency in our long-term software development.

I hope all of this has shed a little more light on the subject. Happy pruning!