Technical Debt – Deal with it Now or It’ll Deal with You: Part I
This is the Part I in the blog series Technical Debt – Deal with it Now or it’ll Deal with you. Catch up with Part II: Identifying Technical Debt and Part III: Dealing with Technical Debt.
Technical debt, while over two decades old, is a term very much of the essence in this age of Agile development, Lean startups, Minimum Viable Products and DevOps practices. Technical debt has been a phenomenon since the first mainframe punchcard but with a much broader swath of our economy being dominated by businesses viewing themselves as “software companies” and “product development” referring to software more often than any durable good, an increasingly broad set of stakeholders feel the effects of technical debt.
What Is Technical Debt?
Ward Cunningham, hugely influential computer scientist and co-creator of Extreme Programming, is generally credited with coining the term “technical debt” in 1992 as follows:
“Shipping first-time code is like going into debt. A little debt speeds development so long as it is paid back promptly with a rewrite… The danger occurs when the debt is not repaid. Every minute spent on not-quite-right code counts as interest on that debt. Entire engineering organizations can be brought to a stand-still under the debt load of an unconsolidated implementation…”
I love Ward’s definition and find it painfully accurate. I find the following to be a more pragmatic definition and one that is most intuitive to product managers (who happen to be those being called on to drive remediation of technical debt):
“Quick, dirty or otherwise inadvisable development that leads to more work later so that the shortcuts taken won’t lead to bugs or make future changes hard to implement.”
Technical Debt Smells
As a technical manager, product manager or Agile Product Owner, how can you get a feel for the level of technical debt in your digital products? How can you gauge whether technical debt is increasing or decreasing? Once we’ve covered more characteristics about technical debt we will cover some good tools for a quantitative assessment of your code bases but for now we will talk about quantitative assessments – use of intuitive “code smells”.
Kent Beck coined the term “Code Smell” as a surface-level indication (in other words, you’re likely to notice it if you’re near it) that usually corresponds to a deeper problem with the code. Just as food that smells a little funny might not guarantee that it is spoiled, you should probably check the food out before you eat it. In software, code smells are usually not as obvious as outright bugs but if you’re tuned in you’ll definitely notice them. The following are some classic technical debt smells:
Simple Functional Changes or Additions Take a Long Time
For instance, you have determined that you need to add a “salutation” and “suffix” field to your CRM application and your development team greets you with pained looks and/or racks several days of work to make the change. The amount of work to unpack and remediate debt-ridden logic while building out your additions is adding major unexpected cost to your project.
Bug Fixes Take a Long Time
A problem comes in from the field that your web application is rendering a key page in poor form on smartphones. The bug takes three days, senior development staff is called in and extensive late hours are put in.
Code Changes for Small Additions Frequently Lead to Bugs
In the course of the addition the “salutation” and “suffix” fields to your CRM application, three reports break and the data update feature breaks. Seemingly unrelated features regress to broken states for no apparent reason.
Developers Actively Avoid Being Assigned to the Code
Your development team actively avoids being assigned to the team working on your apps. Word spreads quickly among the corps when an app’s technical debt has grown out of control and soon it will be difficult to get your developers of choice to voluntarily work on your app.
The Application Operates Slower Than You’d Expect or Slower Than It Used To
You use your app for day-to-day work and the slowdown from how it worked a year ago is palpable. Technical debt has a way of gumming up the works in an application. Workarounds mount and inefficient legacy code dominates the application, bringing it to a crawl.
Any of the above sound familiar? If so that is not a guarantee that you have mounting technical debt but it would be wise to dig deeper and involve technical staff to evaluate your software for the presence of technical debt.
Consequences of Technical Debt
Other than for academic reasons, why should you worry about technical debt? Putting an end to the smells above is alone probably reason enough. However, let’s dig a little deeper to see things you will need to deal with if you leave technical debt unattended.
Interest Payments
Every time developers work with your app, every time a support request comes in and each time you make small adjustments your developers will need to make a hard choice: add to technical debt (making the situation worse) or re-write portions of the software to unwind the technical debt and make progress. This is completely analogous to financial debt: either make interest payments on your loan or sink further into debt.
Unpredictable Tipping Point
Technical debt often takes the form of sub-optimal and often rough workarounds within code that developers have used either out of necessity to meet a deadline or out of a lack of skill. As these aspects of the code base build up there can come a time far enough into the application’s life in which the application is built up of more workaround code than advisably-built professional code. At this point developers will spend more time understanding and working around the various jury rigs than they will contributing to rigorous solutions. Once this happens you are at a tipping point in which more time is spent keeping the software operating and it will become completely unpredictable how long code changes and functional additions are likely to take.
Increased Time to Delivery
Predominant technical debt and code rot leads to developer and architect discussions and in-depth planning to make changes to the code and still deliver quality product. There will be times when, despite this planning, developers run into pockets of the code base that are more entrenched in outdated technologies or unsustainable implementations that side-tracks to shore up the hidden technical debt is greater than projected. Thus, despite the longer prediction than you expected (see above) the actual timeframe can stretch out even further.
Significant Number of Defects
In modern software development, developers and engineers rely on extensive unit, integration and functional tests to run during each commit and catch any instances of regression – times when working on a new feature breaks an old feature. Code bases with a large extent of technical debt are often absent these kinds of automated tests – as a result regressions do occur at a higher rate than normally expected.
Rising Development and Support Costs
Because of the many ways in which high technical debt applications result in lengthier planning, existing code re-writes and sub-optimal coding approaches the time (and associated cost) for in-house staff to work with the application goes up along with the cost of frequent out-of-house consulting required at times to remediated particularly thorny code bases.
Product Atrophy
Because of the above product owners are not as interested in working with a software application – when they do so they are often rewarded with buggy releases, budget overages and delayed timelines. As such they avoid activating teams to work with the application and thus rot continues to build.
Decreased Predictability
Just as developers, engineers and product owners receive constant surprises from technical debt-ridden software the business receives less precise signals as to timeline and cost for maintenance and incremental development. Upper management and product benefactors begin to lose faith in the application and the team as predictability and their ability to make proper business decisions goes out the window.
Underperformance
While we have spent a great bit of time covering the ways in which working with technical debt-ridden applications makes developer and engineer lives difficult, costly and drawn-out there are also very real consequences to the users of applications with high levels of technical debt. Due to the presence of antiquated technologies, algorithmic workarounds and rushed work the actual response time, availability and server/cloud resources of the application will suffer.
Decreased Customer Satisfaction
Rolling together all of the things above about technical and business impacts of technical debt you’re going to see customer satisfaction slip. As such you will soon hear from your end users that they have felt the bite of technical debt.
Not All Technical Debt Is Bad
There are indeed strategically and practically sounds reasons to plan for the creation of technical debt. That may sound very counter-intuitive and granted there aren’t many reasons. But the few reasons that do exist are very good reasons. First, let’s talk about why you need to be careful about this.
Strategically allowing or even encouraging the creation of technical debt is a very valid strategy in certain circumstances. One specific example is a product that is planned to have a short life. Since it’s not going to live long it does not have to be built to withstand a strong legacy; we’ll only need to make debt payments for a very short period of time – and then the app will be shut down. In this case it makes sense to build the product quickly, just good enough to last the short time and then retire it, along with the debt, as soon as possible. It does not make economic sense to gold-plate a short-term solution.
The same can be said for a product nearing its end of life. Eric Ries contends that in a Lean world the value prototypes bring are to validate theories, give learning and stir interest/establish the proof of concept. Since prototypes are intended to be thrown away, this approach is a special case of the “don’t worry about technical debt for products with a short life”.
One very defensible rationale for intentional technical debt is for a “throwaway prototype”. You may have significant interest in a big new application but not quite achieved full budgetary support to build it in full. You may be asked to put together a proof of concept for a very reduced budget to determine viability of the application to solve business problems and to get feedback from potential users. As such a quick prototype with non-production tooling, lower-cost staff and non-enterprise approaches can be taken to provide the appearance of near-complete application such that it can be put in front of customers.
This approach gives the opportunity for very realistic feedback on needed features, the things that have the most value, pointers on what the usability should be like and then a better decision on scope and project sponsorship can be made. Then this prototype can be thrown in the trash and a fully-funded enterprise solution can be developed with these learnings – what you have learned in this process will greatly exceed the cost of the thrown-away prototype. Whatever you do, do not build upon your rough prototype for the real solution! If you do so you will enter an entirely unprecedented world of technical pain.
Check out part II in this series to learn about identifying technical debt and part III about dealing with technical debt.