advanced~2h

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.
MonolithMicroservices
DeploymentOne deployable unit for the entire applicationEach service deployed independently
ScalingScale the whole application together, even if only one part is under loadScale only the specific service under load
DataTypically one shared databaseEach service ideally owns its own data store
Failure isolationA bug in one module can bring down the entire processA failing service can (with proper design, Module 20) degrade gracefully without taking down everything
Operational complexityLow — one thing to deploy, monitor, and debugHigh — 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.

StyleCharacteristicsCovered in
Synchronous (REST/HTTP)Direct request/response — simple to reason about, but the caller is blocked waiting and coupled to the callee's availabilityModule 20
Asynchronous (event-driven)A producer publishes an event and moves on; consumers react independently, with no direct coupling or blocking waitModule 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 →

Practice quiz

Next Step

Continue to Event-Driven Architecture with Kafka← Back to all Spring Boot chapters