How to Get Yourself Out of Technical Debt
This week, for reader question Tuesday, the question couldn’t be simpler. It’s about technical debt, and here’s how it goes:
How do you get out of tech debt?
I told you it was simple.
I’ve talked about technical debt a number of times on this blog. I offered my own definition years ago (in another reader question, actually). I’ve talked about why it exists, and I’ve written at times about how you can use NDepend to identify and quantify it. But I guess I’ve never really talked in any detail about how to escape it.
Let’s do that today.
Not to Be Flippant, But You Can Always Just Run from Technical Debt
Come to think of it, there was another post that I wrote on the subject of technical debt. It was about the human cost.
On a long enough timeline, technical debt creates a lot of misery in the office. Team members tend toward finger pointing and infighting, and a sense of embarrassment pervades. Nobody likes explaining over and over again to stakeholders that seemingly simple changes are actually really hard.
So you might just take a breath one day and ask yourself if life isn’t too short to keep coming in every day and gingerly massaging some 20 year old, battleship gray Winforms app into shape. Maybe it’s time to move on to greener and more satisfying pastures.
Now, bear in mind that I’m not advocating that you quit your job every time the team makes a technical decision you don’t agree with. I’m talking about a situation that feels like a true dead end and where you can feel your market worth slipping day over day. It’s not a decision to make lightly, but you should understand that crushing technical debt isn’t something you have to tolerate indefinitely, either.
Declare Bankruptcy and Total the Application
Moving away from your most dramatic option, I’ll get to one that probably won’t entirely be your decision. (Though maybe it will, if you get to level 4 on this scale.) That involves declaring the application with all of the tech debt to be a total. In other words, you rewrite/retire/sunset the thing and call it a day.
Now this is a nuanced recommendation for me, personally, though. Years ago, I wrote a post for NDepend entitled “The Myth of the Software Rewrite.” The idea with that post was to be leery of a team that worked itself into a ton of technical debt declaring a rewrite the only way forward. I said this because that team is just going to make a mess in the new codebase. A team should be capable of covering legacy code with tests and evolving it piecemeal into a more modern system.
I still believe that just as much now.
But that’s a narrower situation than what I’m talking about here. You might have inherited a codebase from somewhere else entirely, or the entire team might have turned over since the original writing of the code. Or maybe it’s just an application whose user base is in decline.
Whatever the case may be, this is an option for getting away from tech debt, though this should be more of a strategic business decision than a tactical way to make life easier.
Embark on an Intense Legacy Rescue
Here’s something you’re likely to have more control over, if not total control. You can lobby to tackle the problem head on, with an intense effort. This is sometimes called legacy rescue.
The idea is that you put normal work on hold, and do the codebase equivalent of a massive spring cleaning. First you’ll need to get the thing under test. This means meticulously capturing current application behavior with characterization tests.
With a test suite in place, you can start to rework parts of the codebase, preserving existing behavior. The idea here is to pay down as much technical debt as you can with one sustained, Herculean effort. Go rip out that chain of singletons that has spread through your codebase like kudzu and is making it a nightmare. While you’re at it, get rid of the rest of the global state, too. Move away from your old-time, home-rolled ORM that uses code generation to spew out data access objects.
You get the idea.
Like band-aid removal, just do it in one fast, painful effort and get it over with. When you’re done and your tests are passing, the future should look brighter. You’ll certainly have some issues to contend with and a lot of testing to do beyond the automated suite you’ve created. But you’ll be on a path to joy, and away from crippling tech debt.
Form a Plan and Chip Away at it Over Time
Speaking of band-aid removal, you can always go the other way, too. Instead of ripping it off fast and painfully, you can drag it out with marginally less pain as you go. But it goes on a lot longer.
Same with working your way out from unhealthy amounts of technical debt. If circumstances simply don’t allow you to spend many days or even weeks reworking parts of your codebase, you can come up with a plan to chip away at it little by little.
You can do this by adopting a policy of following the boy scout rule with code. Make sure you’re writing unit tests and that you’re constantly improving the code you touch a little bit at a time as you go. The unit tests are critical so that you always have the confidence to refactor.
But on top of adopting that as general good policy for tech debt avoidance, you should also make a plan. Look at the biggest sources of slowness and pain, and figure out how you’re going to address them over the long haul. Then break those big tasks into subsequently smaller component tasks until you hit a point where the component tasks fit seamlessly in with your regular work.
Then simply have a backlog and keep chipping away.
Avoid Creating Technical Debt in the Future
Those are really the main strategies that I can think of off the top of my head. Of course, to some extent you can blend them (e.g. remediate with a plan eventually to sunset or do a bit of intense rework followed by a longer tail effort). Or you might have other ideas that are more specific to a given situation.
But in the end, it comes down to two main things. First, you have to make the decision as to whether you can drive the change you’re looking for in the codebase or whether you have to go elsewhere. And secondly, no matter what you decide, understand the nature of the problem — how the crippling technical debt came about. That way you can get better at avoiding such situations in the future and contributing to the fix when you do encounter them.
Technical debt is neither completely avoidable, nor is it always even necessarily a bad thing (in the short term, anyway). It’s going to surround you and affect you throughout your career. So do you part to minimize it by not creating it and by helping to pay it down when it exists for whatever reason. And, failing those things, declaring bankruptcy and moving on from a hopeless team is a lot less painful than the financial world’s version of bankruptcy.By the way, if you liked this post and you're new here, check out this page as a good place to start for more content that you might enjoy.
Great points on technical debt, it really struck a chord with me. Having witnessed application bankruptcy and a rewrite gone wrong I wholeheartedly agree with your statement: “be leery of a team that worked itself into a ton of technical debt declaring a rewrite the only way forward…that team is just going to make a mess in the new codebase.” Leadership, or whomever suggests the rewrite, absolutely needs to understand the problem. In my particular experience the team couldn’t get out of technical debt because they continued working the same way they had before, nothing changed. The rewrite failed and… Read more »
I’ve seen that a lot, FWIW. That’s, in part, why I led with the “run away” option. When it comes to work circumstances, I’ve found that not all pain is gain.
Doubled-down on a bad investment.
If your codebase is large, when going to the long refactoring route, it’s very important to share a clear target architecture with everyone. Otherwise, we risk having disorganized initiatives going in divergent directions.
We’re facing this particular issue at work and planning to use event storming sessions to draw a target context map.
What are event storming sessions?
I think the whole issue of technical debt would be a lot easier to discuss and deal with if it was accepted that software, like just about every other class of asset, is subject to depreciation. Like a piece of machinery or a building there is the initial cost of construction or purchase, but there is also the regular, ongoing cost of maintaining and upgrading it. Also, there is a finite lifespan.
And only so much capacity to support. Are there software slum-lords?
I’ve been referred to as a scrum lord. I guess that’s close enough.
Have you encountered any organizations that do treat it this way for accounting purposes (or just for strategic conversations)?
One method for managing the trickiness of working on technical debt is the Mikado method (https://www.manning.com/books/the-mikado-method, also amazon, etc.) which keeps the product working as the issues are being worked, and manages the learning about the dead ends, the possible approaches, the to-do bits, etc.
A lot of it is an obvious philosophy about how to debug, which we often forget 😉
That looks interesting. Thanks for the link — will have to check it out.
I like that you are covering this more in depth. So much of my day most days is working around a decade of technical debt that we are gradually chipping away. In fact, it’s so much on my mind of late that today we actually released a podcast episode talking about the subject, using real world debt (and the reasons for that debt) as an analogy for the discussion. Basically, the idea is that some technical debt is more like a business loan from a bank and some of it more resembles a gambling debt owed to a loan shark.… Read more »
Do you have a link to the podcast?