Effectively tackling technical debt
Leo Sjöberg • July 30, 2024
Every company grapples with “technical debt”. This debt accrues when quick, easy solutions are chosen over more robust, time-consuming ones. While these shortcuts help meet deadlines, they can also lead to messier and harder to maintain code. Over time, technical debt can slow down development, increase costs, and require extensive fixes. But technical debt is a good and necessary thing if managed properly. It helps you maintain pace during a project, and paying it down helps you establish better coding patterns for the future.
Where technical debt goes wrong is when you stop paying it off, and you’re left with problems all over your codebase. If you get to that point, it can be hard to know how you could ever fix it. You end up in analysis paralysis, where you don’t know what to tackle first, and you want to fix all of it all at once.
So how do you go about paying down technical debt when you have so much?
Sit down with your team
Start by having an open discussion about the current state of the codebase. Identify the most critical areas needing attention and prioritise these based on factors like performance impact, incident frequency, and overall maintainability.
Focus on the team's perceptions of the issues. Rather than measuring time costs precisely, let team members express which problems slow them down the most. This feedback is crucial as it often highlights what prevents the team from achieving a flow state.
Once you have a list, sit down together, prioritise it, and try to make a rough estimate of how much each problem slows you down. Concentrate on the top three issues, ensuring everyone agrees on the priorities.
A useful way to ensure your list is properly ordered is to, once you have an ordered list of what the team thinks is right, remove everything except the top three and ask the team, if they could only pick three to fix, are those the right ones? You may get some discussion, and should feel more confident in your top three after it.
Once you have a top 3, repeat the exercise, but keep only the first item on the list, and see if the team agrees that it is the most important thing.
Make a plan
Now comes the challenging part: dedicating time to tackle the top issue. Create a detailed plan for addressing this problem. This plan doesn’t need to be a team effort; one or two opinionated senior engineers can propose the best approach.
Focus on fixing one problem at a time without overreaching. The easiest solution is almost always “we’ll rewrite the entire system to follow these new patterns”, and it almost never works. Full rewrites require you to have thought deeply about all the patterns you want to be introducing, and requires a lot of dedicated time, something that most teams don’t have. Instead, look for ways to address your worst technical debt within the existing system, aiming to complete the fix in about a week of dedicated time.
This is hard, so take time to properly plan it. You need to look at your codebase, and decide how your new pattern should work with complex variations of whatever you’re solving. Many tech debt projects run into this problem: you have a beautiful pattern, and the team starts implementing it, and it works for 70% of your codebase. But the migration didn’t consider the 30%, and you’re left with parts of your codebase remaining very hard to read.
Don’t let this happen to you – think about the different places in the codebase where you’re going to apply the new patterns. And yes, this is boring and tedious. It might mean a day or two of just scrolling through your codebase and making a bulleted list.
Get some time to fix it
This might be the hardest part: actually getting stakeholders to agree to committing time. Hopefully, you’ve kept stakeholders within product and engineering aware of what you’re doing, but now you need to get it on the roadmap.
This is where your plan matters. If you’ve made a good plan that requires no more than a week of the team’s time, you can likely secure time within a quarterly roadmap.
This also means you’re unlikely to get to items two, three, and beyond in your list within the same quarter, unless they’re much smaller or can be woven into existing projects.
Make it an event
So you’ve prioritised, planned, and gotten it on the roadmap, and now you need to actually do the work, together with your team.
To do this effectively, make this feel special - it shouldn’t feel like any other work week. Here are a few things you can do:
- Get everyone together in-person: It’s a lot easier to help people when you can just walk around the office or whatever space you’re in. If the team is remote, try to time this to coincide with when your team meets in person.
- Have a kickoff: Run a 10-30 minute meeting to explain why you’re doing this, and setting some ground rules. For example, everyone should be focused solely on technical debt during this period. As the person leading this, make yourself the interruptible person that PMs and other stakeholders go to during the day, and delegate as necessary.
- Provide food: Free food makes everything feel more special. You can provide breakfast on day 1, and afternoon snacks every day. If people are remote, this is trickier, but consider allowing members to order breakfast instead.
Lastly, make sure people start off easy. As part of final preparations before running your event, make sure you’ve made a list of some good, easy places to start.
Get everyone to start off in pairs with one to two easy fixes (under an hour of work). By sitting together, people gain a common understanding of the work. If there’s disagreement, you have a natural place to clarify what you intended, meaning better pull requests from the start, and fewer comments in code review from people that interpreted your proposal differently.
Set expectations for what comes next
It’s unlikely you manage to get through the entire codebase within the allotted time. No matter how good the plan, things always take longer than you think.
At the end of your dedicated time, make sure you have a wrap-up meeting. Celebrate the work that was done, and remind everyone of the importance to continue following the patterns. Encourage the team to include migrating to the new pattern as part of scoping out new projects to gradually move the entire codebase across.
And last but not least, don’t forget a vibe check! Check how everyone’s felt about the week, and try to keep motivation high to keep your new patterns going.