The subject of technical debt comes up often in software development. It is better to have something done sooner rather than later from the perspective of the project. Yet, this assumes all things are equal, which is rarely the case. Often a developer will have a choice: the short term path or the long term path. For example, a task can be done in 2 hours with one implementation. A different implementation will take 6 hours. However, the 2 hour implementation will result in additional 10 hours of maintenance (in the form of bugs or confusion among other developers) performed by developers every 2 months for eternity, while the 6 hour implementation leaves the development team free and clear. Technical debt is named such because of the “interest rate” paid for in development time.
I knew a developer who tried to save himself 2 hours when starting a new project. The shortcut required that the entire web application to load before the user could interact with it. At the beginning that was 30 seconds (can you imagine that?!) and steadily increased as new features were added (more code equals a larger application). Not only that, but it relied on a single binary file that ONLY ONE person in a 6 person team could work on at any point in time. That is a serious productivity killer. You may be asking “why not just take the 2 hours to fix it?” Think about a construction company cutting corners on the foundation of a skyscraper. They then try to fix it after the entire building is built. Not so easy right? My estimate on that fix after 6 months of development was an entire month for that team. All that because one developer was lazy and tried to save himself 2 hours.
This may seem extreme, but it is also closer to the low end of how bad technical debt can get. An entire team can consist of developers like these who rapidly add more and more debt as time goes on. Plenty of companies end up finding that they have to rebuild their entire system at a certain point. Their technical debt is doing one or more of the following:
- Lots of bugs and the time to fix each one is extremely high (e.g. 1 day instead of 15 minutes)
- Really slow implementation time for new features (weeks/months instead of days)
- Not built to handle that many users so the site goes down often
For this reason, many developers argue for zero technical debt and spending as much time as needed to get things “right” from the beginning. Any additional time spent to build something in the beginning would be completely justified by the time savings in the future. After seeing the cases above, how could anyone think anything else?
The problem with this argument is that it takes a black and white view of technical debt. Like financial debt, technical debt comes in all shapes and sizes. Some of it is actually quite useful. Why does anyone take on financial debt today? Usually it is because they can make more money with that debt than they are paying in the interest. The same can be true for technical debt. Take a startup that has 1 million dollars in funding and a developer that costs $100,000 a year. That developer is 10% of the startup’s working capital. Now take a project that could take 2 weeks, with lots of technical debt, or 6 weeks with little technical debt. If the 2 week solution results in the entire project needing to be redone in a year with the 6 week solution, the company has just “wasted” ~$12,000. HOWEVER, what if the company after a year gets 10 million dollars in funding? That developer is now 1% of working capital and rebuilding the feature is 0.12%. The following graph illustrates the point:
Taking on that technical becomes a bargain if it helps the company achieve the new valuation. The challenge for the company and the developer is to monitor when that feature needs to be rebuilt. They need to make sure that the cost of rebuilding will never be greater than the cost of building that system from scratch (as in the case I mentioned earlier). If this is all true, the company can use its increased valuation to hire more developers. These developers can continue to building features at a rapid pace. That makes up for the need to allocate one developer to rebuild something in 6 weeks. Not only that, but the original developer had 4 weeks freed from the original development to work. That is time spent on different opportunities for the company. These opportunities could also increase a company’s valuation even further.
Another fact to consider is that not all features are successful. That is why companies run A/B tests (where half of users see an “A” version of a product and half see a “B” version). The point of an A/B test is to see if users will actually prefer the new version of the product before it is rolled out to everyone. If the test results are not in favor of the new version, there may either be new revisions or it is thrown out. What would be the point of spending large amounts of engineering time polishing something that may get thrown out? That is time that could be spent making more A/B tests or other projects. The time to polish the technology a feature is built on is when a development team knows it will be a success.
The last and most important point I can make about technical debt is this: every line of code an engineer writes is some form of technical debt.
Technical debt is when the code written is not as good as it could be. However, what defines “as good as it could be”? Does it mean that a developer is 100% satisfied with it even after a year has passed since writing it? I’d argue that the developer has not learned much in that year if they can not think of a better solution. And that is an unavoidable fact in development. No matter how much care a developer puts into writing their code, they should WANT to be unhappy with it eventually. That is the mark of learning. Many developers, including myself, have spent too much time early on in their careers trying to make things “perfect”. Disappointment follows a few months later because we have grown as developers. That “perfect” code suddenly looks like garbage. The only way any complex code can be considered pristine for a long period of time is if that code’s author stopped thinking of ways to improve. Writing code to be as good as it can be only counts for a single moment in time. That code will be technical debt when that moment passes.