Introduction to Microservices
Everything through Module 17 lived in one deployable application. This module is the decision to split it apart — and, honestly, why you often shouldn't rush into it.
Learning objectives
- Beginner: State the core trade-off microservices make compared to a monolith (independent deployability versus operational complexity).
- Intermediate: Reason about where to draw a service boundary for a given feature, rather than splitting arbitrarily by technical layer.
- Advanced: Recognize when splitting into microservices is premature for a given team/system size, and argue for staying a monolith a while longer.
| Monolith | Microservices | |
|---|---|---|
| Deployment | One deployable unit for the entire application | Each service deployed independently |
| Scaling | Scale the whole application together, even if only one part is under load | Scale only the specific service under load |
| Data | Typically one shared database | Each service ideally owns its own data store |
| Failure isolation | A bug in one module can bring down the entire process | A failing service can (with proper design, Module 20) degrade gracefully without taking down everything |
| Operational complexity | Low — one thing to deploy, monitor, and debug | High — network calls, distributed tracing, eventual consistency, and more moving parts to operate |
◆ The problem
Splitting a monolith along the wrong lines (e.g. purely technical layers — "the controller service," "the database service") produces a distributed system with all of a monolith's tight coupling plus all of microservices' network overhead — the worst of both.
The standard heuristic is splitting along business capability boundaries — an Order service, an Inventory service, a Notification service — each owning a cohesive piece of business logic and its own data, so a change to how orders work doesn't require touching or redeploying the notification service at all.
▲ Pitfall
Microservices are frequently adopted prematurely, before a team or codebase is actually large enough to need them — trading a single easy-to-debug process for distributed transactions, network failure handling, service discovery, and significantly more operational overhead, without yet having the traffic or team-scaling problem that justifies the trade. A monolith with clean internal module boundaries is often the right choice until you have a concrete, specific reason (independent scaling needs, independent team ownership) to split further.
| Style | Characteristics | Covered in |
|---|---|---|
| Synchronous (REST/HTTP) | Direct request/response — simple to reason about, but the caller is blocked waiting and coupled to the callee's availability | Module 20 |
| Asynchronous (event-driven) | A producer publishes an event and moves on; consumers react independently, with no direct coupling or blocking wait | Module 19 |
◆ Under the hood — why both styles usually coexist
Real systems rarely pick one style exclusively: a synchronous call is natural for "get me this order's current status right now" (the caller genuinely needs an immediate answer), while an asynchronous event fits "an order was placed" (many independent services — inventory, analytics, notifications — need to react, but none of them should block the order-placement request waiting for all of them to finish). Module 19 and Module 20 build one of each.
✓ Quick recap
What's the standard heuristic for where to draw microservice boundaries? Business capability, not technical layer — each service should own a cohesive piece of business logic and its own data. What's the risk of adopting microservices before you actually need them? Taking on distributed-system complexity (network failures, service discovery, operational overhead) without yet having the scaling or team-organization problem that justifies it.
Want a visual for this concept?
Generate a diagram tailored to “Introduction to Microservices” — the AI picks whichever visual (flowchart, comparison, sequence, etc.) best fits.
Sign in to generate a visual →