Technical debt is a tool – use it, but use it wisely.
Technical debt is cool. Am I crazy? No, I think it’s a great feature (yes, feature) of agile development. Let me explain.
Technical debt is there. We can safely assume that in the very moment you finished a feature and pushed it to production – it’s debt. Best code is no code. But let’s talk about intentionally creating it.
Let’s say you like to write good, readable and tested code. You take care of DDD, use best practices, create caches when necessary. But then business has an idea for a feature, and they aren’t sure if it’s gonna work but they wants it fast. If you’d try to make this feature as you like, as your engineering soul tells you, you’d say “ok, give me a week or two”. There are disadvantages to that approach.
Business want something fast, because they want to be ahead of competitors. Also, monitoring usage of the feature and impact it could create takes time, so the faster they start the better. This is when you need to hide your proud and make it happen. Maybe it means that you’ll create a logic inside controller. Maybe don’t use cache right now. Tests? Consider only happy path. This should be conscious decision what to sacrifice and what not. Write your code simply, but not primitive. Have in mind that it could be deleted in any moment. Make a deal with business that you’d deliver feature asap but you’re cutting corners, violates good practices and make poor, error prone code so after that initial part you’d need time to fix things.
Don’t get me wrong. I think we should always write decent code. But not always it has to be perfect and polished. Think about 80/20 rule, it fits here perfectly. Do 80% of the feature with 20% of effort. Move remaining 20% to the future, when you’d know if feature is something worth investing or not. Then you can modularize it, create clean architecture. Learnings from first versions also would help you understand the problem better and adjust.
The thing is – you should know when to take a debt. And sometimes it’s the best thing you can do for your project. Essential thing is to pay it off. The longer debt is there the more expensive it becomes. Someone could use your part of code for example. So try to pay it off quickly. It may be hard because business sees that you can do things fast, so just after you finish this you should take that and that. But they need to understand how you did it and what’s the cost. Your estimation is still 2 weeks, it’s just that you delivered MVP in 2 days, and still need those 8 days to work on it, you could just wait until it was tested and verified.
It’s your responsibility to make it happen. If you’d fail, debt would increase to such huge amount the best thing you’d think of would be complete rewrite. Do you think business would like it? Freeze project for 3 months, don’t deliver any new features just to have “clean code”? No way. And it’s most likely it wouldn’t take 3 months but much, much longer. Without any warranty that it’d be better! You know why? Because making code better is constant thing. You take a few shortcuts there and later you fix them. You spot something wrong in the code so you just refactor it. Some bug occurs? Fix it, but also write a test immediately, so the bug wouldn’t occur ever again.
Don’t believe in huge refactors, rewrites etc. It’s a constant work to maintain your code in good enough shape, to maintain balance. Update libraries, packages and language versions. Make it in between tasks. Observe backlog and tasks and spot any time when things go a little slower so you could sit for a couple of days and pay some debt. Or instead of finishing task for 1 story point in 1 day and in doing so adding more debt, consider refactor with writing tests and at the end making a feature itself.
I did that recently, I had a feature which I could finish in 60 lines of code. But I knew I have a time so I decided to refactor one of the oldest part of the application and move it to new architecture first. So, instead of 60 lines of code and 1 day of work it took me 2 weeks and about 1200 lines added/500 lines deleted. The immediate gain is not obvious, but in time it would be much easier to add next features od modify existing ones. But, it wasn’t just a random task I decided to spend 10x more time than necessary. I knew that in some time we’d mess around it as we plan to change that part of our application. I knew it because I was aware of features and projects we plan in the future. If it would be just a standalone feature to do I’d probably went simpler way and finish it in one day and move on.
What I want to say is that being an engineer is like being a juggler. You juggle tasks and debt, clean architecture and refactors while walking on a rope of your business needs. Code couldn’t exist without the need and vice versa. You should always take into account what are the business needs, how much time you have and possibilities of paying debt and refactor things later. The main role of the business is to make things happen, as fast as possible. Your role in that is choosing the right path of doing that, cut some corners here, but do some features the best you can because you know it’s worth it. You’re responsible of code quality and the least amount of bugs possible. So your role is to balance business appetite with code quality.
Technical debt is a tool like any other. Wisely used it creates wonderful things, allowing your business to take off in no time. But if you’d forget about it it would just kick not only your, but also your business’ ass.