Layers: help large projects

Layers: help large projects #

The main drawback (and benefit) of Layers is that much or all of the business logic is kept together in one or two components. That allows for easy debugging and fast development in the initial stages of the project but slows down and complicates work as the project grows in size. The only way for a growing project to survive and continue evolving at a reasonable speed is to divide its business logic into several smaller, thus less complex, components that match subdomains (bounded contexts [DDD]). There are several options for such a change whose applicability depends on the domain:

Divide the domain layer into Services #

Layers Split Domain to Services

Patterns: Services, Shared Database (Shared Repository), Orchestrator.

Goal: make the code simpler and let several teams work on the project efficiently.

Prerequisite: the low-level business logic comprises loosely coupled subdomains.

It is very common for a system’s domain to consist of weakly interacting bounded contexts [DDD]. They are integrated through high-level use cases and/or relations in data. For such a system it is relatively easy to divide the domain logic into Services while leaving the integration and data layers shared.

Pros:

  • You get multiple specialized development teams.
  • The largest and most complex piece of code is split into several smaller components.
  • There is more flexibility with deployment and scaling.

Cons:

  • Future changes in the overall structure of the domain will be harder to implement.
  • System-wide use cases become somewhat harder to debug as they span over many components.
  • Performance may degrade if the Services and Orchestrator become distributed.

Further steps:

Build an Event-Driven Architecture over a Shared Database #

Layers Split to Event-Driven Architecture

Patterns: Event-Driven Architecture (Pipeline (Services)), Shared Database (Shared Repository).

Goal: untangle the code, support multiple teams, improve scalability.

Prerequisite: use cases are sequences of loosely coupled coarse-grained steps.

If your system has a well-defined workflow for processing every kind of input request, it can be divided into several subdomain services, each hosting a few related steps of multiple use cases. Each service subscribes to inputs from other services and/or system’s clients and publishes output events.

Pros:

  • The code is divided into much smaller (and simpler) segments.
  • It is easy to add new steps or use cases as the structure is quite flexible.
  • You open a way to having several almost independent teams, one per service.
  • You can achieve flexible deployment and scaling as the services are stateless, but you need a Middleware for that.
  • The architecture naturally supports event replay as the means of reproducing bugs or testing / benchmarking individual components.
  • There is no need for explicit scheduling or thread synchronization.

Cons:

  • The system as a whole is hard to debug.
  • You will have to live with high latency.
  • You may end up with too many components which are interconnected in too many ways.

Further steps:

Build a Top-Down Hierarchy #

Layers to Hierarchy

Patterns: Top-Down Hierarchy (Hierarchy).

Goal: untangle the code, support multiple teams, earn fine-grained scalability.

Prerequisite: the domain is hierarchical.

Splitting the lower layers into independent components with identical interfaces simplifies the managing code and allows the managed components to be deployed, developed, and run independently of each other. Ideally, the mid-layer components should participate in decision-making so that the uppermost component is kept relatively simple.

Pros:

  • Hierarchy is easy to develop and support with multiple teams.
  • Individual components are straightforward to modify or replace.
  • The components scale, deploy, and run independently.
  • The system is quite fault tolerant.

Cons:

  • It takes time and skill to figure out good interfaces.
  • There are many components to administer.
  • Latency is suboptimal for system-wide use cases.

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