I always had a big interest in the topic of technical debt (I will use TD for short). Technical debt exists to a certain extent in every project which I’ve been in development for more than a few weeks and influences the life of every developer. If you have a lot of it then your life is going to be full of suffering and the delivery time of new features will grow with every release. Therefore I believe that’s it’s crucial to find a fine balance during development and understand when technical debt creation is actually justified and when existing technical debt has to be taken care of even if it can slow down development for the short time.
What is technical debt?
Not a surprise but many developers, as well as project managers, have often a different understanding of what do we call technical debt. So the first thing that’s important in the team for me is to agree on the definition of TD. It will allow us to have a common language as well as to distinguish it from different types of technical tasks and issues such as performance issues or bugs.
Wikipedia definition states:
Technical debt is a concept in software development that reflects the implied cost of additional rework and omitted internal quality and productivity caused by choosing a not optimally structured technical solution or architectural design now instead of using a better approach that would take longer.
This definition is fine but a bit complex to remember it easy so I personally like to use a bit simplified version.
Technical debt is not optimally structured technical implementation or architectural design which slows our ability to deliver future features.
An important part of this definition is that TD slows our ability to deliver future features by the fact that we have to deal with the consequences of past decisions. It ties a problem of TD to the business side of software development and helps to justify the necessity to reduce it to product managers and product owners. As well as corresponds with metaphor of technical debt itself – alike financial debt it makes us pay interest on our past decisions and if this interest is not paid in time then often the future interest will increase and can become truly crippling and make the team spend most of their time paying for the past decisions instead of implementing new features.
Let me bring some concrete examples of Technical Debt:
- Cruft (a term coined by Martin Fowler) – a general term for deficiencies in internal quality that make it harder than it would ideally be to modify and extend the system further
- Code duplication of a significant amount of code
- Design that requires to be touched in many places for adding simple features or content
- Deep inheritance where composition would be preferred
- Decisions that do not fit current needs
- Side effect coding
- Not data-driven but hardcoded design
- Information overflow in logs without possibility to filter it
- General architecture and design which doesn’t fit purpose or use case
I also like to use Martin Fowler’s Technical Debt Quadrant to distinct between reckless and prudent technical debt. It allows us to distinguishes the choices and their reasons behind the design flaws. A mess, lack of knowledge during the implementation, a bad decision without good reason is a reckless debt which results in a significant slow-downs later and a long period of paying down to get back the speed. The prudent or mindful debt, on the other hand, means that developers make conscious decisions to bring a TD to reach a milestone, a retention test or to fix an urgent bug and they are aware of cost and implications which they will have to carry with it. I recommend reading the full article from Martin Fowler on this topic.
Why is it important to take care of TD?
As I mentioned earlier having Technical Debt means that you will pay some interest each time when you try to implement a feature that touches or uses code with TD. This interest will be manifested in different forms – hard to understand the code base, hard to add or change functionality, easy to introduce bugs. But in the end, all of them will result in extra time which developers have to spend. More time to understand, more time to maintain, more time to change or add, and more time to fix bugs caused by TD related code.
When is it justified to create a technical debt?
Deciding when the creation of Tech Debt is acceptable and when it should be avoided.
First of all, you always should avoid the reckless type of Technical Debt. Only calculated deliberate and prudent Technical Debt can be acceptable. To prevent reckless debt you need a lot of seniority in your team, enough time for technical design, and a good understanding of how exactly your chosen architecture and the current solution will affect your development speed later.
So naturally, the next question is – how do we decide in individual cases when Tech Debt creation is acceptable and brings the team closer to its main goal and when it’s not. We want to measure the risks and implications of possible Technical Debt. Often developers and product managers would think that creation of TD is justified because quick and dirty solutions or not entirely thought through design will give you a short-term development boost.
A useful concept for this is Design Payoff Line by Martin Fowler. When you start development there is a period when the low internal quality can be more productive than taking the high track. During this time there is a possible trade-off between quality and cost. But there is a moment when trading off internal quality for the sake of getting an additional speed will start to harm you much more. For instance, you might want to ensure that you can keep a balance and try to move this line to a certain important milestone when project fate is decided (like releasing an MVP – minimum viable product). I really like this concept or Design Payoff Line and recommend to read more about it here at Martin’s Fowler Design Stamina Hypothesis.
To do that we need to bring certain rules or guidelines when technical debt is acceptable to create. They will depend on the project to project and from the stage to stage. I recommend using guidelines instead of strict rules which have to be followed precisely because it gives more flexibility. For our current project, we formulated these guidelines in the shape of ‘signs’ or ‘flags’. When the creation of TD has certain signs it gives us additional arguments for one decision or another. If you have more signs that Tech Debt creation should be avoided than signs that it will be acceptable then it’s a strong argument to avoid it.
Example of signs for and against in our current project.
Signs when the creation of Tech Debt is acceptable
- it’s unlikely to affect us before the retention test
- prototypes, research or proof-of-concept code
- very unlikely to change in close future
- it allows to bring hotfix faster
- proper solution takes significantly longer to implement (2x longer)
Signs when the creation of Tech Debt should be avoided
- proper solution will take less than a day
- could result in player-facing issues (small lagging or flickering)
- coding style and low-level code smells (improper naming, magic variables, etc)
- will have an impact on hard-to-change systems (systems with external dependencies such as serialization)
- doesn’t align with main architectural decisions (like a system which does something in a totally different way without a good reason)
- likely to introduce bugs by improper usage (bad API method signature which is used widely in different components)
- will slow down other departments (game designers, artists)
As I mentioned before all these are signs are not strict rules which tell you what to do. You still have to decide on each case if TD creation is justified and use your common sense and individual circumstances but these signs allow you to do that easier by understanding better the implications, consequences and build up your arguments.
This post covers a base concept of technical debt and one of the principles of how you can decide when the creation of technical debt actually brings benefits to your project. These principles are just a tool and you still need a lot of discipline, experience, and healthy pragmatism to find a fin balance between short-term gains and long-lasting consequences of the creation of the Technical Debt. In the next post, I will cover how to deal with already existing technical debt, how to track it, and how to prioritize it and start paying it back.
While researching a topic of technical debt I found out a little board game purpose of which is to explain and experience the effects and consequences of
adding feature after feature and accumulating technical debt or doing and investing in continuous refactoring. Full ruleset and explanation could be found here Technical Debt Game.
InnoGames is hiring! Check out open positions and join our awesome international team in Hamburg at the certified Great Place to Work®.