Notes
Monolith
A monolith is one codebase deployed as one application with one database. Modules call each other in memory, and one transaction can update orders and payments together. It's simple to build, test and debug. The downsides appear later: everyone deploys together, it scales as a single unit, and one bad bug can take down everything.
- one codebase, one deployable
- modules call each other in
- memory (nanoseconds)
- one database, real transactions
- + simple to build, test, debug
- + easy refactors across modules
- − one deploy for everyone
- − scales as one unit
- − a bug can take it all down
Microservices
Microservices split the system by business area: users, orders, payments. Each has its own code, its own deploys and its own database, and they talk over the network. Teams ship independently, you scale only the busy service, and a failure can stay contained. But every call is now a network call, and there are no transactions across services.
- each service: one business area
- its own code, deploys and DB
- talk over the network (HTTP,
- gRPC, queues)
- + teams ship independently
- + scale only the hot service
- + one failure stays contained
- − network calls everywhere
- − no cross-service transactions
Why split
Good reasons to split are organisational and operational. Many teams stepping on each other in one codebase. One part with very different scaling needs, like video encoding next to profile pages. Or a part that must survive when others fail, like checkout. 'Big companies do it' is not a reason.
- many teams blocking each other
- in one codebase and deploy
- one part needs very different
- scaling (video encoding vs
- profile pages)
- one part must stay up when
- others fail (checkout)
- NOT: "it is what big tech does"
The costs
The costs are real. A function call becomes a network call that can be slow or fail halfway. Data spread across databases means no simple joins or transactions, so you need patterns like sagas. Debugging one request needs distributed tracing. And you run dozens of deployments, dashboards and alerts.
- network calls: latency, timeouts,
- retries, partial failure
- data spread across DBs:
- joins and transactions are hard
- (sagas, episode 33)
- debugging needs tracing
- (episode 37)
- more deploys, configs, alerts
- versioned APIs between teams
Boundaries
Draw boundaries by business capability, not by technical layer. A users service, a catalogue, orders, payments, not 'the database service'. Each service owns its data, and others go through its API or its events. A good test: if two services always have to change and deploy together, they should be one service.
- split by business capability:
- users, catalog, orders, payments
- not by technical layer
- (not "the database service")
- each service owns its data;
- others ask via its API or events
- if two services always change
- together, they are one service
Modular monolith
There's a middle path: the modular monolith. One deployable, but strict modules with clear interfaces, each owning its own tables, and no reaching into another module's data. When a real reason to split appears, a clean module is easy to pull out into a service. Many companies follow exactly that path.
- one deployable, but modules
- with clear interfaces and
- their own tables
- no reaching into another
- module's data
- easy to extract a module into
- a service later, when a real
- reason appears
- common path: monolith → modular
- → split the hottest pieces
Decision
So: a small team building something new should start with a modular monolith. Many teams with clear domains and mature tooling, deployment pipelines, monitoring and tracing, can benefit from microservices. And if only one piece is hot or risky, extract just that piece.
- small team, new product
- → monolith (modular)
- many teams, clear domains,
- mature ops (CI/CD, tracing)
- → microservices
- one hot or risky component
- → extract just that one
- start simple; split when it hurts
Say it like this
In an interview, draw a handful of services by capability, like users, posts, feed and notifications, each with its own datastore, behind an API gateway. Use synchronous calls where an answer is needed now and asynchronous events for everything else. It also shows maturity to say a real team might start with a monolith.
- draw services by capability:
- user, post, feed, notification
- each with its own datastore
- sync calls for reads that need
- an answer now (gRPC)
- async events for the rest (queue)
- API gateway at the edge
- mention: start smaller in reality