DDD Reference Engineering Architecture

1 background

The application architecture styles adopted by different teams to implement DDD may be different, and there is no unified and standard DDD engineering architecture. Some teams may follow the classic DDD four-tier architecture, or the improved DDD four-tier architecture, some teams may comprehensively consider various architectural styles such as layered architecture, neat architecture, and hexagonal architecture, and some may introduce CQRS in practice to solve the problem of reading The difference between model and write model and so on. Even if it is impossible to formulate a common, standard engineering application architecture, it is still valuable to develop a reference architecture that follows the domain-driven design idea for the team. For the following reasons:

  • Provide a quick-start engineering reference for the tactical design of the team to practice DDD
  • Refer to a large number of naming and structural decisions of the project, explicitly reflect the relevant concepts of DDD, and help the team to reach a consensus on the tactical implementation of DDD
  • At the same time, the reference architecture helps to precipitate some of the team's thoughts and best practices on domain-driven design

2 Considerations for Reference Architectures

Although it is impossible to formulate a completely general DDD reference architecture, it is feasible and practical to formulate a reference architecture in a specific context. The choice of context should be as close as possible to the actual engineering practice scenario and consider multi-dimensional factors.

The reference engineering architecture described in this article adheres to the following principles:

  • Following the essential idea of ​​domain-driven design,
  • Fully consider the characteristics of business system construction
  • Minimize dependencies and keep them lightweight

It is hoped that the engineering reference architecture will cover the following areas

  • Separation of business and technical domains
    • The reference architecture should follow the characteristics of technology and business isolation, and you can refer to a variety of architecture trends. The separation of business and technical concerns is not a unique feature of DDD. This important principle is followed in the hexagonal, clean architecture, and onion architectures.
  • Multiple Bounded Context Scenarios
    • When most teams split microservices based on DDD, especially in the initial stage of system construction, the granularity of the bounded context within a single microservice application needs to be weighed. Due to team organizational structure factors and microservice cost issues, a single application generally accommodates multiple bounded contexts (ideally 1:1). These Bounded Contexts are likely to be migrated to standalone applications with subsequent incremental iterations. Therefore, the multi-context application scenarios to be considered in the reference architecture.
  • Clear components, responsibility boundaries and dependencies
  • Support field report scenarios
    • Reporting scenarios are relatively common in business systems, and DDD does not reflect the processing method of this scenario. As an engineering reference architecture, it is still hoped that it can be triggered from the actual business to reflect the display support for the writing model and report model
  • Minimize external dependencies
    • As a reference architecture, it is necessary to eliminate unnecessary dependencies and keep the engineering architecture lightweight

3 Anatomy of a Reference Architecture

3.1 Multi-context structure of the application


Based on the above principles, the reference project considers the scenario of multiple contexts in a single application, in order to make a trade-off between modularity, service granularity, and cost. The schematic diagram of application architecture’s support for multiple contexts is shown below. After the solution domain identifies and divides the bounded contexts, based on their business cohesion and relevance, multiple contexts are now included in a single engineering application. There may be interactions between multiple bounded contexts in a single application, and the form of interaction can be based on event-driven or in-process calls. The coupling between contexts is lower in the event-driven approach, but generally requires the introduction of event bus support, and the introduction of additional components will inevitably lead to an increase in complexity. In-process calls will have higher coupling, but the complexity will be lower from the perspective of implementation. Which way to choose specifically, developers can make trade-offs based on the actual situation.

It should be noted again that this application architecture decision is a multi-factor trade-off, which may not be consistent with the idealized practice of 1:1 subdomain and bounded context as we know it. However, the overall consideration from the context of a specific architectural decision still has practical application value.

From the logical schematic diagram above, let’s go one level deeper and analyze the presentation form of the detailed application architecture from the layered dimension, as shown in the following figure:

3.2 Hierarchical Concerns

client

The client is in a different process from the application, and is the consumer of application capabilities. In actual projects, it may be the APP, PC, applet, official account, or third-party business caller.

access layer

The access layer is the middle layer between the external system and the internal business capabilities of the application. The access layer is the external facade of the application layer and the entrance for the current application to expose the business capabilities to the outside world. The composition of this layer may be the HTTP interface declaration provided externally, distributed timing task scheduling, message listener, RPC service and so on. Its important responsibilities include basic parameter verification, input parameter adaptation and service routing (forwarding to the application service at the first layer) and response data adaptation for requests from external systems.

Business Layer:

This layer is the layer where the application's business logic resides. The entire architectural style adopts a modular single style, and different bounded contexts in this layer are embodied as different modules. A layered architecture is adopted in each bounded context, which is independently divided into application layer, domain layer and gateway layer.

Application layer:

Coordinate domain objects, domain services, or external dependent services to complete business use cases. This layer only coordinates capabilities and does not process any domain logic.

domain layer:

The domain layer is the core of the entire layering and has nothing to do with technical implementation. It is mainly responsible for domain models, domain events, domain service definitions, and interface abstraction of business-related external services and warehouse interfaces.

The essential difference between the domain layer and application services is that the application layer does not contain domain logic, and all domain logic is lowered to the domain layer for implementation.

Gateway layer:

Gateway layer positioning is the egress gateway of the application, an adaptation layer for the interaction between the application and the external infrastructure, and handles all technical related implementations.

There are many ways to name this component. For example, some teams named it "rpc", and some teams named it "infrastructure". Different naming reflects the team's choice of the metaphor behind it. In the reference architecture of this article, the name gateway-Gateway was chosen. The reason for the decision is: the bounded context itself is highly cohesive, and its interaction with the outside requires a unified exit. The meaning of the gateway expressed by Gateway properly expresses this The concept of unified export. If the Facade layer is the northbound gateway of the application, the Gateway at this time expresses the southbound gateway of the bounded context.

3.3 Components and dependencies


From the macro layering, let's go deeper and look at the component division of each layer. As shown below:

Start component:

The startup entry of the entire application, loading application configuration information, and so on.

Common components

Provides the abstraction of domain model elements that are reused between different bounded contexts, such as the general abstraction of Command, Query, Event, Entity, ValueObject, etc. Of course, the general abstraction of the domain model does not have to be reused in the Common component. It can also be used as an independent bounded context and shared with other contexts by sharing the kernel, or it can also be implemented as an independent jar package component.

API components

The interface declaration component of the RPC type service, taking the JSF used inside the company as an example, this component is the component that applies the JSF API exposed to the external system. This component can be an independent project, of course, some teams will put it into the application project as a Module.

Unified Facade Component: Facade

The entrance of the external client to the application system is also the unified facade of the internal application service, similar to the adapter in the hexagonal architecture style. Based on different scenarios, the reference architecture is divided into several subpackages, such as provider (RPC service), task (scheduled task), listener (MQ monitoring), rest (http interface), etc. After the external request enters the system, the Facade component completes operations such as basic verification of input parameters, conversion of input parameters, service routing, and conversion of output parameters. At the same time, it can also undertake related capabilities such as processing login status, authentication, and logs.

Application Service Component: Application Service

Application services represent use cases and system behaviors. They complete the application logic processing of use cases by delegating to the domain layer and infrastructure layer (the Gateway component in the reference architecture). It can be understood that application services are clients of the domain layer. Typical responsibilities of this component:

  • Load domain objects from the storage layer, delegate domain objects to execute domain logic, and save domain objects
  • Notification of important events to the outside
  • Input and output parameters conversion and adaptation
  • transaction processing
  • Service calls for external non-domain logic

External API 

The logic of application services not only needs to coordinate the domain layer, but sometimes also needs to rely on external three-party services. The External API component is responsible for the interface declaration and definition of these external services, without specific implementation.

Application service components do not directly depend on the implementation of these external services, but on their interface abstractions. At the same time, the model definition here is based on the semantics of the bounded context, which is an adaptation to the external model.

This component does not depend on other components, and is only depended on by application service components and Gateway components. The gateway component relies on the interface declaration of the External API component and provides the underlying technology implementation, and the application service component relies on its interface, and injects the specific implementation through the IOC method to complete the service call.

Note that the services that this component depends on do not involve domain concepts, but are only used to support the orchestration of application services. If domain logic is involved, the interface definitions that depend on external services need to be lowered to the Domain layer.

Query

The Query component solves domain-related report query scenarios and exists as a component equivalent to the application service in the bounded context. The two components are responsible for business query and command logic respectively.

Although the Query component was introduced to provide support for report scenarios, the CQRS model was not fully introduced. In many materials, the probability of CQRS and DDD being mentioned at the same time is relatively high, because under DDD, we have solved the complex domain-oriented writing model, but in the reporting scenario, this rich domain model may not be the best choice . If both the read side and the write side are based on a unified domain model, it will generally lead to a compromise design of the domain model. In order to meet the requirements of the query side, the domain model has to introduce additional, domain-independent attributes, thus causing pollution of the domain model.

Domain

The Domain component is the core of the domain logic and is responsible for the realization of the domain logic of the entire system. It defines the abstraction of the domain model, domain services, domain events, and storage layer. This component does not depend on other components (except the common domain model abstraction component Common.

The reference architecture embodied in the above figure uses the classic modeling elements of DDD's tactical design, such as aggregation, entity, value object, storage, factory and domain event. In the actual implementation process, the abstraction of these design elements has certain challenges. The design process needs to go through continuous analysis, trade-offs and reconstruction to complete the modeling, which is where the core design lies.

Gateway

The gateway layer (in some architectures, it may become the infrastructure layer Infrastructure) is responsible for the realization of the entire technical correlation, and is the egress gateway of internal applications.

Technical dependency is the fundamental feature that distinguishes gateway components from other components. All details of technical implementation should be handled in this component, such as interaction with external services, middleware, DB, etc. At the same time, it cooperates with the interface abstraction of Domain components and External API components, and jointly undertakes the anti-corrosion layer function between the system and external dependencies (including external services and application-dependent middleware, DB and other infrastructure), and is responsible for internal models to external models. Transformation, external model to internal model conversion, and specific interactions. Based on the characteristics of the gateway component, it is also very suitable for unified external service data caching and downgrade fuse processing at this layer.

The gateway layer depends on the Domain, Application Service, External API and Query components, and is responsible for the implementation of the interfaces defined by the above four components. In the Gateway component, the implementation is isolated through subpackages:

  • query : query the implementation of the service component
  • external : External API components rely on the interface implementation of external services
  • repository : the implementation of the repository interface

4 Epilogue


The application architecture pattern is one of the important dimensions of the architecture. The structure is not just a simple package structure and naming, but a top-level abstraction that conveys a lot of practice and knowledge behind it. It is very important to develop an engineering reference architecture that is appropriate for the team and to achieve consensus among team members. Domain-driven design does not have a unified, general-purpose architecture, and it is impractical to try to define a standard architecture. The engineering architecture described in this article is just a reference. In practice, it should be different based on the specific situation of the team, but in principle, it should follow the core concept of separating the business domain from the technical domain.

Pay attention to the WeChat public account: System Engineering Laboratory, get more information

Guess you like

Origin blog.csdn.net/SystemEngineeringLab/article/details/129000573
ddd