Microservices are an implementation of SOA based on lessons learned implementing SOA, and they're seen by the industry as a solution to the challenges of monolithic designs.


Services are borrowed from SOA:

  • Business domain centric: boundaries and seams defined by owning team or domain.
  • High cohesion: follows the single-responsibility principle (Private): inputs, outputs and operations relate only to a single domain; and masks implementation details via encapsulation (Private).
    • Enforces backwards compatibility, maybe by wrapping newer versions of the interface with compatible implementations.
  • Autonomy: owns its domain.
    • Owns its own storage.
  • Resilience: degrade gracefully to default functionality in the event of error rate, delay or unavailability.
    • Use timeouts for queries with external services.
    • Interactions with other services should be stateless.
  • Observability: centralised storage and alarming on key metrics such as error rate and performance and logging.
    • Correlation ID uniquely identifies individual requests, allowing for fan-out analysis.
    • Structured logging with defined error levels.
    • Annotate all log and metric entries with attributes aiding discovery, e.g. instance ID, date/time.
  • Automation: testing and environment setup should take place in a continuous integration environment.
    • Provide immediate feedback to developers.
    • Regression tests should cover different API versions.
    • Automate delivery.


Transactions in a microservices system are distributed: a request can be a composition of multiple services' responses. This makes asynchronous programming models essential.

There are two primary approaches to performing work:

  • Synchronous request/response, where a client awaits a response from a request in the same exchange.
  • Asynchronous request/response, where a client may request that the output is written to a specific network location (e.g. blob storage) or continues to poll for the status, or allows another system to collect and process the response via a message bus or queue.

Communication usually takes place over lightweight, open communication protocols such as gRPC or REST, avoiding tight coupling around a client library.

Transparent over multiple transports?


The hosting of these services is characterised by centralised management:

  • Containers running an individual process are an ideal fit.
  • Serverless/FaaS removes the management of the services entirely, allowing scaling based on transaction volume.
  • API gateways are API-optimised load balancers, providing a central entry point for clients and performing routing and authentication/authorisation.
  • Service discovery
    • Server-side
    • Client-side


Circuit breaker

The circuit breaker pattern defines a way of detecting the failure of a service and backing off to allow it to recover, providing a solution to the thundering herd problem.

Moving toward microservices

  1. Get black box testing in place.
  2. Ensure the system is adequately observable such that you're able to identify faults post-migration.
  3. Split the application into bounded contexts, duplicating shared components where required.
  4. Identify seams in data storage and separate these out, such that each service owns its own storage. This might necessitate building new services that solely manage the storage.
  5. Migrate individual services.