Layered Services

Layered Services #

Layered Services

Cut the cake. Divide each service into layers.

Variants:

  • Orchestrated Three-Layered Services,
  • (Pipelined) Choreographed Two-Layered Services,
  • (Pipelined) Command Query Responsibility Segregation (CQRS) [MP, LDDD].

Structure: Subdomain services divided into layers.

Type: Implementation of Services, Pipeline or Monolith, correspondingly.

Layered Services is an umbrella architecture for common implementations of systems of Services. It does not introduce any special features as layers are completely encapsulated by the service which they belong to. Still, as the services may communicate at different layers, there are a couple of things to learn by exploring the subject matter.

Performance #

Layered Services are similar to Services performance-wise: use cases that involve a single service are the fastest, those that need to synchronize states of multiple services are the slowest.

Remarkable features of Layered Services include:

  • Independent scaling of layers of the services. It is common to have multiple instances (with the number varying from service to service and changing dynamically under load) of the layers that contain business logic while the corresponding data layers (databases) are limited to a single instance.

Layered Services - sharding

  • The option to establish additional communication channels between lower layers in order to drive CQRS databases (read/write replicas of the same database) or CQRS Views (cached subsets of data from other services) [MP].

Layered Services - channels

Variants #

Layered Services vary in the number of layers and in the layer through which the services communicate:

Orchestrated Three-Layered Services #

Three-Layered Services

Probably the most common backend architecture has three layers: application, domain, and infrastructure [DDD]. The application layer orchestrates the domain layer.

If such an architecture is divided into services, each of them receives a part of every layer, including application, which means that now there are as many Orchestrators as services. Each Orchestrator implements the API of its service by integrating (calling or messaging into) the domain layer of its service and APIs of other services, which makes all the Orchestrators interdependent:

Dependencies #

The upper (application) layer of each service orchestrates both its middle (domain) layer and the upper layers of other services, resulting in mutual orchestration and interdependencies.

Mutual Orchestration - 4

The good thing is that the majority of the code belongs to the domain layer which depends only on its databases. The bad thing is that changes in the application of one service may affect the application layers of all of the other services.

Relations #

Three-layered services:

Evolutions #

Orchestrated Layered Services may become coupled, which is resolved either by merging their layers:

Three-Layered Services - 1

or by building derived datasets:

  • A CQRS View [MP] inside a service aggregates any events from other services which its owner is interested in.
  • A dedicated Query Service [MP] captures the whole system’s state by subscribing to events from all the services.

Three-Layered Services - 2

If the services become too large:

  • The middle layer can be split into Cells.

Three-Layered Services - 3

Choreographed Two-Layered Services #

Two-Layered Services

If there is no orchestration, there is no role for the application layer. Choreographed systems are made up of services that implement individual steps of request processing. The sequence of actions (integration logic) which three-layered systems put in the Orchestrators now moves to the graph of event channels between the services. This means that with choreography the high-level part of the business logic (use cases) exists outside of the code of the constituent services.

Dependencies #

Dependencies are identical to those of a Pipeline or choreographed Services except that each service also depends on its database.

Relations #

Two-layered services:

Evolutions #

If Choreographed Layered Services become coupled:

Two-Layered Services - 1

CQRS Views [MP] or Query Services [MP] are also an option:

Two-Layered Services - 2

An overgrown service can be:

  • Split in two

Two-Layered Services - 3

Command Query Responsibility Segregation (CQRS) #

CQRS

Command Query Responsibility Segregation (CQRS) [MP, LDDD] is, essentially, the division of a layered application or a service into two (rarely more) services, one of which is responsible for write access (handling commands) to the domain data while the other(s) deal with read access (queries), thus creating a data pipeline (see the diagram below). Such an architecture makes sense when the write and read operations don’t rely on a common vision (model) of the domain, for example, writes are individual changes (OLTP) that require cross-checks and validation of input while reads show aggregated data (OLAP) and may take long time to complete (meaning that forces for the read and write paths differ). If there is nothing to share in the code, why not separate the implementations?

CQRS - pipeline view

This separation brings in the pros and cons of Services: commands and queries may differ in technologies (including database schemas or even types), forces, and teams at the expense of consistency (database replication delay) and increasing the system’s complexity. In addition, for read-heavy applications the read database(s) is easy to scale.

CQRS has several variations:

CQRS - subtypes

It is noteworthy that while ordinary Layered Services usually communicate through their upper-level components that drive use cases, a CQRS system is held together by spreading data changes through its lowest layer.

Examples: Martin Fowler has a short article and Microsoft a longer one.

Dependencies #

Each backend depends on its database (its technology and schema). The OLTP to OLAP data replication requires an additional dependency that corresponds to the way the replication is implemented:

CQRS

Relations #

CQRS:

Evolutions #

CQRS

Summary #

Layered Services is an umbrella pattern that conjoins:

  • Three-Layered Services where each service orchestrates other services.
  • Two-Layered Services that form a Pipeline.
  • CQRS that separates read and write request processing paths.

CC BY Denys Poltorak. Editor: Lars Noodén. Download from Leanpub or GitHub. Powered by odt2wiki and Hugo Book.