Domain Driven Design in progress

Original address: https://blog.csdn.net/chenlushun12/article/details/80070698

Design of microservice software, including service division, Restful API design, etc. The tricky part is the division of responsibilities of the Service: how to abstract the Model with a unified business scope to make it modular, and how to highly refine and combine multiple modules so that the business can be serviced independently.

What is DDD

Software development is not something that can be accomplished overnight. It is impossible for us to develop software without understanding the product (or industry field). Before development, we usually need to sort out a lot of business knowledge, and then we reach the level of software design, and finally we develop it. . In the process of sorting out business knowledge, we will inevitably form a certain domain knowledge, and to drive software design step by step according to the domain knowledge is the basic concept of domain-driven design.

It sounds like this is no different from software development in the traditional sense, but it's just a new term, but it's not.

Software development VS DDD 
General software design or software development is divided into two types: waterfall and agile.

The former is generally that after a large amount of business analysis, the project manager will sort out a basic model based on the existing requirements, and then pass the result to the developer. This is the developer's requirements document, and they only need to develop it accordingly. In this mode, it is difficult to get feedback from users frequently. Therefore, the business model is correct by default in the early analysis, so the result can be imagined. When it is delivered in a few months or even years, it will inevitably be There is a big gap with the expectations of customers.

The latter has been improved on this basis. It also requires a lot of analysis, and the scope will be designed to more refined business modules. It is iterative in small steps and delivered periodically, so the feedback from customers will be more frequent and timely. However, agile cannot take all aspects of the business into account, and agile embraces changes. A large number of requirements or business model changes will inevitably bring a lot of maintenance costs. At the same time, the requirements for people (Developer) will inevitably be higher.

DDD is different: it is like a smaller-grained iterative design, and its smallest unit is the domain model. The so-called domain model is a carrier that can accurately reflect a certain knowledge element in the field. Domain experts need frequent communication to translate expertise into domain models. The domain model has nothing to do with technology and has a high degree of business abstraction. It can accurately describe the knowledge system in the domain; at the same time, it is also independent. We also need to learn how to make it expressive, so that models can establish relationships with each other to form a complete domain architecture. Usually we can use pictograms or a common language (Ubiquitous Language) to describe the relationship between them. On top of this, we can carry out Domain Code Design in the field. If software design is like building a house, then domain code design is like putting up wallpaper. The former has already planned the blueprint of the house, while the latter is only a small part of the design: if the wallpaper is wrong, we can start over, but if the structure of the house is wrong, it will be a tragedy.

Building Domain Model (Build Domain Model) 
said so many concepts of domain model, what exactly is a domain model? Take the flight of an airplane as an example:

Now it is necessary to develop a monitoring software for the airline that can provide navigation for the aircraft and ensure that there is no route conflict. So where should we start? According to the idea of ​​DDD, our first step is to establish domain knowledge: as the staff who manage and maintain the airport flight order, they are naturally experts in this field. Our first goal is to communicate with them. Maybe we can't Get all the knowledge you want from it, but at least filter out the main content and elements. You may hear domain terms such as takeoff, landing, flight conflict, delay, etc. Let's start with a simple example (even if it's wrong):

The starting point->airplane->end point 
model is very straightforward, but a bit too simple, because we can't see what the plane does in the air, and we can't know how the plane gets from the starting point to the ending point. Just now we seem to have mentioned that there is no route conflict, Then it seems better like this:

Airplane -> Route -> Start/End 
Since points constitute a line, why not:

The process of plane -> route -> points (including starting point and ending point) 
is a process in which we continuously build domain knowledge. The key point is to find domain experts for frequent communication and to extract necessary domain elements.

Although it still looks simple, we have started to build the domain object and domain model step by step.

The above example of Ubiquitous Language 
does seem simple, but the process is not easy: there are natural barriers in the process of communication between us (developers) and domain experts: we are full of classes, methods, design patterns, Algorithms, inheritance, encapsulation, polymorphism, how to object-oriented, etc.; experts in these fields do not understand, they only know professional terms such as aircraft faults, latitude and longitude, and flight routes.

Therefore, when building domain knowledge, we (developers and domain experts) must exchange knowledge. The scope of knowledge involves various elements of the domain model. If one party's description of the model confuses the other party, it should immediately change to another Describe the way until both parties can accept and understand it. In this process, a common language needs to be established as a communication bridge between developers and domain experts.

How can such a universal language be formed? In fact, the answer is not unique, and there is no standard answer to be exact.

a) UML 
UML can clearly represent classes and show the relationship between them. However, once the aggregation relationship is complex, the UML leaf nodes will become very large and may not be so intuitive and easy to understand. Most importantly, it cannot precisely describe the behavior of the class. In order to make up for this deficiency, it is possible to add necessary instructions (which can be labels or documents) for specific behavior parts, but this is often time-consuming and inconvenient to update and maintain. 
b) Pseudo-code 
extreme programming is recommended to do this. This method is good for programmers, but it is necessary to map the existing model to the code level immediately, which is not very demanding for people and is not easy to implement.

Model-driven design (Model-Driven Design) 
model diagram (Model-Driven Design) 
The model diagram in the domain-driven design is as follows:

Layered Architecture

The User Interface 
is responsible for presenting information to users and parses user behavior, which is often referred to as the presentation layer.

Application Layer 
The application layer does not have any business logic code, it is very simple, it mainly provides task processing for the program.

Domain Layer 
This layer contains information about the domain and is the core of the business. The state of the domain model is directly or indirectly (persisted to the database) stored in this layer.

Infrastructure Layer 
provides underlying dependent operations for other layers.

The division of the layer structure is necessary. Only with a clear structure, the final domain design should be used. For example, if a user wants to book a flight, he initiates a request to the service of the Application Layer, and then the Domain Layerer obtains the domain object from the Infrastructure Layer and checks it. After passing, the user state will be updated, and finally persisted to the database through the Infratructure Layer again.

Entity (Entity) & Value Object (Value Object) 
The entity is similar to the concept in object-oriented, and it is mentioned here again because it is the basic element of the domain model. In the domain model, entities should have unique identifiers. Entities should be considered from the beginning of the design. It is also very important to decide whether to create an entity.

The value object is different from the variable of numerical type in programming. It is just an entity without a unique identifier. For example, if the information of two harvest addresses is exactly the same, then it is a value object, not an entity. Value objects can be shared in the domain model, they should be "immutable" (read-only), and when the value object is needed elsewhere, a copy of it can be passed as a parameter.

Services (Services) 
When we analyze a certain field, we have been trying to convert information into domain models, but not all points can be covered by Model. Objects should have properties, states and behaviors, but sometimes there are some behaviors in the domain that cannot be mapped to specific objects, and we can't force them into a model object, but there is no such thing as a method alone. places where service is needed.

Services are stateless, objects are stateful. The so-called state is the basic attribute of the object: tall, short, fat, thin, young and beautiful. The service itself is also an object, but it has no properties (only behavior) and is therefore stateless.

PS: This is two concepts from the state of the server that we often say. A stateless server means that every HTTP request received by the server is like the first time the client sends it; while the stateful server The server will store the state of the client, the common one is Cookie&Session

Services exist to provide simple methods for the domain. In order to provide a large number of convenient methods, it is natural to associate many domain models, so the behavior (Action) should exist in the service by nature.

The service has the following characteristics:

a) The behavior embodied in the service must not belong to any entity and value object, but it belongs to the scope of the domain model 
b) The behavior of the service must be designed with multiple other objects 
c) The operation of the service is stateless

PS: Do not place the service arbitrarily. If the behavior belongs to the application layer, it should be placed there; if it serves the domain model, it should be stored in the domain layer. To avoid business services directly operating the database, most Good pass DAO.

Modules 
For a complex application, the domain model will become larger and larger, so that it is difficult to describe and understand, let alone the relationship between the models. The emergence of modules is to organize a unified model concept to achieve the purpose of reducing complexity. Another reason is that modules can improve code quality and maintainability. For example, we often say high cohesion and low coupling are to advocate the cohesion of related classes to achieve modularization.

A module should have an external unified interface for other modules to call. For example, if there are three objects in module a, then module b should not directly operate these three objects, but operate the exposed interface. The naming of modules is also very particular, and it is best to reflect the domain model in depth.

Aggregates Aggregates 
are viewed as a combination of multiple model units that define the relationships and boundaries of the model. Every aggregate has a root, which is an entity and is uniquely accessible from outside. As such, aggregates can guarantee invariance across multiple model units because other models refer to the root of the aggregate. So if you want to change other objects, you can only operate through the root of the aggregate. If the root is gone, the other objects in the aggregate will also not exist. 
A simple example is as follows:

customer is the root of the aggregation, and the others are internal objects. If the user address is needed externally, just copy a copy and pass it out. Obviously, if the user does not exist, no other information is meaningful.

Factories 
In large systems, entities and aggregates are often complex, which makes it difficult to create objects through constructors. The factory solves this problem, it encapsulates the details of creating objects, and cleverly implements dependency inversion. Of course it also works for aggregates (other objects can be created automatically when the aggregate root is established). The factory was first known to everyone in the design mode. Indeed, the factory mentioned here is also this concept.

But don't blindly apply factories, the following scenarios do not require factories: 
a) the constructor is very simple 
b) the construction of the object does not depend on the creation of other objects 
c) can be solved by using the strategy pattern

Repository 
The repository encapsulates the logic of acquiring objects. Domain objects do not need to interact with the underlying database, it only needs to acquire objects from the repository. Repositories can store references to objects, when an object is created, it may be stored in the repository, and then it can be retrieved from the repository next time. If the data requested by the user is not in the warehouse, it will be fetched from the database, which reduces the number of low-level interactions. Of course, the warehouse also has a strategy for acquiring objects, as follows:

PS: The warehouse looks like something like Infrastructure Layer, but it is not. The warehouse is more like a local cache, and the database is accessed only when needed.

Conclusion 
CQRS itself is an architectural pattern, but more of it is applied in DDD. Because there are factories and warehouses in DDD to manage the domain model, the former is mainly used for creation, while the latter is used for storage. This shows that reading and writing are separated by default in DDD, and DDD seems to have a seamless link with CQRS by nature.

CQRS often requires the database to be separated from reading and writing. Specifically, all update operations have no return value (void), and only the read operation returns the corresponding value. When implementing CQRS, it is combined with the event source (Event Source), and the following is a simple interaction process:

The client initiates a request, and the server maps it to a command, which reads a related aggregate from the warehouse, operates on the aggregate, and generates an event source, sends the event, and the receiver receives it. After the message arrives (not immediately), the domain object will be updated to complete an update operation.

On this basis, there is an architectural style called hexagon, which wraps the domain model of DDD, and contains a variety of adapters to adapt to various communication methods. Generally speaking, I think whether it is DDD, CQRS or hexagons are both an architectural design idea. There is no absolute advantage, and they also have their own complexity. It is not easy to understand, but sometimes when designing software, you may wish to learn more about the small details and ideas. There must be something to gain.

As for whether it can be applied? How to apply? , The author can only say that you can't just copy it, you need to have a certain practical experience to try it. In general, combined with the characteristics of the project, you can appropriately and flexibly adopt the design ideas.

Domain Object Lifecycle

repository

factory

interface design

When designing the method signature of a factory, whether it is an independent factory or a factory method, you must follow the following 2 points

  • Every operation must be atomic
  • factory will be coupled to its parameters

The repository helps manage the middle and end of the lifecycle and the 
factory handles the beginning of the object lifecycle


Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325895577&siteId=291194637