DEV Community

Tal Shafir
Tal Shafir

Posted on

The Sunk Cost Fallacy in Software: How to Recognize It and What to Do About It

What is The Sunk Cost Fallacy?

The sunk cost fallacy is our tendency to follow through with something that we've already invested heavily in (be it time, money, effort, or emotional energy), even when giving up is clearly a better idea.

An everyday example: imagine you buy a $20 movie ticket, and halfway through the movie you realize you're not enjoying it. The rational choice would be to leave and use your time more enjoyably - but many people stay just to "get their money's worth."
That's sunk cost fallacy in action.

How does it relate to Software?

We've all most likely been there, we made a decision that made sense at the time, sometimes because of external reasons.

I bet at least some of these quotes will sound familiar

  1. We need to move fast, no time for tests / documentation / design
  2. We don't have capacity to learn to use X for this new use case, let's keep using Y that we're already familiar with
  3. We don't have enough DevOps to manage another DB, let's use the same DB for all these microservices
  4. Let's use language X - most of our founding team already knows it, and we'll just implement anything missing in its ecosystem ourselves.
  5. We must use this new cool technology, it will scale us great when we reach thousands of customers (only 982 more customers to go until we reach the first thousand)

A lot of times these are good reasons early on and most commonly in small scales, you don't always have the time or capacity to engineer a solution for 1000x customers and load - and a lot of times you shouldn't.

Ultimately, delivering value to your customers through your product is far more important than using perfect tools under the hood. The ocean floor is littered with well-designed ships that never left port.

It's usually a balancing act that we almost definitely will miss at least sometimes.

The Consequences of Past Decisions

Looking back at those examples, it seems inevitable that we'll eventually make decisions we regret. How can we know that we've reached the point that we need to do something about it?

Usually there are some signs that we've reached a point that we already start feeling the cost of previous decisions:

  1. Over-engineered systems and processes
  2. Framework lock-in or bad platform choices
  3. Investing a lot of time and effort on stuff that is not your core business
  4. Slowed feature development
  5. Performance Issues
  6. System Instability
  7. Increasing maintenance effort

These are all common in the modern lifecycle of software products, the industry learned that building the "perfect" system from the get-go is nearly impossible, requirements change, scale change and it's almost impossible to predict those changes without getting your product in the hands of your customers.

How to Recognize When You're Falling for It

It's not the past decisions that hurt us, it's ignoring them and delaying action that causes real damage.
It's tempting to band-aid these issues instead of addressing root causes.
Performance problems? Throw more compute at them.
Database struggling? Scale it up.

The more we push forward with our mitigations and workarounds the more sunk cost we have. If we'd left the 3-hour movie after the first hour we would've lost $20 and an hour of our lives, if we waited 2 hours we'll lose $20 and 2 hours of our lives.

Scale this up to a software company: it's not $20, it's likely $20,000+ in cloud bills. It's not an hour - it's hundreds of person-hours and significant opportunity cost.

A good sign for it is if you start hearing phrases like

  1. We've invested too much to change it now.
  2. The rewrite will take too long.
  3. We'll lose political capital if we admit it didn't work.

Ask yourself these

  1. Are we defending this decision only because of past effort?
  2. Is this architecture still serving us today?
  3. What would we do if we started from scratch?

What to Do Instead: Strategies to Move Forward

I'm in this photo and I don't like it

Ok, we've started to fall for it, what can we do?

Run cost-benefit analyses (fresh, not based on past costs). Compare "cost to migrate away" vs. "cost to keep maintaining" without factoring in what you've already spent.

Small rewrites over big-bang. Instead of rewriting the entire legacy authentication system, start by replacing it piece by piece in new services.

Build confidence with spikes and proof of concepts. Before committing to a database migration, run a 2-week spike to validate the approach works for your use case.

Communicate tradeoffs openly with stakeholders. "Migrating off this framework will slow feature development for 2 quarters but reduce maintenance overhead by 40%" is better than silence and bailing mid-work.

Embrace "build to replace" design patterns. Write new code assuming it might be replaced, making it easier to incrementally modernize.

Invest in modularization to isolate painful components. If you're working on a component you know will need to be replaced, abstract it so you can upgrade it independently.

It's not always possible to handle these cases immediately but detecting and reacting fast can mitigate a lot of the cost of these cases. The solution is to stay vigilant: document decisions and their rationale, hold regular architecture reviews, and foster open discussions that help you catch issues early.

How Can You Make a Change

Always surface the issues you find. Silence helps no one - problems can't get solved if decision-makers don't know they exist.
Before raising concerns, keep these important principles in mind.

Remember you're on the same team, even when you disagree. The goal isn't to annoy people into agreement - it's to align on how addressing this issue helps everyone reach shared goals.

Learn to take "no" gracefully. They're saying no to your idea, not to you personally. You mustn't take it personally and understand that there are factors outside your scope. For instance, "if we don't do X, we won't scale to 100x customers" may not be a valid concern if there are urgent issues that could end your runway before you reach 1.5x customers.

Come with a plan, not just cool-sounding ideas. It's much easier for stakeholders to agree to a reasonable, well-thought-out plan than to a half-baked idea that may not be realistic.

Finally, filter your ideas carefully. Not every interesting technology you read about is worth implementing. Focus on real pain points you're encountering, not solutions designed for companies at the scale of Google or Netflix. "Let's use chaos monkey, gorilla, and kong in production" is probably not what a small company providing non-critical services in a single region should invest time in.

I must admit that I've fallen into some, if not all of these pitfalls at some point.

The Leadership Angle: Creating Space for Rational Change

The people that feel these issues the most are those in the trenches, it's the developers that keep writing the same boilerplate or the PM that keep hearing that "we can't do it in this timeframe" or "we can't do it the DB won't handle it".

It's important to build an environment where raising those issues is rewarded. It's also important to act on it, it's very easy for teams to become numb to these issues and feel that no matter how hard they try to advocate, it won't change or even worse, being framed as a troublemaker and the developer who cried legacy.

Managers and architects should:

  • Reward truth-seeking behavior and try to act on it
  • Protect engineers who raise hard truths
  • Avoid framing rewrites as personal failures

Case Studies: Breaking Free from Sunk Cost

After discussing the theory, let's look at some well-known scenarios where companies pivoted - reworking decisions they had already heavily invested in.

Amazon Prime Video migrated their monitoring service from serverless distributed services to a monolithic application, helping them achieve higher scale and resilience, while reducing their costs by 90%.
(For some reason, the original blog post link doesn't work anymore, but the internet doesn't forget.)

Slack has pivoted more than once!
Slack originated from the gaming company Tiny Speck, which created an online multiplayer game called Glitch. The company developed an internal communication tool for game development, which ultimately proved more valuable than the game itself.
You can read more in their blog post about it 12 years later.

Since its inception, Slack used MySQL as its storage engine, managing sharding and data access directly within their monolithic application. They maintained their product this way for years.
In 2017, they began migrating to Vitess, a horizontal scaling system for MySQL. For more details about this journey and the decisions behind it, see this blog post.
Here are some key highlights:

  • The migration took about three years, all while their system continued to function as usual.
  • Fortuitously, they completed most of the migration just before the COVID-19 pandemic, when many businesses suddenly transitioned to remote work. During this period, they saw query rates increase by 50% in a single week - without Vitess, scaling to meet that demand would likely have caused downtime.

Both of these examples demonstrate that, while such changes can be costly, wise choices and careful planning can yield substantial long-term benefits.

Of course, we can't ignore that there are likely many more examples where such attempts have failed. Often, it's difficult to determine whether the failures stemmed from the attempts themselves - or simply from acting too late.

Choosing Progress Over Pride

Encountering issues and reaching limits of decision is part of our professional lives, it's nothing to feel shame about but a badge of honor - we did such a good job that we need to scale up.

Recognizing sunk cost fallacy is a sign of engineering maturity, being able to act on it is a sign of a good engineering environment.

Sometimes, the best path forward is letting go of what got you here. Start small, audit one decision that may be influenced by sunk costs.

Top comments (0)