We’ve collectively agreed as a software engineering industry to call code we don’t like or whose rationale we’ve forgotten technical “debt,” but we don’t talk about digging out of this debt the same way as we do all the other similar debts in our lives.
Instead, we let it build up until it becomes so burdensome that it’s suffocating, and then we go at it with a big rewrite or initiative that inevitably runs long and makes business executives discount engineering organizations that want to address technical debt wholesale.
And you spent a tremendous amount of goodwill and social capital to get the business to commit to it.
Much like consumer debt payoff plans that try to tackle everything all at once commonly fail, so do common approaches to addressing technical debt.
Engineers complain about it, then complain about nothing being done about it until the pressure raises enough that this cycle begins.
One place I’ve worked in my career went through this cycle multiple times, starting rewrite initiatives in technology after technology until one finally stuck.
I think they’re still running that these days, at least.
If you work inside of a codebase, you know in your bones what technical debt feels like – the sections of a code base that are filled with “good idea at the time” code that everyone is a little afraid to touch because the folks who wrote it are long gone.
Which means the rationale behind the good idea is also long gone. So, you don’t see the tradeoffs that went into why that piece of the app is the way it is, only that there’s this distasteful little corner (or big corner!) that slows everything to a crawl and causes bugs – sometimes subtle ones – all the time.
Leave things better than you found it.
The Boy Scout code of software development
It’s the section of the codebase with the most bugs and the least understanding.
But we do a crap job of telling that story to the larger business, and it’s hard to make the case for maintenance jobs like this in any department and any field.
This is because maintenance work doesn’t mean new revenue, only that things run a bit better, perhaps with fewer complaints. Maybe you can make a case aimed at increased customer satisfaction and less churn.
But when the business weighs that against shiny new features that it can sell immediately to land new revenue, it’s hard to sell technical debt work on a roadmap.
Which is often why things wait until it feels like engineering can put its foot down and insist that some herculean, committed effort must be undertaken for a quarter or longer to address the mountain of technical debt once and for all by doing the big rewrite.
Which becomes somebody else’s technical debt later.
Because, the thing is, code is never done. Maintenance never ends. Code rusts and rots and needs upkeep and care and tending forever and ever.
So, the first mindset shift is to accept that technical debt – aka code maintenance – will always be there, even after you do the massive rewrite that will solve everything.
Instead of tackling technical debt with big heroic efforts once in a while, instead think of it as a regular part of the workload.
One approach is to adopt the Boy Scout model – “Leave things better than you found it” – culturally with your team. This means accepting and encouraging small, incremental improvements to the codebase which might be incidental to the larger work happening.
An important tradeoff here is that it’s been my experience that these sorts of “while we’re here” bits of code tend to be the most likely to cause unforeseen problems once they hit production. Your mileage may vary, but it fits neatly with my earlier stated belief that a lot of what we call technical debt is really forgotten tradeoffs. These tend to rear up once you shift things beneath them.
Another approach I’ve been successful with is to tie technical debt work or code improvements to new product initiatives.
When the business wants the new shiny, point out that to deliver that we’ll need to improve this part of the system. Then, you get the green light to invest in that corner of the app to improve it in service of this new product initiative rather than trying to sell the improvement by itself.
If you’re in a structured scrum or agile system with points and sprints, you can also ticket up, estimate, and fold in technical debt initiatives inside of a sprint by treating them the same as any other work item – low effort, big impact things get folded in more quickly than high-effort rewrites.
Essentially, what I’m arguing for here is to think of your technical debt as something that cannot be wiped out all at once but rather should be approached steadily and incrementally.