Technical debt and entropy: what the laws of physics teach us about refactoring code
Understanding the laws of thermodynamics helps you understand technical debt and development team efficiency. When pondering the nature of Agile development teams I realised that these laws have a lot in common with our day-to-day, and sprint-to-sprint challenges.
Technical debt is code that makes it harder to write more code. It may have been rushed, it could be messy, it might not have tests, or the design patterns of the application may have gradually decayed. I’ll tell you how to collaboratively keep developers at maximum efficiency in the long term by managing technical debt, and fighting entropy. The three laws of thermodynamics have interesting similarities to programming in an Agile development team, and they are not always on our side.
One application I work on at Boost is about eight years old, running an older version of Rails, and has three developers devoted to it. It is a major piece of infrastructure for the client, but managing its technical debt is getting harder. This is because the application is growing in functionality, complexity, and the development team has rotated over the last eight years. However, a little technical debt isn’t a bad thing. We manage it head-on with specific user stories to reduce technical debt in certain areas, and lower our system entropy.
The first law of thermodynamics
This is also known as Law of Conservation of Energy. It states that energy cannot be created or destroyed in an isolated system.
Imagine our application as the isolated system, which contains a fixed number of developers. Those developers have a function. They convert user stories into shippable code and features. They do this at a fixed rate. Multiplying their efficiency by the number of developers gives us our team velocity. In our system, we are bound by our ability and efficiency. Developers cannot suddenly write twice as much code in one day, or suddenly think at a higher cognitive level to fix deep-rooted problems in our application. They are only human, and can’t increase their CPU speed to get more done.
In this sense, the energy of our isolated system is fixed. Throw more developers into the system, and our energy will increase. Take developers out of the team, and our energy will decrease. Within a fixed team, energy cannot change.
Product Owners and developers both understand this, and both understand the system in their own way. A unified Product Owner and developer team understand that an application can deliver two kinds of value: what it can deliver today and what it can deliver tomorrow. So together they can tackle entropy head on.
The second law of thermodynamics
This states that the entropy of any isolated system always increases.
Entropy is the lack of order / predictability in a system. It represents the unavailability of a system’s energy to be used for work.
In our system, lack of order equates to technical debt. And technical debt and entropy have a lot in common. Technical debt imposes itself in two ways: developer divergence, and buying time.
Developer divergence happens gradually, due to the difference in developer style, skill level and confidence. When developers convert user stories into shippable code or features, they will never get it perfect the first time. One developer’s merge request will only be a small part of the application. Another developer ships another merge request… and over time the developers increment the application. These changes are often made without a full grasp of the design of the overall code base, and that is perfectly fair in large applications.
Developers can’t read each other’s minds, and they have different ways of writing code… their own ‘style’. This affects the way we approach problems and how we write our code. No matter how great our architecture discussions were before we started, and how rigid our code review and code style practices are… there will always be a divergence of quality, style and complexity of each iteration. This divergence creates inconsistency which can create technical debt as it makes code harder to work on. So system entropy is increasing, and predictability is falling.
Buying time is a different form of technical debt. It is usually small, and by itself, has little impact on the application. An example of this might look like the following scenario:
- pick up user story
- write code
- something doesn’t work as expected, but the better solution is way out of scope of the story
- to do it properly will take three times longer
- you agree with team to ship working code that is not perfect, but solves an immediate problem, and we can improve it in the future.
By buying time to fix an immediate problem, we have bought technical debt. We have knowingly allowed the entropy in our system to increase. Product Owners will love this outcome, as they tend to be delivery-focussed, and rightly so.
Both developer divergence and buying time are different forms of technical debt. They show how it is similar to entropy rising as per the second law. Without refactoring—changing the internal structure of the application to make it easier to understand and cheaper to modify without changing its observable behaviour—the design of the application will gradually decline. As people change code (whether changes to realise short-term goals and buy time, or changes made through developer divergence) the application loses its structure. It becomes harder to see the meaning of the code.
As technical debt and application complexity grow, our system entropy increases. If you are a Product Owner, think of it like this: technical debt makes it harder for developers to get work done, and makes your developers less efficient. Remember, entropy represents the unavailability of a system’s energy to be used for work. I’ll come back to why some technical debt isn’t necessarily a bad thing towards the end.
The third law of thermodynamics
The third law states that the entropy of a system approaches a constant value as the temperature approaches absolute zero.
One way to stop technical debt growing in an application is to stop working on it altogether. However this is unrealistic unless we are retiring it altogether. This would hold our entropy steady, but at the cost of producing nothing at all.
In reality, to keep our technical debt in a manageable state, or to lower our system entropy, we need to pay some of the debt back. We need to apply external energy to increase the order and predictability of our system.
This means developers stop working within the system, but instead work on the system itself. Instead of adding functionality as developers usually do, they change their output to not adding new functionality; instead they focus on changing existing functionality without changing the application’s observable behaviour.
This is refactoring and refactoring lowers your costs over time.
Developers can refactor technical debt on the fly when adding new functionality. However the results will never be as good as tackling it head on and making a clear initiative to reduce system entropy.
Managing technical debt, and lowering system entropy
Boost takes a collaborative approach to slow the growth of technical debt by:
- having solid code and peer review practices
- a peer user story analysis before we start writing code
- ensuring all developers are following the same code style guidelines
- keeping communication lines open between developers and Product Owners.
This won’t change your technical debt, but will ease its growth. Reducing technical debt requires developers to be confident in sharing their view of application complexity and tidiness.
Developers raise the alarm first, as technical debt has a linear relationship to cognitive load, or their ability to get their work done efficiently. The more the debt, the harder it is to work application. The less efficient their energy expended becomes.
In reality technical debt might end up looking like any of the following:
- messy code
- inconsistent code
- multiple responsibility code snippets
- spelling errors
- lack of tests
- obfuscated code
- bug lists… fix one… another pops up.
At Boost, we try to stay on top of this by making sure all the stakeholders are aware of the issues, and on board with the importance of improving the system. Developers are free to draft stories to:
- re-write certain parts of app functionality
- write more tests
- stories to ‘reduce technical debt‘ in this class
- time box stories purely for refactor time.
These points are all about refactoring code. Developers and scrum masters can sell this to stakeholders by stressing that whoever is paying for their time is getting less for their money over time, as their efficiency goes down. However, this requires a certain finesse.
It can be hard to get non-technical minds to empathise. At Boost, we have recently expressed that we need to spend time reducing debt in one area of the 8 year old application. This was because adding new features was becoming harder and harder, and our understanding of how it works was diminishing. This can be daunting for developers. Luckily, our Product Owners are receptive and understand the need for refactoring.
Finally…technical debt isn’t a bad thing
Like other types of debt, a little technical debt is okay to have. It’s not a bad thing. We take on debt because we need to get things done. We need to ship a product, a piece of code, add a new feature and so on. When we buy some technical debt, we are really buying:
- flexibility, especially when we don’t know the direction the code base will be going in
- delivery deadlines
- maintaining team velocity.
Comparing technical debt with the laws of thermodynamics helps us understand why our applications can grow in complexity over time. This happens even if we have great code review practices and style guides. Often it’s out of our control.
If you’re a Product Owner, keep your ears to the ground. Listen for those grumbling developers who are finding it harder to get work done. Equally, developers should let Product Owners know what state the application is in, and draft user stories on how to fix it.
Product Owners and developers allow for refactoring on the fly, or as a separate task, to manage technical debt. As a team, you can slow the growth of technical debt.
At Boost we do these things, and we’re also keen to learn what you do to fight system entropy.
Scaled Agile Framework – The Team Level — how SAFe handles technical debt
Test Driven Development and Agile — how TDD helps reduce technical debt
How Agile transparency reduces project risk — clearing technical debt to increase transparency
Risk transparency case study — increasing visibility to reduce technical debt