‘Technical debt’ is a term we throw around constantly in the software development industry. You might also hear it referred to as "code debt" or the shorthanded and catchier "tech debt." Whatever you call it, though, it's part of our daily lives.
Despite its frequency, what we mean when we say ‘technical debt’ has, in some instances, extended beyond the original metaphor. That’s not a bad thing. The initial definition is immensely useful, and we don’t intend to open yet another debate about whether it’s appropriate.
However, we do think it’s important that engineers, programmers, stakeholders, and anyone else involved in the development process has a shared understanding of the term. That's why we want to extend the definition to encompass every aspect of what we mean by ‘technical debt’. We can then implement the right tactics to manage it effectively for unique business needs—even if we risk a broader definition over-stretching the original technical debt metaphor.
We’re going to offer the simple, yet (we think) complete, definition of technical debt that we’ve been working with at Stepsize. We help high-growth software companies with measuring and managing technical debt, so we’ve found that we need a bit more of a concrete tech debt methodology, one that encompasses what metrics we're looking at and how we're measuring them.
Technical debt is code written yesterday that's a burden today.
At first glance, this might sound as if code becomes technical debt the moment it’s pushed to production, as if everything in your codebase is technical debt.
That's because it kind of is.
The code that engineers or programmers write to solve a problem is based on their current understanding of that problem. It sounds obvious, but it has profound implications. Even if the perfect engineers found the perfect solution to a problem and coded it perfectly, their understanding of the problem will evolve—and quickly.
But left unattended, their code won't.
That's a bad thing. All that hard work in the first place, can easily become bad code after just a few short days. Their code is then no longer appropriate. Its functionality has been compromised in some way. Much like financial debt, this type of debt happens all the time, especially with legacy code. It also happens much faster than you might think in a high-growth environment.
In his book ‘Is High Quality Software Worth the Cost?', Martin Fowler explains that 'software exists in a world of uncertainty.' Because of this, you'll ship your Minimal Viable Product (MVP) or feature quickly, to learn from your users as soon as possible. And if they request a new feature that you didn't quite see coming, that could raise uncomfortable questions about the entire framework you used to solve the problem you thought you were tackling.
Sometimes, you can simply clean up and rework or pull some refactoring magic to match your new understanding of the problem. But such short-term solutions make your code accumulate cruft. This just increases your amount of technical debt.
Developers find poor quality code significantly slows them down within a few weeks.
‘Is High Quality Software Worth the Cost?’ by Martin Fowler
That's why it's important for high-growth organizations to have a plan for managing technical debt.
Martin Fowler argues that it’s worth investing in code quality since it will speed up new feature development. If a new understanding of the problem at hand has changed significantly, we need to take action, or the rest of the programmers on the development team will have a hard time understanding our code and productivity will suffer. In that sense, if it isn't well maintained or thrown away, code we wrote yesterday will inevitably become technical debt and slow the whole team down.
However, not all tech debt is at the same stage of maturity—and that's where the second half of our definition comes into play.
No matter how incredible our development team is, no one can accurately predict the future. This is true in startups, SMBs, and it's especially true in a high-growth environment. That's why we've replaced the waterfall method with Agile development; software isn’t built like cathedrals.
It's often the case that it can take a year of programming on a project before you understand what the best design approach should have been.
Technical debt quadrant, by Martin Fowler
But the best in the business do know how to handle such high uncertainty. They use unit tests when appropriate, continuously refactor code that has accumulated too much cruft, and won't accept bad code as technical debt. Here's a free VSCode extension to help you do all that directly in your editor.
Often, the very real restrictions we face—project deadlines, budget constraints, and more—mean that we can only afford to pay back the most pressing technical debt that’s getting in the way of our most immediate and predictable goals—the code that's a burden today. This is what drove us to write about how to stop wasting engineering time on technical debt.
In such uncertain conditions, the only tech debt that we can really do anything about is that which gets in the way of our most immediate and predictable goals.
Given our broader definition of tech debt, the only real solution is to continuously address the most pressing technical debt as we continue to deliver new features at pace for our customers. That's the tech debt that we know for sure will slow us down today, or soon.
Distinguishing between different types of technical debt—most notably the reckless and prudent kinds—is another important factor in doing this successfully. We have an article in the works on this very topic, so stay tuned!