The Complexity Tax is Much More Painful Than You Think

When you build a thing, especially a software thing, you can always make it more complicated with the hope of making it better.

Making it more complicated allows you to so try to solve more potential user problems, which hopefully anticipates the user's needs and leads to a great product.

The main question is, when is this complexity worth it?

If you don’t introduce enough complexity into your product, you can’t solve enough user problems, and it will fail.

If you introduce too much complexity, the product will be impossible for a user to understand and even more impossible for your product and engineering teams to maintain.

To me, exactly where you should fall on the simplicity—complexity spectrum is one of the harder questions to answer as a product manager.

The north star of all great product cultures is to work faster.

For every inch that you move further to the right, you hurt your ability to move faster in the future.

What is the Complexity Tax?

The complexity tax is the additional slowdown in the speed of your development driven by this complexity needing to be handled at each step of a process.

When it comes to building software products, adding additional complexity to V1 of a feature means that every step of shipping it will take longer:

  • Its harder for the product manager to accurately describe in a spec
  • Its harder for the designer to clearly communicate convey in the designs
  • It takes longer for the engineers to build and test
  • It takes longer to describe to the executive team what this feature does and why so they can approve it
  • It takes longer for the whole team to QA and ensures that all the edge cases work

This initial complexity makes getting a feature out the door more expensive, but sometimes this is worth it to take on this complexity.

However, the real cost comes with time; as you don’t stop paying the complexity tax once a feature is out the door.

  • Every time an engineer works in that part of the codebase, they have to take this complexity into account.
  • Every time a product manager thinks of features in this area, they have to take this complexity into account.
  • Every time a designer tries to solve a user problem, they have to take this complexity into account.
  • Every time anyone new starts to work in this area, you’ll have to explain this complexity to them.
  • Every time that a feature gets shipped in this area, you’ll have to make sure it doesn’t break this complexity.

This is where the real cost starts to kick in, and it can get really painful.

After your 5th meeting trying to explain how this feature actually works, you’ll start to understand the true cost of complexity.

When I Made This Mistake

In early 2019, the growth team at Codecademy wanted to add a user-to-user referral system for the paid product.

The high-level logic made sense; lots of other companies run very successful referral programs, which become a natural engine for growth.

In addition, Codecademy enjoys a strong brand, and lots of our free users sign up after hearing about us from a friend.

Without getting into too many details here, this was a basic user-to-user referral system.

  1. I have a paid account
  2. I refer you to a paid account
  3. If you sign up, we both get a discount.

To make sure that this was clear, we added this cute message at the top of the checkout page.

How much complexity can that really introduce?

Hint: way more than I thought it would

Lesson: It's Always Worse Than You Think

Cut to 8 months later, and the referral program is a very moderate success. We didn’t lose money building it, but we didn’t make that much money either. It’s a bit more than break-even.

Was it worth it to add this complexity? No, it was not, and here is why:

While this is a pretty small change, so each time we touch the checkout page, it doesn’t cost us that much; however, we touch these pages a lot.

  • If we build another version of our checkout page, we can’t deprecate this version until we add this referral feature to the new version.
  • Because the referral system doesn’t make us that much money, adding this feature will be pretty low on the priority list
  • Therefore, we’ll need to operate two different versions of checkout pages, which makes the codebase more confusing for engineers and makes all feature development on these pages take longer.
  • Every time we add any features to this page, such as showing non-USD currencies, we have to test that it works with the referral system.
  • It greatly increases the number of scenarios that you have to run through when you build something new.
  • Does a new feature work if a user pays in USD, with tax, with a discount code AND is referred
  • What does this look like on average screen sizes? What about mobile? Does it push the “purchase” button below the fold for the iPhone 7? How can we be sure? Did someone check?

Taking all of this into account, it was definitely not worth it. In fact, we should have killed the whole program.

So What Do You Do With This Information

There are a few takeaways from this experience (and my many others like it)

While it's really hard to determine at the start of a project when I was making this mistake, there are a few things that I should have done in retrospect.

1. Step up & Make Decisions

Every time that I have made this mistake, I can point back to decisions that I should have made and didn’t.

These are always stressful; I could have chosen wrong; it makes product development take more time, etc,

However, this was always the core issue. I should have made a call on something that I delayed, and then we had to build for two scenarios that didn’t, in reality, have to happen.

2. Kill Things that Don’t Clearly Work

One of the worse outcomes, when you introduce unnecessary complexity is that the feature kinda works, but it isn't great.

This means the thing is going to stay around, you have to maintain it, but you are not clear if you or the user get a real benefit.

This is especially true in your core product. The more often the area that you’re working on will need to get touched again, the worse this tax is going to be.

This is much harder than it sounds, as turning off features or product lines is not that simple. Inevitably there are a few users who like them; you have to manage their transition off it, migrate the data, etc.

Sometimes this takes as long, if not longer, than building it.

3. Default to the Simpler Solution

If all else is equal, just go with the solution that is easier to implement and maintain.

You can always iterate on it and use the information from the first launch to inform the second one.

It's natural to want your first version of a feature to work, so you think by adding more and more functionality to it, you’ll make that happen.

In reality, you could also just be delaying the lesson that you’re on the wrong path entirely.

Other Articles: