All articles
ArchitectureEngineering

The Tradeoffs Behind the Stack

Irshit Mukherjee

Irshit Mukherjee

Founding Engineer

August 7, 20269 min read
The Tradeoffs Behind the Stack

I have one belief that shapes how I look at every system I've ever worked on.

Everything comes at a price.

Every architectural decision is a purchase. The invoice arrives whether or not you read it before signing.

Software architecture is about understanding tradeoffs. It's never about choosing Kafka or RabbitMQ, Postgres or MySQL, C++ or Rust. Those are just tools. The real question is what tradeoffs your system can tolerate.

Most architecture arguments I've watched are two people comparing feature lists when they should be comparing bills.

The Concorde problem

The Concorde crossed the Atlantic in about three and a half hours. Nothing in service today comes close. It's in a museum.

It wasn't beaten by a faster plane. It was beaten by fuel burn, by a sonic boom that got it banned over land, and by a cabin of 100 seats where a 747 had 400. It optimized hard for one variable and paid in every other one at once.

That's the shape of most engineering failure. Not a wrong answer. A right answer to a question nobody was asking.

A supersonic airliner on a museum plinth beneath an unreached ceiling line.
Optimize hard for one variable and you pay in every other one at once.

Precision is a currency

The AI stack is the clearest version of this, because the constraints are just arithmetic.

A 70B parameter model at 16-bit precision needs about 140GB for weights alone. That doesn't fit on a single 80GB card. Quantize to 4-bit and you're at roughly 40GB, which fits on one card, or on a laptop with enough unified memory.

The price is quality, and it's unevenly distributed. On everyday tasks the gap is hard to notice. On long reasoning and on code, where small errors compound across a chain of steps, it's obvious. Benchmarks tend to hide this, because the damage concentrates exactly where you care most and an average tells you nothing about where the losses landed.

The rest rhymes. Mixture of experts buys compute efficiency and pays in memory, since every expert stays resident whether or not it fires. Batching buys throughput and pays in latency. Speculative decoding buys the latency back and pays in wasted compute. Caching is the same trade one level up, latency for staleness.

A fine dense grid beside a coarse one, the difference drifting away as particles.
There's no setting where you get all of it.

There's no setting where you get all of it. A full-precision model that can't run is worth less than a good one that can, so the setting you want is whichever gave up what you needed least, which is a much less satisfying rule than it sounds, because it means the right answer moves every time the workload does.

What the tools actually cost

Kafka is an append-only log. Consumers track their own offset, so replay is free. You pay in ordering that only exists inside a partition, a partition count that hurts to raise later, and no per-message acknowledgement, priority, or redelivery.

RabbitMQ tracks state per message. That buys you acks, retries, dead-letter queues, priorities, routing. You pay in memory when a queue backs up, a lower throughput ceiling, and no replay at all. Once a message is acknowledged it's gone.

The question isn't which is better, it's whether a consumer will ever need to read history again.

Postgres and MySQL look identical on a comparison table and aren't. Postgres writes a whole new row version on update, so indexes get repointed even for columns that didn't change — HOT updates avoid this when no indexed column moves and the page has room, but that's a condition you earn rather than assume. Streaming replication ships the physical log, so all of it crosses the network; logical replication has been there since PG 10, but it's still the less-traveled path. What you buy is the best type and extension system in open source: PostGIS, pgvector, real JSONB, partial indexes, and a planner that survives complex queries.

MySQL makes the table itself the primary key tree. Lookups by primary key are one traversal, updates touch only the indexes that actually changed, and logical replication keeps the stream cheap across regions. You pay with two traversals on secondary lookups, a weaker planner, and an ecosystem that isn't close.

Underneath both sits a question people are a little embarrassed to say out loud. A database your team has already debugged at three in the morning is worth more than a better one they've never seen fail.

The bills real companies paid

Seven paper strips of dramatically unequal lengths laid out in a row.
Scale doesn't only change the answer. It changes which currency you're paying in.

Prime Video

Built the textbook serverless pipeline, then found that S3 and Step Functions are an expensive way to move a video frame six inches. Collapsing it into one process cut infrastructure cost by over 90%.

Segment

Gave every destination its own service and its own repo, then started adding three a month. They merged it all back.

Uber

Moved from Postgres to MySQL in 2016, and people still quote it as proof that MySQL wins. Their workload was update-heavy, with many indexes per table, replicated across data centers. That's the exact intersection where the Postgres design is most expensive. Change any one of those three facts and the answer flips.

Discord

Went Mongo, then Cassandra, then ScyllaDB, cutting p99 reads from over 100ms to about 15ms. Migrating twice looks like getting it wrong twice. It isn't. Each choice bought the runway to reach the scale where the next one made sense, and there was never a version of this where they started on ScyllaDB, because at their 2015 size running it would have been an absurd use of the people they had.

Figma

Hit the ceiling on Postgres, evaluated CockroachDB, TiDB, Spanner and Vitess, then sharded Postgres themselves rather than throw away years of knowing exactly how their database fails. They wrote more code so they'd have to learn less.

Dropbox

Left S3 for their own exabyte-scale storage and saved about $75M over two years. Everyone cites this when they want to leave the cloud. Almost nobody citing it has exabytes, or that team. At a few hundred terabytes the same decision is a catastrophe.

WhatsApp

Ran on Erlang with 32 engineers and 450 million users. Nearly perfect fit. The price was the hiring pool, which is affordable at 32 engineers and ruinous at 200 hires a year.

Scale doesn't only change the answer. It changes which currency you're paying in, and most of these teams found that out by getting a bill in a currency they weren't tracking.

The cost of starting over

Rust gives you memory safety and a modern concurrency story. Rewriting a mature C++ codebase is still rarely worth it.

Google reported memory-safety bugs falling from 76% of Android vulnerabilities in 2019 to 24% in 2024, without rewriting the old C++ at all. Vulnerability density decays with age. Ten-year-old code has already had its bugs found by fuzzers, researchers, and outages at inconvenient hours. New code is where new bugs live, so they wrote the new code in Rust and left the rest alone. A rewrite replaces proven code with unproven code and resets that clock to zero.

A running system holds knowledge that exists nowhere else. Not in the design doc, not in the tests, not in any one person's head. It's in the strange conditional somebody added at two in the morning during an incident, the one nobody can explain and everybody is afraid to remove, which is usually load-bearing for a reason that stopped being written down years ago.

A rewrite deletes all of it and calls that progress.

The debt nobody measures

AI has made writing code easier than ever. Generating code is now cheaper than understanding it, and those two costs used to move together.

The real technical debt is a codebase nobody truly understands, which is not at all the same thing as a messy one.

DORA found AI adoption hurting delivery stability in 2024, and in 2025 throughput turned positive while stability stayed negative. More output, more instability. That's what you'd predict when producing code gets nearly free and reviewing it, and debugging it at three in the morning, does not, because those are paid in human attention and there's a fixed supply of that per team per week.

Messy code a team understands is fine. Clean, well-typed code nobody has reasoned about passes review because there's nothing to point at, then fails in production because nobody knows what it assumes. The bus factor used to mean how many people can leave before the work stalls. It can now be zero on day one, with every test green.

Near-empty isometric warehouse racking with a single stocked shelf.
Understanding is inventory. It looks like idle time right up until something breaks.

Toyota is the example people reach for here, and they usually get it backwards. Toyota did perfect just-in-time manufacturing, but after the 2011 Tōhoku earthquake they built a semiconductor stockpile as a continuity measure, and that's a large part of why they rode out the 2020 chip shortage better than most of the industry. They had already paid for the lesson that some inventory isn't waste, it's a shock absorber that looks like idle money. Everyone who hadn't paid it got the bill in 2021. Understanding is the same kind of inventory, and it looks like idle time right up until something breaks in a way nobody predicted.

How I actually decide

I don't have a framework that produces answers. What I have is a set of questions that make the price visible before the decision gets made.

What am I willing to be bad at?

If the answer is nothing, no decision has been made. Costco carries about 4,000 products where a supermarket carries 50,000, and that constraint is the whole business model.

What currency does this cost, and who pays it?

Costs get quieter as they move between currencies. Saving infrastructure spend by adding two hours of on-call hasn't saved anything, it's moved the charge to a budget nobody reviews.

One-way door or two-way door?

A cache is reversible in an afternoon. A partition key isn't. Irreversible decisions deserve the meeting.

At what scale does this break?

Most architecture arguments are really about where that point sits, held by people who've never said a number out loud. Say the number.

Who can debug this at three in the morning?

Not who can build it. Who can fix it while it's on fire and the author has left the company. If the answer is one person, that's your real architecture.

What does this cost when it fails?

Every design is evaluated in the happy path and lived in the failure path. Decide in advance what you drop, or the system decides for you at the worst possible moment.

Why my portfolio has no tech stack

This is also why I've never listed tech stacks in my portfolio. I don't want to be known for the frameworks I use. I want to be known for understanding systems, making the right tradeoffs, and picking the right tool for the problem in front of me.

A stack is a snapshot of what was reasonable in one year for one problem. It tells you what I've touched, not whether I knew why.

The engineers I want to work with often can't name the newest features of their tools. What they can tell you is what those tools cost them, where they'll break, and what they'd do differently if the load changed. That knowledge doesn't go stale when the tool does.

Anyone can learn a stack.

Great architects understand the tradeoffs behind it.

Sources

Work with us

Have a project in mind? Let's talk.

Pilots, platforms, or roadmaps — tell us what you're building and we'll get back within one business day.

Newsletter

Get our latest writing in your inbox.

Agentic engineering, AI platforms, and what we learn shipping them — no spam, unsubscribe anytime.