Technical Debt — Good or Bad?
This article is meant for you to understand what is technical debt, if it’s a good thing, if it’s a bad thing, or if it’s something you can’t get rid of.
In my first years of writing code, I’ve heard from everyone that they/we had technical debt in our projects and we needed to get rid of it. It was something that we wanted to change (and refactor), and everyone was pretty afraid of it. In my mind, I considered that this is a very bad thing and we never should have technical debt in our code. After some years I realized that I was wrong and I was afraid of something I couldn’t control.
Based on Wikipedia, the definition of technical debt is:
Technical debt (also known as design debt or code debt) is the implied cost of additional rework caused by choosing an easy (limited) solution now instead of using a better approach that would take longer.
So…it’s actually “the simple way out” for fixing a problem, even if it’s not the best solution. It’s like a “loan at a bank”; well, most of us can’t buy a house without a loan, so, is it that bad? During the next years, I realized that technical debt is a “necessary evil” in most projects, as long as you keep a balance of it. As in bank loans, if you don’t keep a balance and you don’t care, you’ll end up paying double the amount you took, maybe even more sometimes.
Another definition from Atlassian is:
Technical debt is the difference between what was promised and what was actually delivered
But, what if the quality of what was promised, got changed? What if last year when the project started if 50 concurrent users were using the system and they had 2 seconds delay was ok, but now the business people are not ok with this specification; aka: if specs changed regarding what was promised, or if the technology changed/evolved as standards, is it still a tech debt? Of course, it’s debatable, but in my mind, it’s still a debt, even if you like it or not, even if it’s what you promised in the beginning.
Possible causes:
Most of the time the cause is the pressure from the business people. Most of them don’t know what technical debt is, how it will impact the business itself in the future and let’s be honest, they likely don’t have professional devs around. A professional should be able to talk to the business people “in their language”. A professional developer should always focus to do his job at the best level he can and his job is only to solve the needs of the business. The business people will always want the product on the market as fast as possible, for multiple reasons: to get faster feedback, to analyze how the market behaves after the product was launched, to get money as fast as they can and so on, but it’s our job as developers to help them understand about this thing called technical debt and calculate together how to keep that balance. Deliver something quick and dirty now, but in the next sprint already have an item in the backlog ready to be picked up, to make this “prettier”.
Bad analysis, prioritization or planning. No BAs, no one that knows the market need, not all the team members know what they are trying to solve and what’s the plan to do it, no real backlog or roadmap, no direction. If you add the fact that the real users that the product is targeting are far away, (only the manager of the manager of the PM of the PO of the team can talk to them), that product has big shots to fail.
Badly written code. No one wants to write bad code. Believe me, in all my experience, I never met a person that told me his main purpose of that day is to write bad code. The problem is that in the product is no one with enough tech knowledge to teach the others how to write good/quality code, or just maybe no code standards are enforced and kept up to date, or just tightly coupled components, that aren’t flexible enough for the changes needed by the business nor the devs that are able to extract them.
No ownership, no developer wants to make the business people understand how the technical debt influence the business and he is just complaining about it. No business people take to ownership of the product to help the dev team to be much closer to the end-users and help improve the product (by asking questions and challenging the decisions).
Legacy code and here I am referring to code that was written long ago, it’s working, everyone is afraid to touch it and the people that wrote that code are no longer in the company. I am talking about a module or a piece of code that everyone considers a black box.
No documentation or not maintained, or worse, bad written one, and everyone will try their best to run away. I know most of the non-technical guys still consider that documentation is the best tool, as long as it has the same number of pages as the bible, but this is not true!
No tests. I already stated my opinion in a lot of posts here already about this. If you don’t have tests, in my mind you are screwed if you are trying to build a real project not only a PoC. If you are trying to improve something you can’t know for sure if you didn’t break something. You might fix a bug and introduce 5 more and so on. I don’t even wanna start again, why do you need tests.
Processes that are ignored, and here I am referring to things like pushing the code into production without testing it, or closing stories, just to get a higher number of story points done in the sprint, without code review.
Delayed refactoring. You make something ugly and dirty to get some feedback from the users. You put it into production. Your PO creates a story to clean up the mess, but it never gets prioritised, due to other “more important” things. Another example could be the zero time to get all the frameworks and 3rd party components that you are using to the latest version. You start on version 3, but in 2 years when you launch, it’s version 6–7. You can launch as it is, but you’ll have some security issues, with which the company will or won’t agree, or you will need to upgrade, which will take you a lot of time, because you didn’t upgrade one version at a time, and you might need to re-write entire components.
Some real-world examples:
If you create an MVP, as fast as possible, with high technical debt, you can have 2 results: a failed product and in that case, you don’t care about the technical debt, because most likely you will throw it away; or you can have a great success and in that case, you’ll need to get a balance fast: lower the technical debt and add new features in parallel. If you’ll only add new features, their cost will grow exponential. If you’ll only solve the technical debt, most likely as any other great success others will copy your product and add new features and most probably will take your place on the market (or at least get a market share).
If you work on a product that is promised to someone and everyone knows is not only an MVP to test the market (or it’s a long-running product), you should keep the technical debt as low as possible from the beginning. Let’s be honest, if you will work for 1-2–3 years for a product, before going into production (even if it sounds very bad, there still are a lot of cases like this), multiple things might change in this time, so the cost of the change should be at the minimum possible. If the estimation is 2 years, no know will ever care if it’s 21 months or 26.
How to manage this?
First of all, you shouldn’t be afraid of technical debt. I read somewhere something funny: 99% of the products from the market have technical debts, the rest of 1% are not into production yet. The world is changing pretty fast, the same for the requirements and for the frameworks that we are using. Everyone should keep in mind there’s no bulletproof solution and no perfect products.
To keep a balance of technical debt and be sure you won’t get into trouble I suggest you do the next few things:
- Always check and upgrade to the last LTS versions of your frameworks and libraries that you are using
- Have a strong standardization for your coding and if you need to change it, don’t be afraid to do it, but don’t ignore it.
- Always try to improve your code, architecture and security. Refactor while you’re coding (and get/make time to refactor the modules in which always bugs appear/in which you have a high number of bugs).
- Use tools that measure your technical debt, for example, SonarQube, but configure it due to your product needs, do not use it with default.
- Do not forget about the testing pyramid and use it!
- Be prudent! Do not go into production if you are not sure about your product. A bug can close your business!