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 application 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 product development will be in the future. All the shortcuts are taken and all the savings on code or architecture quality, accumulate as a metaphorical technical debt. That's a quick and easy way to explain technical debt. Now let`s get to the details.
Code debt no different from the financial 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 its 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 web applications, slowly boiled in a soup of technical debt, getting way too expensive to develop and unprofitable to maintain.
Technical debt examples
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 the 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 struggling 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 updates 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 apps vulnerable to breaches and 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 process 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 development teams to take shortcuts and implement features in an easier, quick-and-dirty way. When pressure is high, even experienced developers take that path, usually with the hope that this code will be improved (refactored) someday. But will it?
Unintentional tech debt and intentional tech debt
An experienced software developer is at least conscious when debt is introduced to meet business needs. But another popular driver of unintentional 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 roadblocks very expensive to overcome.
Some would also say that technical debt comes simply from the laziness of many developers. Although it may be true in some cases, I would argue that it is not that widespread. 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 into 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. At Accesto, we make sure that all developers know WHY they implement particular features and that's maybe why they stay with us for many years.
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 tech debt at any cost?
Financial debt vs tech debt
The previously mentioned analogy of financial debt is very true here. Should you avoid any monetary debt? 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 of it to pay off the financial debt.
The 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 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 deciding on that trade-off, and deliberately accepting 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, henever 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. Unlike financial debt, for tech 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, paying interest later on. Same for technical debt. You release a new feature, you get more users and more revenue, and... you pay off the technical debt. It is always tempting to leave it as it is, not improve that feature, and just start working on another one. But how much technical debt you will be able to handle? Accumulation 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, an intentional 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?
Manage 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 ways of managing technical debt, but it is usually unnecessary and we discourage that approach. Although it is reducing technical debt significantly, it freezes product development for a long time and competition or 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 technical 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 blog post of our CTO on possible scenarios of handling technical debt. And we also have an article about converting the PHP Monolith to Microservices Using the Strangler Pattern, check it out if that's interesting to you.
During the last 5 years at Accesto, we focused mostly on helping successful web applications reduce technical debt accumulated by years of growth. If you are not sure whether it is worth fighting code 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 through 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 code debt is hidden in your web app and suggest the best approach to get rid of it.