Skip to content

Microservices Architecture

A microservices architecture builds a system from many small services. Each service can be deployed on its own. Fowler and Lewis name this independent deployability as the main reason to use services instead of libraries as components.

Split by business capability. Many systems divide into technical layers. Microservices divide by business capability instead. Each service implements one capability within a bounded context. A bounded context is a boundary around one part of a complex domain. Domain-driven design uses it to split that domain. See the articles Bounded Context and Domain-Driven Design.

Size and granularity. Size is often described by team size. Examples range from Amazon’s two-pizza team to a half-dozen people supporting half a dozen services. A single small team can maintain each service. Avoid services that are too fine-grained. Keep functions that change together in the same service. Chatty communication between services signals tight coupling and low cohesion. See Coupling and Cohesion.

Own data. Each service owns its data and schema. Services share no database. This cuts dependencies between services and lets them evolve independently.

Communication. Services usually talk through HTTP request-response with resource APIs, or through lightweight messaging. Long call chains (A calls B, which calls C) add latency and network load. APIs should not be chatty, and asynchronous communication helps where possible.

Operations. Success needs a mature DevOps culture, orchestration such as Kubernetes, and automated CI/CD. Observability needs centralized logging and distributed tracing. Teams may pick different languages and frameworks. Too many make the system hard to maintain, so some governance is advisable.

Origin. The term was first discussed at an architects’ workshop near Venice in 2011.

An online shop has separate services for catalog, orders, and payments. Each has its own small team and its own database. The orders service never reads the payments database. It asks the payments service through an API or a message. The team can release a payments change without touching the other two services.

Microservices add a cost premium. Fowler advises that most systems should start as a single monolithic application. Microservices fit only when the system’s complexity and size justify them.

  • Data consistency: A change that spans several services is unlikely to be an ACID transaction. Teams use BASE and eventual consistency instead, which is harder to reason about.
  • Latency: Calls over the network add delay, especially in long chains.
  • Debugging: Correlated logging across services can be hard.
  • Operations: The system needs DevOps maturity, orchestration, and automation.
  • Technology sprawl: Free technology choice creates a maintenance burden.

Services organized by business capability, each owning its data, communicating through lightweight interfaces.

Diagram source
flowchart LR
O[Orders service] -->|API or message| P[Payments service]
O -->|API or message| C[Catalog service]
O --- OD[(Orders data)]
P --- PD[(Payments data)]
C --- CD[(Catalog data)]
  • Each service implements a single business capability within a bounded context.
  • Each service owns its data and schema, with no shared database.
  • The document explains how data stays consistent across services without ACID transactions.
  • Long call chains and chatty APIs between services are avoided or justified.
  • Orchestration, CI/CD, centralized logging, and distributed tracing are in place or planned.