We’re starting a new series on technical debt. In this first post, we explain what technical debt is and why it’s important.
You can find cars, phones, houses, aircrafts, and a plethora of devices we use in our everyday lives that are controlled by some type of software system. And in the last one to two years, article after article has appeared talking about the fact that software is everywhere and recommending that “traditional” companies change the way and the pace at which they deliver software.
Now that everyone is aware that software has indeed eaten the world, we need to understand why technical debt is eating software.
Right about now you’re probably thinking, “Wait a minute. What do you mean? What is technical debt and how is it affecting the software we use?”
In this post — the first in a new series on technical debt and software quality — I’ll try to explain in simple terms what technical debt is and how it affects software and businesses in general.
The Kitchen Metaphor
If you Google the term “technical debt,” I’m sure you will find many good definitions, descriptions, and explanations.
However, when I introduce a new word or idea, I always prefer to discuss it in a simple way before diving into the technical details. So, let me explain the concept of technical debt using a kitchen metaphor.
Imagine that you are an excellent cook. It’s Friday night and you have invited some friends to your place for a dinner party. You want to prepare a delicious meal. But, at the same time, you want to spend as much time as you can with your guests.
When dinner is ready to be served, you decide to leave the kitchen without cleaning up and go back to your friends. The next morning, you wake up and want to make a quick breakfast before starting your day. The kitchen is a mess from the previous night’s meal. But you woke up late and don’t want to lose the whole day by doing a deep clean.
So, you set the scouring pads aside and decide to just clear some space by stacking the dirty dishes in the sink. Your breakfast is ready in five minutes and you move on to the other items on your Saturday task list.
Now imagine that you and the rest of your household do this same thing for a whole week. You prepare meals but always leave the kitchen worse than you found it.
It’s very probable that after 10 days it will be impossible to work in the kitchen. Even worse, it will be a nightmare to properly clean it up. So, you take the brave decision and blow it up.
The above example makes absolute sense to our topic of technical debt if we think about the following analogies:
The kitchen is the software system.
The dishes you prepare are some cool new features that customers expect to get in the forthcoming release.
The preparation of those dishes is the code you add or modify in the codebase, and the mess left after those 10 days is — yes, you guessed correctly — the technical debt.
Should Technical Debt Always Be Avoided?
After reading the kitchen metaphor, you might assume that technical debt is an evil thing that must always be avoided. It turns out that is both true and false.
The meal preparation example again comes to the rescue and will help make this concept easier to understand.
When you are making something to eat, you probably use some cooking pots, a cutting board, a few utensils, etc. Unless you are a cleaning maniac or you want to use the same pot again, you rarely wash them before you eat.
I usually eat, take a nap, and then I clean everything up later. And most people would agree that it’s absolutely fine to leave the kitchen a mess for a little while.
The same applies to software. It’s OK to have technical debt for some period of time. Actually, since there’s always someone who is cooking in the kitchen (since developers add/modify/remove code all the time), there’s no such thing as software without technical debt.
Instead, the key question to ask is: How long are we allowed to leave the kitchen in such a mess? There’s no one-size-fits-all answer. I can’t give you a specific number in hours or days or even weeks.
Instead, I prefer this approach: Before someone else wants to use the kitchen, clean it up and put everything back in its place.
To put this same sentiment in terms of software development: Before you move to the next feature or bug fix, make sure that you haven’t created any new technical debt in the codebase.
How Does Technical Debt Affect Software Development?
What kind of mess can developers create when they make changes to the code?
When a new file is added but it’s not covered by unit tests, when they copy and paste some code that they believe works and looks close to this new task, or even when they don’t document some design or architectural change, technical debt can occur.
In other words, all those little things that developers know are wrong when they’re doing them but don’t have the time to fix contributes to technical debt. There are always better things to do than refactoring this 2000 line class, right?
Certainly you will not need to blow up your system after 10 days like we would have to do with the kitchen. However, the cost of fixing a bug or adding a new feature to a module that is so over-complicated that a single code change would break everything is something that you should care about.
You might be tempted to compare technical debt with financial debt. At first glance, this might sound reasonable. If you don’t pay the debt now (fix the code today) you will have to pay some interest in the future (spend more time to fix the same code). The big difference, however, is that financial debt is usually relatively stable, whereas technical debt increases exponentially over time.
So, that’s why it’s important to always pay attention to technical debt. And to keep your team motivated to do so, here are some of the rewards of keeping technical debt in check:
- Reduce defects in terms of number and severity
- Increase maintainability and productivity (how fast you can add new features)
- “Predict” the future by eliminating surprises in the codebase
- Do better release planning and respect the dates you set
- Keep the morale and happiness of your developers at the highest possible level
On the other hand, long-term technical debt can cause a variety of security and performance problems. In some cases, these problems (such as data leaking, severe production outages, or significant performance delays) could even cause a catastrophe that will lead to the business’s death.
In future articles, I will discuss how to compute technical debt and how to present it in a simple format that is easily readable by humans. Before that, though, it’s good to understand that there are many different types of technical debt.
Flavors of Technical Debt
Although it’s a common practice to compute the technical debt as a whole and report a single number to the management or development team, we can break it up into four different flavors or types.
Perhaps the most well-known type of technical debt, which is caused by poor design and architecture, is design debt.
This kind of debt is created primarily by developers who put bad code into the system. Duplications, the absence of design patterns, or not following coding standards or best practices are some of the basic root causes of design debt.
But why would developers — even the best ones — write bad code? The following example will make things clear.
You can imagine quality and technical debt as the material in an hourglass. The higher the quality, the lower the technical debt that you have to pay and vice versa.
In theory, this means that if you apply care to the quality of the system, then you will constantly have low technical debt. However, in reality, almost all development teams work under pressure and at some point are forced to take shortcuts that sacrifice the quality of their code.
This choice usually allows teams to run a 100m sprint and boost their short-term productivity to quickly deliver customer features. If they don’t get back as soon as possible to improve the quality, however, future changes that they will need to make to that part of the code will be more expensive.
And the next time they have to fix something in the code within a tight deadline, they will be imprisoned again in the same cell. They will not have the time to properly refactor the code and will add some more technical debt. And it becomes a vicious cycle that never ends.
But fear not. In a future article, I will explain some strategies to work with and eliminate technical debt even in large, legacy systems that seem hopeless.
Next comes a type of technical debt called testing debt, which is caused — you’ve probably already guessed it — by the lack of testing or by poor testing quality.
The most common patterns that can be used to recognize testing debt are:
- complete absence of testing
- tests that should run but don’t
- tests that are unreliable because they randomly fail or take too long to finish
- mismatches between test scenarios and actual testing
- outdated tests
The root causes of such debt are more or less the same as with design debt. Testing is still considered a luxury for many development teams, and it’s not uncommon to see developers who completely ignore writing tests because they “want to be more productive.”
But, when the team realizes that the absence of testing is causing problems to the system and doesn’t allow them to make quick changes, they will need much more time to do it. This is essentially the interest on the debt they have to pay.
Test suites are the safety pillow for every software system. Writing software without testing is like participating in extreme sports without wearing any protective gear.
The third type of technical debt to consider is documentation debt.
Developers sometimes seem to consider documentation to be hard labor. I partially agree with those who prefer writing clean and readable code rather than comments and documentation. But, that is only one side of the coin.
There are several things that need to be well documented and kept continuously up to date, including:
- API and common libraries documentation
- Requirements, user stories, and any other sources that describe the system functionality
- High-level design and architecture documentation (You don’t need to keep every little piece of the system updated but a document presenting the overall architecture and possible integrations should always be available.)
Last but not least, there is a type of technical debt known as defect debt.
Defect debt describes the known defects that are not yet fixed because they are low priority, low severity, or there’s a known work-around. Some other cases include defects that have been reported but are rarely reproduced or are reproduced only under extreme or corner cases.
Sometimes defect debt is computed as part of the design debt. But in some cases, it’s better to have a clear picture of the defect debt on its own, such as when you need to make important decisions about the future of a product.
In this first post of the series, I explained the concept of technical debt using the kitchen metaphor and why it’s important to measure before it completely eats your software.
I identified the main factors that cause developers to produce technical debt and also clarified that there’s some distinction between good and bad technical debt. As noted above, it’s not a problem to introduce technical debt during the implementation of new features as long as developers work to clean it up before moving on to the next feature or bug fix.
Finally, I discussed the four flavors of technical debt (design, testing, documentation, and defect) and shared some common symptoms that can help you identify the existence of each type of debt.
Technical debt is eating software in many ways, and this article was just the beginning of our journey. Stay tuned for my next posts in which I’ll explain how to measure the debt and share strategies to eliminate it.