Courses › System Design › Core Concepts

Microservices

Monolith vs microservices, service boundaries, data ownership and sync vs async communication.

Most interview designs are drawn as several services — users, orders, payments, notifications. That's fine, but you should be able to explain why those boundaries exist, how the services talk to each other, and who owns which data. Interviewers also notice candidates who split everything into dozens of services without a reason.

Monolith vs microservices

A modular monolith — one deployable with strict internal module boundaries — is a strong default for small teams. Split out a service when there's a concrete reason: different scaling needs (a CPU-heavy transcoder), different reliability requirements (payments), independent team ownership, or different technology (a search index).

Drawing service boundaries

  • Split by business capability (orders, inventory, billing), not by technical layer ("database service," "validation service").
  • Aim for high cohesion, low coupling: changes to one feature should usually touch one service.
  • A useful smell test: if two services must always be deployed together, or one constantly calls the other synchronously for every request, they probably belong together.

Data ownership

  • Each service owns its database, and other services access that data only through its API or events. Shared databases create hidden coupling: one team's schema change breaks another.
  • Data that other services need is published as events so they can keep their own read-optimized copy (e.g. the search service maintains a denormalized index from ProductUpdated events).
  • Operations that span services can't use one transaction; use the transactional outbox and sagas.

Communication

[Client] -> [API Gateway] -> [Order service]
[Order service] -> [Pricing service: sync gRPC]
[Order service] -> {Kafka: OrderPlaced} -> [Email service]
{Kafka: OrderPlaced} -> [Analytics service]
  • Keep synchronous call chains short — three services deep is already a lot. See Resilience Patterns.
  • Prefer events for notifying others of facts; prefer commands (queues) for asking one service to do work.

The supporting infrastructure

  • An API gateway as the single entry point: authentication, routing, rate limiting.
  • Service discovery — services find each other by name through DNS, Kubernetes Services or a registry.
  • A service mesh (optional) — sidecar proxies for mutual TLS, retries and telemetry.
  • Observability — distributed tracing is essential once a request crosses several services.
  • Versioned APIs and schemas — services deploy independently, so changes must be backward compatible.

[!TIP] Name the services, then justify one split In an interview you don't need to defend every boundary. Draw a few services, and explain one meaningful split — "media processing is its own service because it's CPU-heavy and scales with uploads, not with reads."

[!INTERVIEW] E-commerce boundaries "I'll split catalog, cart, orders, payments and notifications. Payments is separate because it has stricter compliance and reliability requirements; catalog is separate because it's read-heavy and cached aggressively. Orders calls payments synchronously because checkout needs the result, but publishes OrderPlaced for notifications and analytics, which don't need to block the user."