I have spent a while considering what technical debt is and concluded there is no good definition that is particularly useful to estimate the problem. Instead it is more practical to understand when code should be considered technical debt as this is more useful. Many people don’t know when to tackle technical debt and often choose to tackle it at the wrong time.
It’s common to hear people talking about technical debt as either code which is hard to maintain or code which does not conform to their idea of good code. Fashionable best practices often influence the latter. I will use these two ideas to loosely define technical debt. I believe there isn’t a definition that can quantify debt absolutely, so I’ll use a reasonably simple definition that mirrors how developers think about it in the real world.
At True Clarity we have several separate teams all working on enterprise web applications using fashionable best practices. Each team has roughly the same distribution of skills and experience and equally challenging work. I have reviewing each team’s code many times and each team does have markedly different levels of technical debt.
The interesting thing is that all teams have a reasonably close level of productivity.
I have made similar observations throughout my career. The complexity of the code is often not a contributing factor to productivity. My hypothesis is that familiarity of the code you are working on negates technical debt being a problem. Put another way: the impact of technical debt is inversely related to the familiarity of the debt.
This leads to some interesting conclusion:
- If you have never seen a particular code base before you are more likely to be unproductive and you are more likely to feel like there is technical debt.
- If a code base does not use the coding practices you believe are “best”, it is less likely to seem familiar and therefore you will think it is technical debt.
This highlights the high degree of coupling between productivity and our natural familiarity with something. This statement is obvious in itself, but with code, people seem to forget it.
Another observation at True Clarity is that a team tends to be at its least productivity when we put a brand new person on that team. How quickly that person gets up to speed depends on how easy the code is to read and make changes to (factors like how much time colleagues spend helping the person tend to be equal among the teams).
This means we pay the greatest interest on technical debt when people are new to the code they are working on. This is a pretty consistent observation, and I haven’t seen contrary behaviour (taking motivation out of the equation).
It turns out it is not always observed that you pay interest on technical debt when working on complicated code. It can be quicker to make changes to complicated code if you know what it is doing (because it may support what you want to do quite easily if you have the know how).
Ultimately, you have to decide how often people will be working on unfamiliar code to get a good measure of the true size of technical debt.
The tipping point for tackling technical debt
This actually means there is a tipping point for deciding when, if at all, to tackle technical debt. Let’s say you seldom work on an area of code, but when you do it is very time consuming. Is the cost of rewriting that code greater than the time spent updating it when you need to? That is a question an architect should be having with the business.
So far so bleak, but we can also draw some very positive observations.
If a team spends extra effort making highly readable and maintainable code it often gets a productivity boost that offsets this extra effort. At True Clarity we have never seen a team go much beyond break-even in terms of payback on productivity, however, the ability for new people to get up to speed is very rapid so we have seen good payback in this respect.
To start to tackle technical debt, evaluating the tipping point (when it becomes valuable to the business to rework “bad” code) is the key. By conceptually dividing your code base into the small modular areas you can determine the tipping point of each area. If you are a developer or architect that genuinely understands what is important to the business you may have autonomy to choose when to rewrite code. In the case where you have autonomy you can make those decisions at a very granular level (on a file or method/function level for instance).
Out of interest there is an alternative solution to technical debt: refine your project induction process. By this I mean the human element of induction like coaching and mentoring (i.e. get better at explaining your own software by explaining often and refining your own understanding). Something that documentation can’t replace is learning to communicate your domain expertise to different audiences (after all not all developers need the same information or process information in the same way). I will discuss documentation in another post, the short story is there is a tipping point where documentation becomes debt so it needs care. After all, once a person is familiar with code the interest on technical debt diminishes. This may be a solution if your team is volatile and you don’t know where to start on your debt problem.
Take care rewriting technical debt
I will leave you with one caveat to rewriting code that is another consequence of the fact familiarity reduces debt. Often a developer will rewrite something that makes more sense to them, but another developer will look at the old version and the new version and think there is no improvement. The process of rewriting gives you instant familiarity, therefore leading you into a false sense of “solving” the debt. Unfortunately you have only solved it for yourself, you have not helped the business one bit. Another instance of this is rewriting something using a fashionable new technology where people will immediately feel more at home with the code. This is legitimate as it will help people gain quicker familiarity. The true goal, however, is to make the code really readable without relying on fashionable coding tools/techniques. This involves a real understanding of the cognitive friction involved in a person reading code and extrapolating the business requirements from it. Ultimately, you should be concerned with how easily someone can relate your abstract model to the real world. I have found this last question leads to a satisfactory definition of debt as a cognitive relationship rather than a technical standpoint.