Three modes of DDD layered architecture

Source: Internet
Author: User
Tags in domain
This is a creation in Article, where the information may have evolved or changed.

Introduction

Before discussing the pattern of the DDD layered architecture, let's review the knowledge of DDD and hierarchical architectures together.

Ddd

DDD (Domain driven design, domain driven) is a software development approach that helps us to design high-quality software models. With the right implementation, the design that we do with DDD is exactly how the software works.
UL (Ubiquitous Language, General language) is a team-shared language and one of the most powerful features of DDD. No matter what your role in the team, as long as you are a member of the team, you will use UL. Because of the importance of UL, so that each concept needs to be clear and unambiguous in their respective contexts, DDD has proposed a model BC (bounded context, gauge contexts) in strategic design. Both UL and BC form the two pillars of DDD, and they complement each other, that is, UL has its own contextual meaning, and every concept in the BC has a unique meaning.
A business area is divided into several BC, which are integrated through a context map. The BC is an explicit boundary, and the domain model exists within that boundary. A domain model is a software model for a specific business domain. Typically, domain models are implemented through the object model, which contains both data and behavior, and conveys accurate business meaning.
Broadly speaking, the domain is what an organization does and what it contains, representing the entire business system. Since the domain model contains the word "domain", we might think that a single, cohesive, and full-featured model should be created for the entire business system. However, this is not our goal of using DDD. On the contrary, the domain model exists within the BC.

In the practice of microservices architecture, the concepts and techniques in DDD are widely used:

    1. The micro-service should first build UL, and then discuss the domain model.
    2. A micro-service should not exceed one BC, otherwise there will be ambiguous domain concepts in the microservices.
    3. A microservices minimum is not less than one aggregation, otherwise it introduces the complexity of distributed transactions.
    4. The division of MicroServices is similar to the BC partitioning process, and each microservices has a domain model.
    5. The integration of microservices can be done through the context map, such as ACLs (anticorruption layer, anti-corrosion layers).
    6. MicroServices are best served by domain event (domain events) to allow microservices to remain loosely coupled.
    7. ...

Layered architecture

An important principle of layered architecture is that each layer can only be coupled to the layer below it. Layered architectures can be easily divided into two categories: strict hierarchical architecture and loose wind layer architecture. In a strictly layered architecture , a layer can only be coupled with the layer directly below it, while the loose wind layer architecture allows a layer to be coupled to any of its lower layers.

The benefits of a layered architecture are obvious. First of all, due to the loose coupling between layers, we can focus on the design of this layer, without having to worry about the design of other layers, and not worrying about the impact of our design on other layers, which is very helpful for improving software quality. Secondly, the layered architecture makes the program structure clear, upgrade and maintenance are very easy, change the specific implementation code of a layer, as long as the interface of the layer remains stable, the other layers can not be modified. Even if the interface of this layer changes, it only affects the adjacent upper layer, the modification work is small and the error can be controlled, without unexpected risk.
To maintain the advantages of layered architecture, it is necessary to adhere to the loosely coupled relationship between layers. When designing a program, you should first divide the possible hierarchies, and the interfaces that are provided by this hierarchy and the interfaces that are required. When designing a layer, you should try to maintain isolation between layers, using only the interfaces provided below.
With regard to the benefits of layered architecture, Martin Fowler the answer in the book Patterns of Enterprise application Architecture:

    1. Developers can focus on only one layer of the entire structure.
    2. It is easy to replace the implementation of the original level with the new implementation.
    3. You can reduce the dependency between layers.
    4. Conducive to standardization.
    5. Facilitates the reuse of all layers of logic.

"Gold is no can't pure, nobody is perfect," the layered architecture inevitably has some drawbacks:

    1. Reduces the performance of the system. This is obvious because the middle tier is added, but can be improved by caching mechanisms.
    2. may result in cascading modifications. This kind of modification is especially in the top-down direction, but can be improved by relying on the result.

In order to highlight the domain model in each BC, the hierarchical schema pattern is presented in DDD. In recent years, the author in the practice of ddd, but also often use the layered architecture model, this article mainly share the DDD hierarchical architecture of the more classic three models.

Mode 1:4-tier architecture

Eric Evans presents a traditional four-tier architecture pattern in the "Domain driven design-software core complexity response" book, as shown in:


Ddd-l4.png
    1. User interface is the UI layer (or presentation layer) that is responsible for displaying information to the user and interpreting user commands. can refer to a user can be another computer system, not necessarily the user interface of the person.
    2. Application is the application layer that defines the tasks the software needs to accomplish and directs the objects that express the domain concept to solve the problem. This level of responsibility is significant for the business and an essential channel for interacting with the application layers of other systems. The application layer is as simple as possible, does not contain business rules or knowledge, but only coordinates the tasks for the domain objects in the next layer, assigns the work, and makes them collaborate with each other. It does not reflect the state of the business situation, but it can have a different state to show the progress of a task for the user or program.
    3. Domain is the domain layer (or model layer) that is responsible for expressing business concepts, business status information, and business rules. Although the technical details of preserving the business state are implemented by the infrastructure layer, the state that reflects the business situation is controlled and used by this layer. The domain layer is the core of the business software and the domain model is located at this level.
    4. The infrastructure layer is the base implementation layer, providing common technical capabilities to other tiers: delivering messages to the application layer, providing persistence mechanisms for the domain layer, drawing screen components for the user interface layer, and so on. The infrastructure layer is also able to support four levels of interaction patterns through an architectural framework.

The traditional four-tier architecture is a bounded, loosely layered architecture that can be accessed at any upper level of the infrastructure layer (the "L" type), while the other layers adhere to a strict hierarchy

In the practice of the four-tier architecture model, the localization definition of layered is mainly:

    1. User interface layer is mainly RESTful message processing, configuration file parsing, and so on.
    2. Application layer is mainly multi-process management and scheduling, multi-threaded management and scheduling, multi-scheduling and state machine management, and so on.
    3. Domain layer is mainly the implementation of domain models, including the establishment of domain objects, the life cycle management and relationships of these objects, the definition of Domain Services, the release of domain events, and so on.
    4. Infrastructure layer is mainly business platform, programming framework, third-party library encapsulation, basic algorithm, and so on.

Mode 2:6-tier architecture

In 2009, James O. Coplien and Trygve Reenskaug published a paper "DCI Architecture: A new vision for object-oriented programming", marking the birth of the DCI architecture model. Interestingly, James O Coplien is also the creator of the MVC architecture model, a man who has done two things in his life: creating MVC when he was young, creating a DCI when he was old, and thinking about it all the time, so my generation.
Object-oriented programming is intended to unify the perspective of programmers and users in computer code: it is a blessing to improve usability and reduce the difficulty of understanding programs. But while the object is a good reflection of the structure, but fails to reflect the system's actions, DCI's vision is to reflect the roles in the end user's cognitive model and the interactions between the roles.

Traditionally, object-oriented programming languages have not been able to capture the collaboration between objects, reflecting the algorithms in collaboration. Just as an instance of an object reflects a domain structure, the collaboration and interaction of objects is also structured. Collaboration and interaction are also part of the end-user mental model, but you can't find a cohesive representation in your code to represent them. In essence, the role embodies a generalized, abstract algorithm. The character is not flesh and blood, does not do the actual thing, the final work still falls on the object's head, but the object itself also bears the responsibility which manifests the domain model.
There are two different models of the unified whole of "object", that is, what the system is and what the system does, which is the fundamental problem that DCI should solve. The user acknowledges the objects and the fields they represent, and each object must implement some behavior in accordance with the user's idea of an interaction model, which is linked to other objects by its role in the use case. Because the end user can combine the two perspectives, the object of the class can perform the member functions of the class in addition to the member functions of the owning classes, as if those functions belong to the object itself. In other words, we want to inject the logic of the character into the object, making it part of the object, and its position is not as weak as the method obtained from the class when the object is initialized. At compile time, we have arranged all the logic that we might need to play a role in the object. If we were a little bit smarter, we would know the assigned role at runtime, and then inject exactly the logic we needed to do it.

Algorithm and role-object mappings are owned by the context. The Context "knows" which object should be found in the current use case to act as the actual actor, and then is responsible for "cast" the object into the scene of the corresponding role (cast in the drama is the meaning of the word, the word here is at least in line with the meaning, the other is the intention is to associate the cast Meaning in some programming language type systems). In a typical implementation, each use case has its corresponding context object, and each role involved in the use case has an identifier in the corresponding context. What the Context does is to bind the role identifiers together with the correct objects. Then we just trigger the "opening" character in the context and the code will run.

So we have the complete DCI architecture (Data, context, and interactive three-tier architecture):

    1. The data layer describes what domain concepts and relationships are in the system, which focuses on the establishment of domain objects and the life cycle management and relationships of these objects, allowing programmers to think about the system in terms of the object, so that "what is the system" is easier to understand.
    2. Context layer: A layer that is as thin as possible. The context is often implemented in a stateless way, just to find the right role and have the role interact to complete the business logic. But simplicity does not mean that it is not important, the context layer is to understand the software business process to provide a point of entry and the main line.
    3. The interactive layer is mainly embodied in the modeling of role, role is the real performer of complex business logic in each context, and embodies "what the system does". What role does is to model the behavior, which joins the context and domain objects. Because the behavior of the system is complex and changeable, role makes the system separate the stable domain model layer and the changeable system behavior layer, and the role focuses on modeling the system behavior. This layer tends to focus on the scalability of the system, more close to the software engineering practice, in the object-oriented more in the view of class to think design.

DCI is now widely seen as a development and complement to DDD, and is used in object-oriented domain modeling. By explicitly modeling role, it solves the problem of congestion model and anemia model in object-oriented modeling. DCI models the behavior by explicitly using role, while allowing role to bind (cast) to the corresponding domain object in the context, which solves the problem of inconsistent data boundary and behavior boundary, and solves the problem of high cohesion and low coupling of data and behavior in domain objects.

One tricky problem facing object-oriented modeling is that data boundaries and behavior boundaries are often inconsistent. Following the modular idea, we encapsulate the behavior and its tightly coupled data through the class. However, in a complex business scenario, behavior often spans multiple domain objects, and such behavior, if placed in an object, inevitably causes other objects to leak their internal state to the object. As a result of object-oriented development, there are two competing factions in domain modeling, one that tends to model behavior across multiple domain objects in a domain service. If this practice is overused, it causes the domain object to become a dummy object that provides only a bunch of get methods, which is called the anemia model. The other faction firmly believes that the method should belong to the domain object, so all business behaviors are still placed in the domain object, which causes the domain objects to become god classes as the supported business scenarios become more numerous, and the level of abstraction of the internal methods of the class is difficult to agree with. In addition, because the behavior boundary is difficult to be appropriate, the data access relationship between the objects is more complex, and this modeling result is called the congestion model.

For a multi-role object, give an example of life:

People have multiple roles, and different roles perform different duties:

  1. As parents: We want to tell stories to children, play games with them, and coax them to sleep.
  2. As children: we should honor our parents and listen to their life advice.
  3. As a subordinate: we must obey the supervisor's work arrangement and finish the task with high quality.
  4. As the boss: we need to arrange subordinates ' work and develop and motivate them.
  5. ...

Here people (large objects) aggregate multiple roles (small classes), in which a person can only play a specific role in a scenario:

  1. In front of the children, we are parents.
  2. In front of our parents, we are children.
  3. In front of the boss, we are subordinate.
  4. In front of our subordinates, we are the boss.
  5. ...

After the introduction of DCI, the domain layer in the DDD four-tier architecture pattern became thinner, previously the domain layer corresponded to the three layers in the DCI, and now:

    1. The domain layer retains only the data and interaction layers in the DCI, which we typically use in practice to isolate layers of data and interaction by using two directory object and role.

Object-role-dir.png
    1. The context layer in the DCI moves from the domain layer to the context layer.
    2. The context layer divides into two layers in the system of the message interaction more, namely the context layer and the big context layer. The context layer processing Unit is the action, corresponding to a synchronous message or asynchronous message. The big context layer corresponds to a transaction processing, consisting of an action sequence, generally implemented by the transaction DSL, so we are accustomed to calling the big context layer the transaction DSL layer.

After applying DCI in the DDD tiered architecture mode, the application layer often does some scheduling-related work, so we used the more appropriate name "Scheduler" in the DDD six-tier architecture pattern, as shown in:


Ddd-l6.png

In practice, the six-tier localization is defined as:

    1. User interface is the interface layer, which is mainly used to handle the restful requests sent by the user and to analyze the user input profile, etc., and pass the information to the interface of the scheduler layer.
    2. Scheduler is a scheduling layer, responsible for multi-process management and scheduling, multi-threaded management and scheduling, multi-scheduling and maintenance of business instances of the state model. When the dispatch layer receives a request from the user interface layer, the delegate transaction the DSL layer to handle the transaction related to this operation.
    3. Transaction DSL is a transaction layer that corresponds to a business process, such as UE Attach, that combines the processing sequences of multiple synchronous messages or asynchronous messages into a single transaction, and in most scenarios there is a selection structure. If the transaction fails to execute, it is rolled back immediately. When the transaction layer receives a request from the dispatch layer, the action of the context layer is delegated, often accompanied by the specification (predicate) of the context layer, which is used to select actions.
    4. The context is the environment layer, which, in action, processes a synchronous message or asynchronous message, casts the domain object of the domain layer into the appropriate role, and the role interacts to complete the business logic. The environment layer also usually includes the implementation of the specification, that is, through the domain layer of knowledge to complete a conditional judgment.
    5. The domain layer is the domain layer, which defines the domain model, including not only the modeling of domain objects and their relationships, but also the explicit modeling of role roles of objects.
    6. The infrastructure layer is the base implementation layer that provides common technical capabilities for other tiers: the business platform, the programming framework, the delivery of restful messages, the framework of the things model, the persistence mechanism of domain objects, the release of domain events, the encapsulation of third-party libraries, the general algorithm, and so on.

The core of the transaction layer is the transaction model, and the framework code of the transaction model is generally placed in the infrastructure layer. On the transaction model, I have previously shared an article-"Golang transaction model", interested students can see.

The DDD six-tier architecture, like the traditional four-tier architecture, is a bounded, loosely layered architecture .

Pattern Three: Hexagon architecture

There is a way to improve the layered architecture, that is, the dependency lead principle (Dependency inversion Principle, DIP), which improves by changing the dependencies between different layers.

The principle of reliance led by Robert C. Martin, formally defined as:
High-level modules should not be dependent on the underlying modules, both should be dependent on abstraction.
Abstractions should not be dependent on detail, and detail should be dependent on abstraction.

According to this definition, low-level components in the DDD hierarchy should rely on the interfaces provided by the upper-tier components, that is, whether the upper or lower layers are dependent on abstraction, and the entire layered architecture seems to be flattened. If we flatten the layered architecture and add some symmetry to it, there will be an architectural style with symmetrical features, the hexagon architecture. The hexagon architecture was proposed by Alistair Cockburn in 2005, in which different clients interact with the system in an "equal" manner. Need a new customer? Not a problem. Just add a new adapter to convert the customer input into a parameter that can be understood by the system API. At the same time, for each specific output, there is a new adapter responsible for completing the corresponding conversion function.

The hexagon schema is also known as ports and adapters, as shown in:


Ddd-hex.png

Hexagon each different edge represents a different type of port, which either processes the input or processes the output. For each external type, there is an adapter corresponding to the outside world through the application Layer API and internal interaction. 3 Customer requests arrived at the same input port (adapters A, B, and C) and another customer requested adapter d. Assuming that the first 3 requests use the HTTP protocol (browser, rest, soap, etc.), the next request uses the AMQP protocol (such as RABBITMQ). The port does not have a clear definition, it is a very flexible concept. Regardless of the way the port is divided, when a customer request arrives, there should be a corresponding adapter to convert the input, and then the port will invoke an action on the application or send an event to the application, and control is given to the internal zone.
The application receives the customer request through the public API and uses the domain model to process the request. We can consider the implementation of the modeling element repository of the DDD Tactical design as a persistent adapter that accesses a previously stored aggregate instance or saves a new aggregate instance. The center of the adapter E, F and G shows that we can implement the resource pool in different ways, such as relational database, document-based storage, distributed cache, or memory storage. If the application sends domain event messages to the outside world, we will use adapter h for processing. The adapter handles message output, and the above-mentioned adapters that process AMQP messages handle message input, so different ports should be used.

In the actual project development, the components of different layers can be developed at the same time. When the functionality of a component is clear, development can be started immediately. Because there are multiple users of the component, and the focus of these users is different, you need to provide several different interfaces. At the same time, the understanding of these users is also constantly in-depth, it is possible to refactor the relevant interfaces multiple times. As a result, multiple users of a component often look for component developers to discuss these issues, virtually reducing component development efficiency.
In a different way, component developers are focused on functional development after defining the functionality of the component, ensuring that the functionality is stable and efficient. The user of the component defines the interface (port) of the component itself, then writes the test based on the interface and evolves the interface. In cross-layer integration testing, it is up to the component developer or user to develop an adapter.

Evolution of the hexagon schema pattern

Although the hexagon architecture pattern is already good, there is no best only better, evolution has no end. In the years following the hexagon schema pattern, three variants of the hexagon schema pattern were derived in turn, and interested readers could learn by clicking on the link themselves:

    1. Jeffrey Palermo introduced the Onion architecture in 2008, and the hexagon architecture is a superset of the onion architecture.
    2. Robert C. Martin introduced a clean Architecture (Architecture) in 2012, a variant of the hexagon architecture.
    3. Russ Miles presented the life preserver design in 2013, a hexagonal architecture based design.

Summary

This article reviews the knowledge of DDD and hierarchical architecture together with the reader, then elaborates the three modes (four-tier architecture, six-tier architecture and hexagon architecture) commonly used in the DDD hierarchical architecture, and gives readers a deep understanding of the DDD layered architecture pattern. To deliver well-structured and maintainable software products by choosing the most appropriate DDD tiered architecture pattern in the development practice of microservices, depending on the situation.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.