There has been some renewed discussion recently on the subject of technical debt, this has been played out on twitter as well as a variety of blog posts including this one.
The technical debt metaphor is one I use often and I believe that there is some clarification required around this subject.
At it’s broadest, technical debt is any trait of the current system that is considered sub optimal from a technical perspective. The debt aspect reflects the cost of ownership of that trait. For example and overly complex and untidy method is sub optimal, it incurs cost each time it needs to be re-visited and re-understood due to either a defect in the logic or a new requirement. This method obviously incurs more cost if it is re-visited more often.
Much of the debate recently has been focused on the times that it might be good to incur technical debt. The debt metaphor reminds us of borrowing money from the bank to get that new toy a little sooner. The question here is two fold, does technical borrowing exists and how can we view the rate of interest or total cost.
Before we can consider technical borrowing we need to split technical debt into two categories. First, the design or implementation decision that was sound the day it was made but now, with new information, is constraining our ability to progress. Second, the quick and dirty approach that we can see on the day of writing is gong to cost us very soon.
The first category of debt is a direct result of doing the simplest thing that could work and resisting the temptation to predict the future. We develop simple software that is easily changed through effective use of tests, the code that is written is written well. We categorise these design traits as debt when new information presents its self and we identify a change that will enable the system to serve us better. We may decide to make the change or not based on the ongoing cost of maintaining an design that no longer reflects our understanding of the problem or technology.
The second category is often the result of a deadline looming. A common chorus of “lets hack this in now and we’ll fix it later” is coupled with the nagging concern that later never arrives. In my mind, this category of debt can give the first category a bad name. But, is this thinking sound? Surely there are times when the wrong technical solution is the right business decision. It is my belief that there are situations where a quick fix is the right decision, imagine a major flaw that brings down a trading system. However, there are too many instances where code bases become un-maintainable through a feeling of time pressure that leads developers to incur debt with little or no benefit. In fact, in most cases, untidy, poorly designed software incurs cost both short and long term. In the short term, defects delay the release of the software and in the long term software is difficult to maintain and rigid in the face of changing business need.
So we arrive at technical borrowing. The decision to borrow must be explicit. As a team, along with appropriate stake-holders consider the decision. For example,
we have selected framework X for the next release, it does not offer the scaling flexibility we would like but we believe that our early entry to the market is a higher priority. We plan to move to framework Y in the next release window to achieve our target scaleability.
There are less extreme examples of refactorings that should be done but won’t fit in this iteration. Again, be explicit. Discuss the need for refactoring with your Product Owner or Project Manager, consider the cost of the refactoring, the cost incurred by not doing so, the risk of refactoring. One approach to maintaining a healthy code base is to keep a backlog of refactoring and allocate time in each iteration.
However, beware the temptation to save time, get it done, do a quick fix or tidy it up later. In almost all cases code that is hurried, poorly designed, overly complex or untidy will incur far more cost both short and long term than the time saved today by not doing it right.
Finally, this can be most difficult in a legacy code base where technical debt abounds. I use a simple motto that has served me well with a few teams:
Do no harm!
Where you cannot fix it all be sure to agree, as a team, that you won’t make it worse. In fact agree to making one small aspect of everything you touch better for the next person.