Loading...
Loading...
Architectural style structuring an application as a collection of modular, lightweight services.
Trigger real-world events to see how both architectures react.
One codebase, one database, one process.
Independent services behind an API Gateway.
You already know from the RPC-versus-REST module how in-process calls become network calls with timeouts and retries, and from the service-discovery module how callers find healthy instances without memorizing addresses. Startups do not start with microservices (many small programs, each owning one job and its data, talking over the network). They start with a monolith (one big program holding every job and one shared database). But as the team grows from 5 to 500, one codebase becomes a queue: every deploy waits on everyone, and one slow feature holds the whole release. Services let hot parts scale and ship alone, at the price of turning function calls into network trips. In the sandbox above, ship one small fix with the monolith and watch the whole app redeploy, then ship it as a service and watch one truck roll while the rest keep serving, because independence is the product you are buying.
Think of one big restaurant kitchen versus a fleet of food trucks, the one comparison we will use here: the big kitchen shares everything and serves fast while the crew is small, while trucks move independently once the staff outgrows one room but must phone each other for every shared ingredient. In the sandbox, ship one small fix with the monolith and watch the whole app redeploy, then ship it as a service and watch one truck roll while the rest keep serving, because independence is the product you are buying.
The naive belief is that services are a free speedup: cut the code apart and everything scales. The real arc is harsher. A monolith wins while coordination fits in one head, then merge conflicts, test time, and blast radius tip the balance. Services fix the people bottleneck by accepting a machine bottleneck: every former function call now pays network latency, serialization (converting objects to bytes and back), and the chance of failure. Work the latency math: 3 inside calls at 0.05ms each cost 0.15ms in memory, while 3 network calls at 2ms each plus retries cost 6ms or more, about 40 times slower per hop.
| Pressure point | One big program | Many small programs |
|---|---|---|
| Growing load | Scale everything together, wasting memory on cold parts to feed the hot one. | Scale only the hot service. Ten checkout copies, one admin copy. |
| One bad bug | One fatal crash can take the whole process down with it. | One truck stalls while others serve a smaller menu, called graceful degradation. |
| Shipping speed | Ship everything at once. Slower reviews, bigger blast radius. | Ship one service alone in minutes with its own rollback. |
| Shared facts | One database with easy joins across tables. | Each service owns its rows. Joins become network assembly you code by hand. |
| Cost per call | In-memory calls at microseconds, rarely failing. | Network calls at milliseconds over HTTP or gRPC (two common wire styles), with timeouts and retries. |
The tipping point: If services are so good, why not start there? Because they trade code complexity for operations complexity, and a team of five feels only the second half.
The naive split draws boxes and stops. The real split budgets for the four bills below and only proceeds when the people bottleneck already hurts more. We rejected splitting into services on day one because a team of five pays all four bills below with none of the headcount pain to justify them. In the sandbox, kill one middle service and watch the271 end-to-end path fail even though four boxes glow green, because distributed success multiplies: 5 hops at 99.9% each yield about 99.5% overall, and at 99% each only 95%.
Fetching a user's orders used to be a memory lookup. Now the gateway calls orders, which calls users, each with timeouts (deadlines after which the caller gives up) and retries. Budget latency per hop and cap retries, or one slow truck queues the whole fleet.
Each service owns its data, so no single query joins users to orders. You assemble in code, duplicate read models, or emit events others copy. Every choice buys either extra storage, extra lag, or extra reconciliation when copies disagree.
When checkout fails, the cause could sit in the gateway, cart, or payments. Distributed tracing (passing one request id through every hop so logs join up) plus shared dashboards turns five mysteries into one timeline. Without it you grep five machines per complaint.
More services mean more deploys, dashboards, alerts, and version matrices. A fleet of 20 with weekly deploys is nearly 3 production changes a day. Your delivery and on-call effort must grow with the fleet, or speed gains drown in operational drag.
Carve out the hot or fast-moving slice first, like checkout or search, while the rest stays whole. Give it its own data, its own deploy, and its own dashboard. Promote the next slice only when deploys collide or one part needs ten copies while the rest needs one.
Split by boundaries that already exist in the business, not ones you hope will appear. And remember what the sandbox just showed you: every split trades a code problem for an operations problem. Which seam in your own system already hurts enough that you would gladly pay four operations bills to cut it?
Try this in the playground
Open a template and build it yourself — then take a quiz.