Technical debt is an inherent part of software development. You can't prevent it from happening but there are ways to make it easier to handle.
Live for the refactor
There are 2 types of code.
- Code waiting to be trashed: This is the exploratory work that you do, what people refer to when they say they're writing throwaway code. You know you're not going to use it so why spend time making it robust?
- Code waiting to be rewritten: This is everything else.
This is not meant to be an insult. A piece of code can be very much right at the time of writing and still require a refactor later. A lot of this has to do with the fact that tech is moving at a rapid pace and the needs of your customers will evolve with it, thus transforming the boundaries of your system.
Even the simplest service will reach a point of exhaustion and will require some work to get it back up.
Even https://pinboard.in needs work sometimes.
Site will be down for a few minutes to fix the tagging issue.— Pinboard (@Pinboard) March 22, 2018
Most of the cases where code lingers for years is when it is a piece of a complicated puzzle resembling a house of cards, and the risk of breaking the system is far greater than the pain of maintaining it.
One way to avoid this situation is to make your system refactor-friendly from day one. I'm not talking about going full steam ahead with micro-services everywhere - a few simple tricks can do wonder:
- Adopt continuous delivery: Practicing continuous delivery (CD) is great for 2 reasons. First of all it will accelerate the feedback loop with your customers reduce your deployment risks. And secondly it will give you a robust suite of tests that will come in very handy when you'll need to re-build part of your system.
- Separate your backend from your frontend where you can: At Squadlytics we have a Rails 5 API monolith for the backend and a React app for the frontend. The advantage of this setup is that it gives us clear boundaries if we need to change some of the endpoints. The frontend team can also keep on moving fast without worrying about breaking the underlying system. And the backend team could easily split the monolith if necessary, by moving endpoints to different systems.
- Comment everywhere: Code should be written not for you, but for the person coming next. You need to make sure that she'll have an easy time understanding the logic behind your choices and more often than not clever code tends to be difficult to deal with later. Best to keep things simple and leave as much help as possible in the codebase itself.
Story points VS. dedicated streams
We've talked about how you can prepare for tackling technical debt, and now we need to find a good way to budget for it.Once again there was 2 school of thoughts:
- Allocate story points (or number of tasks): In this scenario you dedicate a percentage or fixed number of story points to the backlog.
- Get a team or person to focus on debt: In this case you get part of the team to focus on technical debt while the others work on new features and improvements.
My advice is to NOT rely on story pointing. The reason is that all story points are not created equals and debt story points are prone to be pushed to the bottom of the backlog. One of the core premise of Agile is that we're really bad at estimating and planning and things are much better when we work on short stints and stop often to correct the course. This is absolutely true. Teams often end up having to cut scope, or shift some stories to the next sprint. And when it is arbitrage time guess which tasks your Product Manager is likely to push back on? Product Managers are not to be trusted with story points allocation. I know that because I was a PM myself.
So my preference has always been to have a team or at least a person that focuses on tech debt instead. That way you have 2 separate backlogs and you're unlikely to tamper with the debt goal that you set for yourself. To be a bit more serious about the previous point it's not so much that Product Managers shouldn't be trusted, but rather that when you mix tech debts and new features in a backlog it's harder to understand the tradeoffs you're making than if you have to say "John is no longer on technical debt".
Taking a step back to make a leap forward
My final word is that tech debt should not be a dirty word. It will always be, by nature, a source of tension between the engineering and the product team but it's something that can, and should be managed continuously. You do not need to have a plan to fix all issues tomorrow, but at least you need to define and communicate a strategy for it.
(Photo by Alice Pasqual on Unsplash)