Complex Code is Technical Debt, and it will Charge Interest

Complex Code is Technical Debt, and it will Charge Interest

Last updated:
Table of Contents

Everyone is always under a deadline. This means most tasks are always under pressure to be completed as soon as possible.

So there is never enough time to set aside for tasks that don't immediately deliver business value, such as refactoring and house-cleaning.

What does this mean for code quality?

This means that the most likely scenario is for software systems to gradually lose structure and add accidental complexity1 as time moves on, making it increasingly harder to get things done.

Code complexity drains team resources

Interest needs to be paid, and it compounds:

  • It takes longer to understand current code when you need to add features or otherwise make changes to it;

  • Existing complexity means you will need to add even more complexity and hacky code for future changes, just to work around the existing lack of structure;

  • Unnecessarily complex and messy code is a broken window2. Whoever needs to work on this system will probably not take care in writing high-quality code. "This project is a mess anyway, why bother writing good quality code?"

  • Complex databases make it easier for bugs and security holes to lay hidden detected.

What to do when you cannot refactor

Obviously the appropriate and sustainable solution is to clean up after yourself immediately:

  • refactor sub-optimal code before making changes to it

  • at the very least, refactor right after you shipped a quick-and-dirty version for some feature

However, it's often the case that business priorities leave no time for "house-cleaning" activities - especially in early-stage, high-growth companies.

It may be the case that the opportunity cost of not shipping a quick-and-dirty solution is to jeopardize the company's existence. In this scenario, quickly shipping something which will add a lot of technical debt is the lesser of two evils.

So what can a software engineer do in these cases?

Comprehensive testing

Make sure you add comprehensive tests for all features you create.

This will make it easier and less risky to refactor code in the future.

Add technical debt tasks to Jira

Make sure that all known technical debt is added to your task tracker (e.g. Jira).

This is important because it will make such debt explicit rather than implicit, and it will make sure your manager is aware that this should be done and prioritized eventually, just like any other task to deliver value to the end users.

  • As with any other task, make sure you create clearly defined as opposed to vague task descriptions:

    BAD task description
    (too vague, it's unclear what to
    do and how much time this will take)
    GOOD task description
    "Refactor module X" "Refactor module X, by replacing all
    individual functions by one single
    function that takes the type as an
    argument; centralize logging
    and saving to the database."


1: Inherent vs accidental complexity

2: The Broken window theory states that subtle signs of disorder and lawlessness (such as broken windows) increase the likelihood of more serious crimes nearby.