Search This Blog

Monday, May 17, 2010

Technical Debt

What is Technical Debt?

The term "technical debt" describes the obligation that a software development organization incurs when it chooses, knowingly or unknowingly, a design that saves time or money in the short term, but in the long term increases complexity and ends up being more costly. There are two basic kinds of technical debt; intentional and unintentional. The first occurs when an organization makes a conscious decision to optimize for the present rather than the future.

This is not always a bad thing. For strategic reasons, companies often incur technical debt when time to market is critical or to preserve startup capital, preferring to pay for the expense out of later (and hopefully greater) revenue than critical startup resources. Eventually, however, the debt must be paid.

At best, technical debt can be annoying, making maintenance difficult and slowing productivity. At its worst, it can make forward progress impossible and destroy productivity. Steve McConnell acknowledges that “if a company’s technical debt grows large enough, eventually the company will spend more on servicing its debt than it invests in increasing the value of its other assets. A common example is a legacy code base in which so much work goes into keeping a production system running (i.e., ‘servicing the debt’) that there is little time left over to add new capabilities to the system.” (McConnell, 2010) The industry estimates that it spends up 80% of its total cost on software maintenance (Pressman, 1992). We need to understand technical debt better, adopt in only when we have to, avoid it when we can, know it when we have it, and know what to do with it when we have it.

Signs of Debt

There are a number of ways you can tell if your software has developed significant technical debt. Here is a list of things to look for:

1. Large backlog of bugs
2. Fragile code
3. Unmaintainable/uncommented code and/or outdated comments
4. Security issues
5. Missing infrastructure
6. Lack of documentation and standards
7. Over-reliance on tribal knowledge for maintenance
8. Lack of understanding that you have technical debt and/or ignoring it

As the technical debt increases, and the size of the code base increases, it is important to note that the maintainability costs exponentially rise, and eventually reaches critical mass such that the code becomes unmaintainable. Every new line of code may be a potential new mine in a mine field; a ticking time bomb in a brittle code base where layers of technical debt have created ever increasing levels of risk when the source code needs to be touched. And the source code usually does need to be continually touched to meet continuing customer needs.

Fast, Cheap, Good: Pick Two

It’s been said that lowering quality lengthens development time. This is because the burden of the technical debt must eventually be paid off. If you’re a cowboy coder and you simply hack some code out, it may seem like you get the code out sooner, but the technical debt that must be paid off is much greater compared to the senior developer who creates a full set of unit tests, good designs, and code that is fully performant, secure, reliable, and maintainable from the start. Boehm (2000) discovered that as software proceeds through the life cycle it becomes progressively more expensive to change. Software does not get better over time; it gets worse - unless you actively take steps to fight the decay. In a word, software rots.

Unfortunately, many have interpreted this inflating cost curve to mean that you must produce perfect requirements, followed by perfect specifications, followed by perfect designs, etc. This is not what Boehm’s work suggests. Rather, the software base must be kept resilient and maintainable to keep it prepared for any further customer changes. Code bases begin to accrue technical debt when they are “moved into maintenance” and stop being refactored by the development team as new features are added and bugs are fixed. Refactoring is the process of restructuring an existing body of software without changing its external behavior for the purpose of improving readability, maintainability or to reduce complexity. Refactoring and unit testing are a primary means of fighting software rot.

Once you recognize that you have technical debt and that you have been accruing it, have a transparent discussion with your business owners about the costs of the technical debt. Chances are they may already be aware of it, at least indirectly, by recognizing the signs I’ve listed above. Make sure they understand what the technical debt of the code base is costing the business. They may have unrealistic expectations from software developers working on a legacy codebase. Other teams may be able to develop new features faster (or will be able to develop new features at all), and this may be frustrating to them. Part of this buy-in will be to develop some long-range thinking on the part of the business owners. This type of development is an investment that will yield dividends in the form of higher productivity and higher quality.

Paying off your technical debt

In order to pay your technical debt off you must first understand it. Where is your technical debt occurring, and how is it affecting your business? Do you have high maintainability costs? Look at your bug regression rates. Look at your backlog of bugs. Look at your code metrics. Do you have security issues? Do STRIDE-based security threat modeling on your application to understand potential security threats. Do you have adequate technical documentation and artifacts with respect to the product architecture? Do you have adequate unit tests in place before you start refactoring the code base? You need to list out your technical debt and make it durable by placing it in a permanent, visible location, like a team SharePoint site.

One thing developers love to do is to throw the old code out and start from scratch. I will agree with Joel Spolsky (2010) on this point and suggest that this is almost always a stupid idea. Legacy code may be hard to read, poorly architected, and full of bugs, but it’s been used, tested, and contains a great deal of real-world domain knowledge, bug-fixes and market leadership that will be discarded if you start from scratch. Better to iterate and refactor.

After understanding the nature of the technical debt you have, you need to build a business case with the entire team, including the product owners, on paying down the technical debt. Like most debt, you won’t be able to pay it all off at once, but a little at a time. After you have buy-in from all stakeholders, allocate a small portion of each sprint and pay off the most profitable debt items first. As long as you are paying down more debt than you are accruing, you will be incrementally improving quality and decreasing risk.

Working off technical debt can be a great way to boost team morale. If your Product Owners can be convinced to surface product backlog items dedicated to retiring technical debt, or even devoting entire sprints to the effort, measurable performance and quality improvements can be made which can be highly motivational for the entire team. These improvements will inevitably show up in improved customer satisfaction ratings as well.

References

Boehm, B. (2000). Software Cost Estimation with COCOMO II. New Jersey: Prentice Hall.

McConnell, S. (2010). 10x Software Development. Retrieved May 17, 2010 from http://blogs.construx.com/blogs/stevemcc/archive/2007/11/01/technical-debt-2.aspx.

Pressman, R., (1992). Software Engineering: A Practitioner's Approach. New York: McGraw-Hill.

Spolsky, J. (2010). Things you should never do, Part I. Retrieved May 17, 2010 from http://www.joelonsoftware.com/articles/fog0000000069.html.

1 comment:

  1. Do not wait until it is too late to remedy the situation. A vairation of 20/80 rules: 20% of total cost will solve 80% of the problems should prevention is taken in the beginning while 80% of total cost may not even be able to solve less than 20% of the problems when timing is missed.

    ReplyDelete