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
The Concept
What Each Style Actually Does
Monolith
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.
You are a small team validating a product, and the overhead of distributed systems would slow you down more than a redeploy ever will.
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
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.
Many internal teams need to expose functionality to each other and you need centralized control over how services communicate.
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
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.
Different parts of your product scale at different rates, and a failure in one should not be allowed to take down the rest.
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
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.
The workload is spiky or infrequent, and paying for idle servers between events would be wasted spend.
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
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.
Several unrelated systems all need to react to the same fact in real time, without blocking each other or the thing that produced it.
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.
Side By Side
What You Actually Trade
Monolith vs microservices
SOA vs event-driven
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
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.
Stops calling a failing service after repeated errors, so one bad dependency doesn't cascade through everything that depends on it.
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.
Isolates resources like thread pools or connections per dependency, so one slow service can't starve the others of capacity.
A unique ID attached to a request so retrying it doesn't repeat the side effect, like charging a customer twice.
Where a message goes after repeated processing failures, so it doesn't block the rest of the stream behind it.
Data across services converges to correct over time rather than instantly, which means reads may briefly be stale.
An infrastructure layer that handles retries, timeouts, and observability between microservices, so each service doesn't reinvent them.
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?
One team, one deploy, nobody has been paged at 3am yet. Stay on the monolith.
Multiple internal teams need to call each other's functionality through one gateway. Move to SOA.
Different parts of the product need to scale, deploy, and fail independently. Break out microservices.
The workload is spiky, infrequent, or event-triggered, and idle servers would be wasted spend. Go serverless.
Many independent systems need to react to the same fact in real time without blocking each other. Adopt event-driven architecture.
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.