How to deal with technical debt
By: Mirek Stanek
Tags: Coding, Leadership, Programming, Software Development, Technical Debt

How to deal with technical debt

A company needs no heroes but strategists

In software engineering, when you think of how the product value is developed over time, you likely see something similar to this image:

We are humans, and it is natural for us to notice a linear correlation in everything, especially when observing things from a here-and-now perspective. Except there are very few aspects of the physical world that are linear. For sure, the correlation between time and product value isn’t one of them.

Nonlinearity means that nothing is predetermined in our job. In the long shot, you can scale up product value unpredictably high, which is excellent. But you can also burn all the cash and make the company disappear.

Fortunately, being nonlinear is the essence of software engineering — it’s in our veins. We build things in a way where we don’t have to solve a given problem more than once. We automate the process, so we don’t have to repeat tedious work over and over again.

Actually, when you ask software engineers for the visualization of their impact on time/value ratio, it’s very likely, you will get this:

Overengineering

Being exponential is great, but it also has some pitfalls. One of them is a long investment time. Usually, when we build a highly extendable solution, we need to spend some time brainstorming it, developing an appropriate framework, and implementing a business use case on top of it. While as engineers, we can see product value growing each day, from the business perspective, it looks different. For the company, the product has value when it’s done and available for the customers.

If you spend too much time building your framework, there is a risk that its flexibility will never pay back. Let’s say you need one year to develop the first version of the working product. The year is a time when the business has no profits from your work and can only trust that you do the right thing. Sure, your framework will allow the company to release version 2.0 within a month instead of a year. And version 3.0 within a week. But these will work only under these conditions:

Your company has enough money to survive one year without a working feature, Your solution is future proof, which means you know what your company needs one year from now.

Can you predict these future needs? Can you make your solution easy enough, so the company understands and can use the full potential?

If you answered “no”, you do overengineering work. The cost of your code may be growing, but you cannot say the same about its value.

Technical debt

Growing technical debt is the opposite of this situation.

The value of technology is dictated by the value of the product. That’s why we should deliver it as soon as possible at all costs (they say 😉). The sooner you reach the market, the faster you get the feedback from your customers. Does it sound familiar? Agile, “fail fast”, “move fast and break things” — this is our bread and butter nowadays, no?

Imagine the situation — one day, your boss comes to you and asks — “this feature changes everything, we need it ASAP, what is the fastest you can make it live?”. New requirements don’t fit much in current platform capabilities, but who doesn’t love to make the impossible possible? Your tech stack is complex anyway, so another bunch of “if-else” statements won’t change much.

“Two weeks”, you answer.

After one Scrum Sprint, the feature is ready. The product brings new value to users, and again you proved your value with the heroic movement you did. Everyone’s happy 🙌.

Except for your technical stack. To meet your deadline, you needed to introduce some tradeoffs. As a result of it, the quality of the code slowly started deteriorating.

Next time when you need to implement a similar feature, it will take two and a half weeks instead of two. And the next one will make four. Before you know it, your boss will approach you with the question, “how on earth changing one simple thing in our platform takes one month?”

You have an answer for that “It’s technical debt, boss. You shouldn’t have to push me so much on delivery speed”.

Tech debt is frustrating. Your company took so many shortcuts over the years that tech stack looks like a house of cards. What’s worse, now, when it’s high time to pay for all of the tradeoffs, it is hard to find two extra months to stop all the development, build a task force team and do all the cleaning.

Wait! It’s not the company making bad decisions about your code. It is you, engineer. You showed them shortcuts and proved that another “if/else” in your code won’t change anything. You are responsible for the technical debt no one wants to pay for.

What to do?

Ok, tech debt is bad, but no one wants to come back to waterfall-development times, where it was taking months/years until the product reached its customers. That’s why if you are on a leading/senior position in technology, your job is to find the right balance between taking shortcuts and building highly customizable frameworks. Here are some hints from my experience that can help you with handling that.

A company needs no heroes but strategists

Being a hero and delivering faster-than-anyone is tempting. Who doesn’t want to have an immediate impact on the company? Except your business will last for more than two weeks from now. It’s way more valuable to keep the pace of delivery high in a long-term perspective than playing one-time heroic acts that slowly deteriorate your technical stack capabilities. Be strategist, not a hero.

Have long term plan

Being a good strategist means that you have a plan. How do you know you move in the right direction with your day-to-day development? Think about how your tech stack may look like in a year from now. Maybe the project is split into specific modules. Perhaps your deployment process is fully automated. Or maybe there is no more code using the old, deprecated library. If you have clear goals like these, it will be way easier to assess how much of the technical debt will be removed or introduced when deciding on feature implementation.

(If you look for the inspiration, check my blog post about building vision and strategy for your team).

Be 1% better each day

If you have a plan, put it into motion whenever you can. Don’t think about finding a dedicated month for paying a technical debt. Instead, if it’s only possible, make every single product-related work part of your tech-stack strategy. Did you estimate your work for five days? Why don’t you add one day more, to make sure that your code is not only great but also in line with standards you want to meet in your planned future.

Measure everything

In a data-driven company, not only product should be measured. Try to find numbers in anything you do. Make sure that your long term plans are specific (you can use KPIs or OKRs for defining them). You can measure the number of releases, issues rate, % of rewritten modules, build time, testing time, engineers onboarding time. Being 1% better each day is hard because you can barely notice that. But if you look at it from week/month/quarter perspective, you will see trends much more clearly.

Distribute responsibility

Finally, make sure that constant improvements are in your engineering team’s DNA. Distribute responsibility for long term goals among all team members. Don’t call the feature “proof of concept” if it’s going to be the cornerstone for future development. Don’t incentivize half-baked tradeoffs by promising “dedicated one month of maintenance work” in the near future. Don’t separate technology and product-related work. If someone in your team says, “it is done,” don’t expect that your boss will ask you, “are you sure? What about leftovers from the old, deprecated code?”