Back to blog
Hendrik Wallbaum
Frontend Engineering Manager

Technical debt and dirty dishes

Hi, I’m Hendrik, a JavaScript enthusiast and Engineering Manager at Taxdoo. Today I wanted to take you on a journey of exploring what technical debt is and how we deal with it here at Taxdoo.

Working with Engineers you probably heard the term “Technical Debt“. But what is this “debt” Engineers keep referring to? Just an excuse to push features further out? Join us on a journey to understand what Technical Debt has to do with doing your dishes and paying back your student loans.

What is debt?

> Something that is owed

In its most basic form, Debt is simply something that is owed to another. The most common debts we owe are:

– Money 💸, that we owe to a bank or student loan.

– A favor 🤝, that I might owe to a friend who helped us move apartments. 

This is what we most often think about when the word “Debt” is mentioned. But there is another kind of Debt that we all face in our daily lives. I like to call it “Dishes Debt“.

Why doing your dishes is important

Most of us use our kitchens every day. We go in, prepare our food, and then leave. One might say:

> Your kitchen provides value to our lives by allowing us to cook with all the appliances we need.

However, this ‘value-creation process of cooking food always leaves behind dishes that we have to wash before more food can be prepared. As a fan of one-pot meals myself, I know my big pot of pasta requires washing right after I finish it.

This is how I came up with the term dishes debt. Dishes debt is exactly that moment in time when I realize I have to do my dishes first, and only then can I allow the kitchen to deliver its core value of allowing me to cook my food.

> Occasionally the value-creating process of cooking produces Dishes Debt that has to be paid down before more value (food) can be created.

We find the same kind of principle at work in Engineering. We call it technical debt.

Technical Debt

In Engineering we as Engineers:

> Provide value to our customers by coding features for our products.

As engineers, it is our responsibility (and passion!) to provide value to our customers by coding the right features for the products we are working on. Similarly to how the kitchen provides value when it comes to food preparation, we engineer products that make our users’ workflow a pleasant and easier-than-ever experience. Of course, as with every process, engineering also leaves behind some byproducts that need to be taken care of before we can create more value.

> Occasionally the value-creating process of coding produces debt that has to be paid down before more value (features) can be created.

Remember the one-pot pasta dish I was talking about? Well, in engineering terms, this is her again.

That being said, the point where we have to do some coding before implementing new features, we call Technical Debt. The only difference here is that as your dishes pile up next to your sink, you can see them, count them, and make a plan of action. Technical debt, on the other hand, is not as tangible, which is why it takes some extra effort from our side to pay it back.

Before we continue to see how we can implement the best strategies for dealing with technical debt, let’s first learn what types of it exist out there.

Types of Technical Debt

At Taxdoo, we divide technical debt into three categories: deliberate, architectural, and entropy. Let’s dissect each.

Deliberate Technical Debt

Deliberate technical debt is one we take on knowingly. We either see it coming intuitively, or we’ve done something similar in the past where debt arose and we can just feel it in our guts. A sentence you hear us say most when deliberate technical debt is involved is “We need to deliver this now”. For the sake of making a deadline, we then cut corners.

> We know there are problems but we accept them to deliver something on time.

These problems we accept or corners we cut come in different shapes. They include “hardcoding” connections, maybe for now you can only filter a table of offices by a hardcoded list of cities while we know that in the future that list of possible filters should come from the list of all offices.

Architectural Technical Debt

In engineering, managing expectations is no easy task. Even more difficult is when we have to accommodate them. This is when architectural technical debt steps are the work we need to do to accommodate these ever-changing expectations.

> The system was not built to support this.

Whether we didn’t know about an important use case before commencing work, our original assumptions were wrong, or our company pivoted, all of a sudden our work becomes more difficult. Now, with all the other things we need to do, we also have to do some refactoring. Often we find ourselves asking the question: What do we need to change in the way we support the current use case to support the new use case?

This type of Technical Debt often arises in the conflict of creating a “solves all problems” vs “solves exactly our problem” solution. A highly-adaptable product might take a bit more time now but pays back with its flexibility later. Something more targeted is faster to accomplish now but will require a lot more work to become adaptable later.

Entropy Technical Debt

Entropy is the fact that:

> Over time the quality of everything you don’t consciously maintain deteriorates.

So many things add entropy to the work of engineers that it’s difficult to even start listing. New team members cannot know the full history of our code, for example, and will naturally work differently. Architecture and requirements change, and sometimes already utilized technology becomes outdated. It’s part of the game, and entropy technical debt is at exactly this intersection of time and relevance.

Washing the dirty dishes

Now that we can understand the different types of technical debts, it’s time to learn how to tackle them. We will do this by once again looking at the dishes debt and how we often overcome it.

Some of us (and I might be included in that) clean just what they need. Like my pot for porridge that I often wash in the morning to make today’s batch.

A trained chef-turned-programmer I used to work with was quite passionate about this one. He taught me that no professional kitchen could run if it didn’t take care of the dishes while cooking was still in progress.

Habits are great, they become involuntary actions that we don’t think about, we just do. And doing dishes every day makes sure we clean small batches that are easy to handle, enabling us to use all our dishes every day.

Sometimes there is nothing else you can do. For days you didn’t pay down your dishes debt and now you can’t see the countertop. You’ve got to put in that hour of effort and do everything now.

Maybe you can even find a way to not have as much dishes debt. Ordering take-out every day could be an option but it produces a lot of waste and is much more expensive. An innovation could be a dishwasher: it’s a bigger, one-time investment but now you don’t have to do the washing anymore, and it can handle a lot in one go.

Technical Debt strategies

The best part is that we can translate our dishes’ debt strategies to pay down our technical ones. Let’s change up a few words together, shall we?

Picture it: there is a new feature coming in but some technical debt is holding us back. No other choice but to fix that first. Only if we had fixed it on time… Now our system wouldn’t be so hard to maintain, estimates wouldn’t have blown up more, and Software Engineers would be at least a tad happier. What a dream.

In Software Engineering we often employ something we call code reviews. In a Code Review, peers check each other’s work and give ideas on what could be improved. Apart from being peer-to-peer learning opportunities, code reviews are also a natural place to catch Technical Debt before it makes its way into our main codebase.

Another great example of doing dishes while you code is often referred to as “scout mentality” – always leave a piece of code you touch cleaner than it was before. To reflect this, some teams always add a fixed percentage of “scoute time” to their estimates.

We at Taxdoo allocate 10% of our time towards technical innovation and learning. This time-budget is up to Engineers to spend.

And for the other 90% of our time, we make sure to prioritize both feature improvements and technical work.

Sometimes you either need to fix your technical debt now because your systems are failing, or there is no feature pressure right now, so your team can take their time to perfect the technical implementation.

For us this sometimes takes the form of taking a whole sprint just dedicated to fixing and improving things.

A great way out of technical debt is to solve the old problem in a new way. If updating the system always takes longer, maybe you can build a configurable system that can get adopted faster and erase the existing technical debt, thus making Engineers happy.

We drive innovation both as part of feature work and in the 10% innovation and learning time that our Engineers get. It makes me extremely happy to say that it has resulted in amazing improvements!

Preventing technical debt

Although we apply the above-mentioned methods to reduce our technical debt, there still are some residues. There probably always will be. This doesn’t mean that we still can’t take more measures to prevent some of this debt from arising, though.

The right tools can already catch some of the debt in the act. Using TypeScript over JavaScript, for example, will help you detect some of those runtime errors during the stages of development. Observability will make you aware of problems while they are still easy to fix. What a relief!

Realizing that debt is something we are likely to incur enables us to consciously take on debt where it helps us to move the business forward and turn it into a part of our prioritization.

Final thoughts

Writing code is a complex problem. Software Engineers constantly need to decide on trade-offs between “thinking about everything up front” – so that we will need no adoptions later – and “building what is needed right now” – so that we are fast. Both are right at times, largely depending on how easy the system is to change later.

When considering technical debt in the context of planning time for implementation we have only two options: either to invest time in preventing debt to arise, or invest time later to pay down the debt created. In either scenario, we need to look at our priorities and make sure we are making an informed decision.

But, and it’s a big but, if you ask me, it’s always worth investing in debt prevention whilst paying down your current debt. Doing this makes sure that your company can react to sudden market changes and not be held back by unfinished business. And we all know it: in a sea full of fish, being quick to react is the most important factor that sets you apart from the rest.

Back to blog

More articles

  • 29 November 2022
  • Taxdoo Engineering

Emotional Intelligence – A Toolkit for Software Engineering

Want to thrive in tech? It might come as a surprise that hard skills alone are not enough to progress your career as a developer. At Taxdoo, we believe that nurturing Emotional Intelligence (EI), as well as technical skills, is the key to a healthy, productive environment. Why care about EI? The stereotype of a […]

Read more
  • 29 November 2022
  • AJ Cole

Migrating from AWS Lambda to AWS ECS: Benefits and Challenges

AWS Lambda is a powerful service that provides a hassle-free way to run our code in the cloud without needing to concern ourselves with the underlying infrastructure. At Taxdoo, we rely on Lambda for a vast array of services, as it streamlines our development process and ensures our focus remains on delivering innovative solutions. However, […]

Read more
  • 29 November 2022
  • Maria Canero

EI in Software Engineering | How to Improve Code Quality

Software engineering is all about coding. Right? Wrong. Well, just a little bit at least. Software engineering is way more than writing lines of code. Problem-solving, understanding complex business systems, specifying the scope of project implementation, defining contracts between clients and customers, coordination (for resource allocation, deployments, interlinked pieces of work), prioritizing, communication between colleagues […]

Read more