System Design Bits

Support the project

System Design Bits is free and always will be. If it helped, a coffee helps back.

Buy Me a Coffee QR codeBuy me a coffee

Concept 2 · Fundamentals·13 min read

Architectural Styles: Monolith to Event-Driven

The progression companies actually get forced through, and what each step costs.

Big Idea

These five styles are not a ranking, and moving between them is not an upgrade. Every migration trades one set of problems for another, nobody skips a stage for free, and real systems end up running several at once rather than picking a winner.

Why This Exists

Why Teams Move Too Early

▸

Teams reach for microservices because it is what the companies they admire run, then discover they have bought network latency, service discovery, and per-service pipelines without ever having had the pain that justified any of it.

▸

Company size is the signal most people use for when to move, and it is the wrong one. The real signals are specific symptoms, like a deploy touching unrelated code, or one team's bug taking down a feature owned by someone else.

▸

Some problems that feel architectural are not. If tracing a request across services has become guesswork, that is a tooling gap, and no amount of restructuring will produce the tracing you actually needed.

Think Of It Like

A Kitchen That Keeps Outgrowing Itself

Monolith

One cook running the whole kitchen. Nothing to coordinate, nothing to route, and nobody eats if that cook is out sick.

SOA

Stations in the kitchen, but every order passes through one head chef who decides where it goes. Coordinated, until that chef becomes the queue.

Microservices

Every station takes its own orders and owns its own supplies. Genuinely independent, and now somebody has to be able to say where an order actually is.

Serverless

A caterer you call only when there is an event. No kitchen sitting idle, and they need a moment to arrive.

Event-driven

A board where “table 6 ordered” gets posted, and every station that cares reacts without being told to. Nobody waits to be asked, and nobody can say exactly when the whole order is done.

The Concept

What Each Style Actually Does

Monolith

How it works

One codebase, one build, one deployment. Database logic, business logic, and the website are glued into a single unit that ships together. Early Amazon.com ran exactly like this, and it worked until every small change meant redeploying the entire site and one bug could take down the whole store.

Use it when

You are a small team validating a product, and the overhead of distributed systems would slow you down more than a redeploy ever will.

Avoid

Splitting into microservices before the monolith has actually caused pain. Premature decomposition buys you network latency, service discovery, and per-service deploys, none of which earns you anything if one team can already ship fast.

SOA

How it works

The system breaks into services, but they all talk through a shared middleman called an enterprise service bus, a central switchboard routing messages between departments. In 2002 Jeff Bezos mandated that every Amazon team expose its functionality through a service interface, no exceptions. Clunky next to what came later, but the direct ancestor of AWS.

Use it when

Many internal teams need to expose functionality to each other and you need centralized control over how services communicate.

Avoid

Letting the bus become a dumping ground of untested transformation logic. If nobody can explain what happens to a message between send and receive, you have built a black box, not an integration layer.

Microservices

How it works

Small, independently deployable services, each one owning its own database. Each can be updated, scaled, or crashed without taking down the others. Netflix is the textbook case: after a 2008 database outage took their whole service down, they spent years breaking the monolith apart so a failure in recommendations never touches billing.

Use it when

Different parts of your product scale at different rates, and a failure in one should not be allowed to take down the rest.

Avoid

The distributed monolith: services that all deploy together, share one database, or break the moment another service's schema changes. That is a monolith with network latency, not microservices.

Serverless

How it works

You stop thinking about servers. You write a function, it runs only when triggered by an event, then disappears, and you are billed per execution rather than for idle uptime. Upload an image, a function fires, resizes it, and shuts down. No server was sitting around waiting for that to happen.

Use it when

The workload is spiky or infrequent, and paying for idle servers between events would be wasted spend.

Avoid

Putting a latency-sensitive, user-facing endpoint on functions you have never load-tested. Cold starts run a wide range, roughly 150 to 500ms for Python or Node, but multiple seconds for a heavy dependency tree or a VPC attachment. Fine for a background resize, painful for a checkout button.

Event-driven

How it works

Services publish events into a stream and listeners react independently. The publisher does not know who is listening, which is what lets a new consumer be added without touching the service that produced the event.

Use it when

Several unrelated systems all need to react to the same fact in real time, without blocking each other or the thing that produced it.

Avoid

Assuming the decoupling is free. Tracing one request across many asynchronous consumers is genuinely harder, and ordering guarantees stop being something you get for nothing.

The Real Signal

When To Actually Move

Company size isn’t the real signal, these symptoms are. Match what you’re feeling to what fixes it, and notice that the last row is not an architecture at all.

Signal you're seeingMove to
Every deploy touches unrelated code and Friday releases are dreadedSOA or microservices
Multiple teams keep re-implementing the same internal integrationSOA
One team's bug takes down a feature owned by a different teamMicroservices
You're paying for servers that sit idle most of the dayServerless
Five unrelated services all need to react to the same business eventEvent-driven
Tracing one request across services is now guessworkAdd tracing. That's a tooling gap, not a new architecture
That last row is the one worth remembering. Some problems that feel architectural are not, and a system rewritten to fix a missing instrumentation library still won’t have the tracing it needed.

Side By Side

What You Actually Trade

Monolith vs microservices

MonolithMicroservices
What it isOne deployable unitMany independently deployable services
You manageA single build and deploy pipelinePer-service pipelines, service discovery, networking
Billed byServer uptime, regardless of loadUsage per service, scaled independently
Failure blast radiusWhole applicationIsolated to the failing service

SOA vs event-driven

SOAEvent-driven
What it isServices routed through a central busServices reacting to a shared event stream
You manageThe enterprise service bus and its routing rulesTopics, consumers, and event schemas
Billed byBus throughput and middleware licensingStream throughput and retention
Failure blast radiusBus outage stalls all routed trafficA slow consumer only lags itself, not the stream
Read the failure blast radius row of both tables together. That single line is most of the reason anyone takes on the extra machinery: not speed, but limiting how much goes down when something does.

In Practice

Nobody Runs Just One

These patterns aren’t a ladder you climb and leave behind, they compose. A modern system is usually several of them layered together: microservices that communicate through events instead of direct calls, a few spiky workloads pulled out into serverless functions, and an API gateway or service mesh handling the cross-cutting concerns like auth, retries, and rate limits so no single service has to reinvent them.

Amazon today runs microservices, event streams, and serverless functions side by side. Not one pure architecture, and that is the normal end state rather than a compromise.

Key Terms

Jargon You’ll Hit Next

Enterprise service bus

The central switchboard in SOA that routes messages between services, holding the routing rules so individual services do not have to know about each other.

Circuit breaker

Stops calling a failing service after repeated errors, so one bad dependency doesn't cascade through everything that depends on it.

Saga pattern

Coordinates a multi-step transaction across services using compensating actions instead of one database transaction, because no single database owns all the data any more.

Bulkhead

Isolates resources like thread pools or connections per dependency, so one slow service can't starve the others of capacity.

Idempotency key

A unique ID attached to a request so retrying it doesn't repeat the side effect, like charging a customer twice.

Dead-letter queue

Where a message goes after repeated processing failures, so it doesn't block the rest of the stream behind it.

Eventual consistency

Data across services converges to correct over time rather than instantly, which means reads may briefly be stale.

Service mesh

An infrastructure layer that handles retries, timeouts, and observability between microservices, so each service doesn't reinvent them.

API gateway

A single entry point that routes, authenticates, and rate-limits requests to backend services.

Seen In The Wild

The Progression, As It Actually Happened

▪

Early Amazon.com ran as one monolithic application handling everything. It worked until it didn't: every small change meant redeploying the entire site, and one bug could take down the whole store.

▪

In 2002 Jeff Bezos issued an internal mandate that every Amazon team must expose its functionality through a service interface, no exceptions. It was clunky and heavyweight next to what came later, and it was the direct ancestor of AWS.

▪

Netflix spent years breaking its monolith into hundreds of microservices after a 2008 database outage took the whole service down, specifically so a failure in one area like recommendations never touches another like billing.

▪

Amazon today runs microservices, event streams, and serverless functions side by side. Not one pure architecture, which is the normal end state rather than a compromise.

Key Points

What To Carry Forward

✓

These five are not a ladder you climb and leave behind. A modern system usually layers several of them together, and running more than one is normal rather than a sign of indecision.

✓

Every migration trades one set of problems for another. Nobody skips a stage for free, and no step is strictly better than the one before it.

✓

Company size is not the signal. Specific symptoms are: deploys touching unrelated code, one team's bug breaking another team's feature, servers idle most of the day.

✓

A distributed monolith is the common failure: services split apart that still deploy together or share a database, paying every cost of distribution with none of the independence.

✓

Serverless bills per execution instead of per idle hour, but cold starts make it a poor fit for latency-sensitive user-facing paths unless you have measured them.

✓

SOA centralizes knowledge in a bus, event-driven distributes it into a stream. The publisher not knowing its listeners is what makes new consumers cheap to add.

Common Mistakes

Where This Usually Goes Wrong

✕

Splitting a monolith into microservices before the monolith has actually caused pain, buying network latency and per-service pipelines that earn nothing while one team can still ship fast.

✕

Building a distributed monolith: services that deploy together, share one database, or break when another service changes its schema, which is every cost of distribution with none of the benefit.

✕

Letting the enterprise service bus accumulate untested transformation logic until nobody can explain what happens to a message between send and receive.

✕

Putting a latency-sensitive endpoint on serverless functions without load-testing cold starts, which range from barely noticeable to multiple seconds depending on runtime and dependencies.

✕

Treating a tooling gap as an architecture problem, most often rewriting a system because requests are hard to trace when distributed tracing was the actual answer.

✕

Assuming event-driven decoupling is free, and discovering afterwards that ordering guarantees and cross-service debugging both got harder.

Try It Yourself

Which Stage Are You Actually At?

1

One team, one deploy, nobody has been paged at 3am yet. Stay on the monolith.

2

Multiple internal teams need to call each other's functionality through one gateway. Move to SOA.

3

Different parts of the product need to scale, deploy, and fail independently. Break out microservices.

4

The workload is spiky, infrequent, or event-triggered, and idle servers would be wasted spend. Go serverless.

5

Many independent systems need to react to the same fact in real time without blocking each other. Adopt event-driven architecture.

Read those five against a system you actually work on, and be honest about which line describes it today rather than which one you would like to be answering. If none of the symptoms are present, the answer is to stay where you are.

Quiz Review

Check your understanding

Question 1 of 6

A team keeps saying they should move to microservices because that's what the companies they admire run. What is wrong with that reasoning?

  • ✓Company size is not the signal. Those companies moved because a specific pain forced them to, usually one team's deploy breaking another team's feature, or parts of the product needing to scale at wildly different rates. Adopting the destination without the pain buys network latency, service discovery, and per-service pipelines while earning nothing, because a single team that can already ship fast gets no benefit from paying those costs.