Technical Debt as a Product-Engineering Issue
I originally published this article on Medium, in November 2021. This is a bit shorter version.
A search of the current literature reveals many definitions of "technical debt." Here are a few examples:
Technical debt is a concept in programming that reflects the extra development work that arises when code that is easy to implement in the short run is used instead of applying the best overall solution. - From techopedia.com
Technical debt … is the result of prioritizing speedy delivery over perfect code. - From productplan.com
Even excellent code can become a problem
Most definitions of technical debt focus on selecting the easy approach instead of the right one as the cause. But that' is not the only reason engineers write code that is not future-proof. It's a very common reason, but it's not the only one.
There are millions of lines of badly written code that work sufficiently well, deliver value, and will never have any kind of bad effect on anything. There are implementations full of antipatterns and bad practices that serve the needed purpose, and nobody will ever deep dive into that code because it doesn't generate any defects. I am convinced that many lines of bad code reside in the devices we happily use every day. Are these lines of code "technical debt" or just "impurities"? How relevant are they?
I assume that some readers are now thinking "this author is advocating quick and dirty solutions just to produce features," which is not true. There is a very good reason why best practices of programming exist. They represent the accumulated experience of generations of engineers. We should study and use that experience. But even technical excellence and following all the best practices can't guarantee that there will be no refactoring (technical debt) in the future.
No matter how we implement a system, at one moment in the future that implementation may become unfit. So, in my view, this is a better definition of technical debt:
Technical debt is the unfitness of code written in the past to meet today's needs.
Knowing the reasons why the code doesn't fit anymore will help us avoid some of the similar issues later. But when we start to notice the effects of technical debt on the business (and our productivity), we need to fix it. Every team has faced this challenge sooner or later.
Sometimes technical debt is so big that it hinders or even prevents further product development. These clunky components of unfit code are embedded in products whether we like it or not. And this is where product/business colleagues can help a lot. If we can explain and quantify the impact of tech debt issues on the business we can treat them as a part of produuct management.
How technical debt affects the Business/Product
All products need maintenance. Maintenance takes time. Engineering time is a scarce resource in many companies, and we want to use it optimally. Some systems need just a bit of maintenance from time to time, and some systems require daily work just to keep them running.
To be profitable, the value a product generates should be higher than the sum of expenses to run it. Engineering time is one of those expenses. It's the simple economics of any investment, and that's what software development is: an investment. Technical debt increases operational expenses and that negatively affects the overall profit. The more technical debt we remove, the more time is left for developing the product further. That's one of the ways how the removal of technical debt directly contributes to the business. It reduces the cost of running products, which increases profit.
It also has a lot of less tangible benefits: engineers' satisfaction (retention), cognitive load (impact of quality), motivation, focus, productivity, and even security. Technical debt often causes toil: manual, numbing, cognitive load, and repetitive work. It can also slow down or even stop further product development.
Left unattended for long enough, technical debt can even stall a business. When software development can't catch up with new business needs, the company usually starts a "modernization" or "technical transformation" project. These can be years-long, painful efforts that drain the enthusiasm and motivation of everyone involved, but most visibly - drain the budget. Technical transformations can feel like re-implementing the same thing again. It is often difficult to get the proper recognition and credit for the work done on technical transformation - if the business value is not clear for everyone.
The best way to prevent expensive and exhausting "modernizations" is to continually resolve smaller parts of technical debt and never let it accumulate. It's more of a planning problem than anything else. But only a few (usually experienced) apply that principle.
"The techies will handle it"
In our industry today we often see a strong distinction between "product" and "engineering" departments. Well-known frameworks and methodologies reinforce that silo. Job titles and responsibilities, personal "KPIs" and organizational trends support this division. The dominant thought pattern in the current era is "Product people should make and prioritize the requirements and engineers should implement them." Which makes perfect sense. But there are always trade-offs:
- engineers are not familiar with business requirements (they just look at tickets descriptions) and the business context, and
- product teams don't know what kind of work is needed to build and run their products (investment).
This separation of responsibilities leads to a separation of knowledge (and people make decisions based on information that they have). When we talked about the technical debt I heard colleagues from Product saying something along the lines: "The techies will handle it, it's their responsibility to make sure the systems run reliably."
Coming up with new features is the most glorified aspect of the product profession, and that makes sense. But profit is - broadly speaking - a difference between revenue and costs. Understanding the effects of technical debt is essential for understanding the costs of running a product, and technical debt can become a huge part of these costs. It's necessary to partner up with "techies" to optimize for profit. Otherwise, a CFO, or whoever is responsible for the budget, may ask why do we have so many employees producing disproportional output.
Technical debt is a part of any product, and can't be avoided. Every time you write a line of code you create a possible technical debt, not because the engineers are bad, but because today's requirements are different than tomorrow's, and nobody can predict with 100% certainty what will be optimal in the future. Of course, experienced people have more chances to guess better, but it's impossible to completely avoid technical debt. It is about constant control and managing it.
Symptoms of technical debt
Here are some frequently seen signals of technical debt:
- More and more bug fixes.
- Increases in the time engineers spend on maintenance.
- Slower and slower releases.
- You hear things like "it's complicated" and "we're late because we discovered new things" more and more often.
- Engineers complain about toil and cumbersome development.
- Engineers push back when you want to introduce new features because "it's complex".
- The team's health and mood changes because of tech debt.
- The product becomes unstable.
- ...and other.
Some of these signals are obvious, while others are more subjective and require a measuring/tracking method. For example, lengthened release schedules. If we don't have data in place, we only have subjective opinions which can differ from person to person. That can be sufficient in some cases, but nothing can replace data. It pays to think about and implement a small number of measures for each team or product: some simple "data signal" which you can interpret to detect technical debt. One of these signals can be, for example, the frequency of release. Another idea requires more effort to measure: a relative proportion of time spent on developing new things as compared to the maintenance of an existing system.
How to handle technical debt: Product-Engineering partnership
How do we decide what technical debt is important? We need good cost-benefit analysis and some measure of impact: "how much will it cost us if we don't take care of this?" This estimation is often vague because nobody can predict the future. That makes it even more important to approach the impact with as much business mindset as possible.
Who can make this cost-benefit analysis? The topic is technical debt, so technical people must be involved. But engineers usually aren't skilled in writing good cost-benefit analysis and business prioritization - and that's why tech debt is partly a product issue.
We can observe technical debt as a part of the product that needs changes. Like any feature that brings value, removing tech debt also brings value. That implies prioritization and putting tech debt handling on the roadmaps. To do that, we need to know the value that resolving technical debt will create.
It's also important to remember that not all technical debt is relevant at the same time, so we need to re-prioritize and re-estimate technical debt from time to time. Managing technical debt is an ongoing activity.
One possible process for handling technical debt
Here is one of the possible solutions for handling technical debt.
- Have periodic lightweight sessions with engineers to collect information about technical debt. Keep a list of tech debt issues.
- Evaluate the effects of the technical issues team finds most relevant. Per each issue: the time you save, cognitive load, speed of delivery, saving money, security - all these could be the benefits of solving tech debt. And you need to evaluate the effort of handling it.
- Select the most beneficial technical issues to solve and plan a work breakdown (milestones, architectural diagrams, dependencies, etc.). Treat it like you would treat any other product initiative.
- Partner with your Product team members. One possible approach is to agree on how much time you want to dedicate to handling the technical debt issues. Sometimes it's 20% of the roadmap time, sometimes 10% and sometimes the best decision is to dedicate more than 50%. It is both Product and Engineering question.
- Put it on the roadmap, but I'd recommend to focus only on a few topics at the time.
Two more things
- Don't work on too many issues at once.
It's very rare that technical debt issues are not connected in some way, and if they are, the complexity multiplies. For example, the availability of people who can work on a particular issue, or architectural changes and integrations that make it more complex to work on more issues in parallel, etc. It's helpful if big transformative projects can be broken down into smaller, autonomous chunks.
- Find a way to celebrate the success of removing technical debt and connect that result with the company goals.
This will keep the team involved motivated and the business happy. It's about making partnerships, and when you are able to present the data about how your team contributed to the overall success, those partnerships will come about naturally. One trick for keeping the momentum rolling is to start small. Choose a smaller milestone or project to prove to everyone (including yourself) that this system works. And change the system if it doesn't work well for you.