Over 4 years ago our CTO wrote a blog post claiming that technical debt is the number one reason why software development projects get derailed. Years have passed since, and I can say that he couldn't be more right. Although I see that business owners get more familiar with the term technical debt, it quite often plays the role of an elephant in the room. And in the long run, such stories rarely have happy endings. So if you don’t know what the technical debt is, or you do but you don’t think you should worry about this villain - better read further.
What is technical debt?
10 years of leading web development projects gave me the knowledge of how various technical decisions influence web applications development in the long run. I observed how hours of work invested in code quality and good software architecture enable future growth of software products and their business success. At the same time, I followed the stories of other products struggling to scale up and develop further due to all the shortcuts taken in the early stages of development.
The lesson is simple - the more hours you save by doing things quick-and-dirty today, the more difficult the product development will be in the future. All the shortcuts taken, all the savings on code or architecture quality, accumulate as a metaphorical technical debt.
Ward Cunningham, an author of that metaphor, highlighted its similarity to the financial debt and interest that you have to pay in the future. A technical loan, that you take out by saving some coding hours today, will make further development and product maintenance more difficult, time-consuming, and expensive. And that is the interest that you pay for cutting corners. But unlike financial, technical debt is way harder to measure and track, so it’s costs are often overlooked or neglected. Let’s see them in more detail.
What are the costs of technical debt?
Technical debt accumulates slowly, usually invisible at the beginning. Gradually making product development less efficient and thus more expensive. Like in a popular among software developers anecdote of a boiling frog. If placed in boiling water, the frog will jump out, but if it is placed in cold water and slowly heated, it will overlook the danger and may be cooked to death. And this is very true for the web applications, slowly boiled in a soup of technical debt, getting way too expensive to develop and unprofitable to maintain.
We experienced it ourselves at Accesto when we had to shut down our own successful product a couple of years ago. It was a popular SaaS tool for the online gaming industry, used by the majority of hosting providers in Poland. Despite the great market traction, we had to discontinue its sales, when costs of development and maintenance outgrew all the profits. After years since we shut it down, we are still getting requests from people willing to pay for it. It was bitter, but a valuable lesson on the technical debt for us.
These days I see more and more web products struggle to grow due to the technical debt. The startup boom for web applications and SaaS products continues for over two decades now. Many of the products that made it to the market did it by taking technical shortcuts. The pressure to deliver quickly and within the budget has its side effects and now some of these products struggle with growing costs of technical debt.
Our main focus at Accesto is to help such products grow, by fighting technical debt and reducing its costs. Among such costs the most common are:
- Decreased web development pace - slowed down by technical roadblocks, rework, hard to understand code, and focus on workarounds instead of efficient development
- Longer time to market for new features - slow development and constant bug fixing makes it difficult to meet any deadlines for releasing new features
- Expensive maintenance - finding and fixing bugs becomes more difficult, lack of automated tests adds a cost of manual testing work with every change in the code
- Reliability issues and recurring bugs - fixing one bug leads to another
- The increased cost of introducing changes - even small update may require changes in many places, that’s because code is tangled with unnecessary dependencies
- Hidden performance defects - software that worked well for a few users starts to clog when the amount of data and number of users increases, app slows down
- Higher uncertainty - more difficult to estimate and plan the web development work
- Technology locking - poor code or architecture makes it hard to update current technology or migrate to a more modern one
- Risk of security defects - old technology makes web app vulnerable to breaches, unreadable code makes it difficult to secure
- Decreasing customer satisfaction - due to recurring bugs, poor performance, and a long time to market for new features, competition won’t miss that chance!!
- Decreased development team motivation - everyday work becomes a constant fight with messy code, bug fixing, and trying not to break something
- The increased cost of hiring web developers - poor availability and high cost of hiring specialists with expertise in old technology and willing to work with legacy code
- Cost of knowledge transfer - lack of documentation and unreadable code makes it hard to understand the project and introduce new team members
- Inability to respond to market opportunities - the cost of missed chances due to long time to market for all changes and features
If you see that your web development slows down, the number of bugs increases, or your dev team starts to complain about the code, do not neglect these symptoms! Further in this article, I will show you some ways of fighting technical debt. But before fixing things, let’s first make sure it won’t get worse. To do so, we have to eliminate (or at least reduce) the drivers of technical debt in your project.
Where does the technical debt come from?
“Don't overcomplicate it, just do the simplest!”
“No matter what, we have to publish it before black Friday!”
“Why is the estimate so high? It’s a simple feature!”
Do these or similar phrases sound familiar to you? Time and budget pressure are among the key drivers of technical debt. Code quality and deliberate planning simply stand in a way of such short term, more urgent goals. This forces developers to take the shortcuts and implement features in an easier, quick-and-dirty way. When pressure is high, even experienced developers take that path, usually with a hope that this code will be improved (refactored) someday. But will it?
Experienced developers are at least conscious when the debt is introduced. But another popular driver of technical debt is the lack of qualified specialists in the product team. Lack of certain skills generates hidden debt that nobody is aware of, which is very risky. This is why projects run by junior web developers may happen to be cheaper at the beginning but quickly lead to the roadblocks very expensive to overcome.
Some would also say that technical debt comes simply from the laziness of developers. Although it may be true in some cases, I would argue if it is that popular. It may be the case with junior developers, but the more experienced developers are, the more they like clean and well thought out solutions. I noticed that instead of cutting the corners they rather tend to overthink and over-engineer.
For sure there is one more catalyst of technical debt - a constant change in business goals and requirements. And in a similar way to time and budget pressure, it may lead even experienced team members to get off the track of deliberate development. The more thought a developer puts in good code design and implementation, the bigger demotivation when he has to throw it away when requirements change. If this happens very often, team members start to care less about the quality and long term impacts of the code they create. There is a lot of truth in saying that the only constant in IT projects is the change. But it is important to discuss all the business goals and underlying purposes with the development team. This will allow them to assess the required quality and foresee the probable changes. Otherwise, they may spend hours meticulously designing something that is just some proof of concept.
Short term benefits of keeping the budget low while developing features quickly are hard to argue, especially in the early MVP stages of the software product. But like with finance, if you neglect the long term perspective and base your cash flow only on the liabilities, you will end up in the debt spiral, sooner or later. So should you avoid technical debt at any cost?
Should I avoid a technical debt at any cost?
The analogy of financial debt is very true here. Should you avoid any financial debts? If you can run and develop your business without taking out any loans then good for you. But in many cases to grow, to develop, you cannot avoid banks. You are not waiting until you save enough money to open a new production line. You take out a loan, you open a line, and you use the profits out of it to pay off the debt.
Same is with technical debt, you accept it to make thighs faster. Especially in the early stages of the business, or when you want to test a new business opportunity. If you are not sure whether some product or feature will get the market traction it is usually a wise choice to limit the initial investment and cut some technical corners. As Neil Ernst mentioned in the Carnegie Mellon University field study, technical debt conceptualizes the tradeoff between the short-term benefit of rapid delivery and long-term value.
But when decide on that tradeoff, and deliberately accept technical debt, please remember that:
When you take a bank loan, you can’t forget about it. If you do, costs are even higher and you won’t risk that situation. But it is way easier to forget about the technical debt, as the interest rate and cost of code shortcuts are not that obvious. So remember, whenever you agree on some technical debt, do it considerably, note it, manage it, and pay it off. Better sooner than too late.
You can't take out loans over and over again and it is true for both finance and software development. If you borrow too much, next time your financial institution will deny lending you more. With technical debt, there is no special institution that will limit your liabilities. So listen to the development team instead. Do they complain about the code quality? Do they mention the refactoring? Talk to them, there is no one else to tell you when too much is too much.
All debts must be paid - simple as that. You borrow money to scale your business and pay off that debt later on. Same for technical debt. You release a new feature, you get more users, more revenue, and... you pay off the technical debt. It is always tempting to leave it as it is, do not improve that feature, just start working on another one. But that will lead to a metaphorical big ball of mud and trust me, it is not something that you want your web application to be.
Not all debts have to be avoided and in many cases a deliberate technical debt can have a positive effect on overall product and business development. But only if you are going to pay it off. But how to do it?
How to pay off the technical debt?
The only solution is to rewrite it from scratch - that may be a popular phrase that you will hear from software developers when they see the codebase of your web application. Don’t be surprised, developers usually don’t like working with old, legacy code, but love new, greenfield projects. Rewriting from scratch is of course one of the solutions to get rid of technical debt, but it is usually unnecessary and we discourage that approach. Although it significantly lowers technical debt, it freezes the product development for a long time and competition and users won’t wait.
Another approach is to continue the development of new features in the old codebase, but with a focus on refactoring. Creating a new module? Do it without taking any shortcuts and also improve parts of the application that relate to that module. This won’t freeze your development and will let you pay off the debt in smaller chunks.
Working with clients at Accesto, we usually implement a solution that goes slightly further. Instead of developing new features in legacy code, we create a new, separate codebase for them. All the new features are implemented in that new part, and the old code is step by step migrated to that new part. More on that approach, you can read in a blogpost of our CTO on possible scenarios of handling technical debt.
During the last 5 years at Accesto, we focused mostly on helping successful web applications to get rid of technical debt accumulated by years of growth. If you are not sure whether it is worth fighting debt in your software let me just mention two of our case studies:
One of our customers reached us when previous developers denied further work on his product, burdened by accumulated technical debt. The approach mentioned above turned into a 35% yearly debt reduction. Their legacy application evolved to highly scalable SaaS in just 2 years, with time to market for new features reduced by 87%.
And our recent story of accelerating SaaS growth by gradual improvements in web architecture. After 1.5 years of cooperation with Accesto, our customer won the Atlassian’s Codegeist 2020 contest for the Best app for remote working. Thanks to the new architecture, the module that won the contest was created in just 3 weeks. Something that would be impossible before.
I am glad that, although a couple of years ago technical debt made us shut down our product, we are now helping others to avoid such bitter decisions. If you are also looking for help, just let me know, we can verify how much debt is hidden in your web app and suggest the best approach to get rid of it.