Microservices vs monolith
When a monolith is the right answer
Microservices are an organizational scaling tool. They do not make a single request faster; a network hop only adds latency. What splitting buys is independent deploys and team ownership: many teams shipping without coordinating one release. For an eight-person team that win is small and the tax is immediate, so the honest answer to "let's go microservices to move faster" is usually a modular monolith with clean internal boundaries and one database.
Wrong "microservices scale better than a monolith." A monolith scales horizontally too, run N copies behind a load balancer. Services let you scale and deploy parts independently. Conway's law is the tell: service boundaries end up mirroring team boundaries whether you plan for it or not. When you do migrate, use the strangler fig: peel off one bounded context at a time behind a facade and skip the big-bang rewrite.
Where service boundaries go
Split by business capability (Orders, Payments, Inventory), never by technical layer and never one service per table. The sizing tool is the bounded context: the largest boundary inside which one domain model stays consistent. "Account" means one thing in Billing and another in Support, so those are two contexts. A microservice is a bounded context or smaller, but a context is not automatically one service.
Data ownership makes it real: one service, one private database. Other services reach it through its API or its events, never by reading its tables. Share a database and a schema change for one service breaks another. That is a distributed monolith: the network cost of services with the coupling of a monolith. You also lose cross-database JOINs, so cross-service reads use API composition or a CQRS read model fed by events.
Distributed transactions and the saga pattern
You cannot wrap writes in three databases in one BEGIN...COMMIT. Two-phase commit can, but it blocks: the coordinator holds locks across every participant until commit, and a dead coordinator leaves them in-doubt, so availability drops as you add services.
A saga models the business transaction as a sequence of local transactions, each committing in one service and triggering the next (publish the event via the outbox so it is atomic with the commit). On failure, run compensating transactions to semantically undo the committed steps: you issue a refund, you cannot un-charge the card.
Order.create -> status = PENDING
Payment.charge -> on fail: Order.cancel
Inventory.reserve -> on fail: Payment.refund; Order.cancel
Shipping.schedule -> on fail: Inventory.release; Payment.refund; Order.cancel
Order.confirm -> status = CONFIRMED
Choreography has no coordinator: services react to events and emit their own, loosely coupled but with an implicit flow that is hard to trace past a few steps. Orchestration puts a central coordinator in charge of each step, which is easier to debug once the logic branches.
The point interviewers wait for: a saga is ACD, not ACID. There is no isolation. Each step commits and is visible before the saga finishes, so a concurrent read sees a half-placed order (lost updates, dirty reads). The fix is a semantic lock, the PENDING status other transactions respect until the saga settles. Order the steps so the hardest-to-undo one runs last.
beta
The interviewer part is in the works.
The diagnostic, personal maps, and AI mock interviews are being finished right now. The notes stay free either way. Leave an email and you'll get the first-cohort invite, plus a month of Pro when it opens.