Add navigation. For detailed ideas on how to design aggregations, please refer to this article.
In 2004, Eric Evans published Domain-Driven Design-Solving the Complexity of Software Core (Evans ·DDD for short). Domain-driven design is divided into two stages:
Taking a common language that can be understood by domain experts, designers and developers as a tool for mutual communication, domain concepts are discovered in the process of communication, and then these concepts are designed into domain models;
Software design is driven by domain model, which is realized by code;
Therefore, the core of domain-driven design is to establish a correct domain model.
Why is it important to build a domain model?
Domain-driven design tells us that it is very important and necessary to establish a domain model when implementing a business system through software, because the domain model has the following characteristics:
0000 1.? Domain model is an abstraction of a domain with certain boundaries, which reflects the essence of users' business needs in the domain. The domain model is bounded and only reflects the part we care about in the domain;
00002.? The domain model only reflects the business and has nothing to do with any technical implementation; The domain model can not only reflect some physical concepts in the domain, such as goods, books, application records, addresses, etc. It can also reflect some process concepts in this field, such as fund transfer.
00003.? The domain model ensures that the business logic of our software is in one model and in one place; This is very helpful to improve the maintainability, business understandability and reusability of software;
00004.? Domain model can help developers to transform domain knowledge into software construction relatively smoothly;
00005.? Domain model runs through the whole process of software analysis, design and development; Domain experts, designers and developers communicate through domain models and share knowledge and information with each other; Because everyone is facing the same model, it can prevent the requirements from being out of shape and make the software made by software designers and developers really meet the requirements;
00006.? It is not easy to establish a correct domain model, which requires the active communication and efforts of domain experts, designers and developers to deepen the understanding of the domain and refine and improve the domain model.
00007.? To make the domain model visible, we need to express it in some way; Graph is the most commonly used way to express domain model, but it is not the only way. Code or text descriptions can also express domain models.
00008.? Domain model is the core of the whole software and the most valuable and competitive part of the software. A well-designed domain model that meets business requirements can respond to changes in requirements more quickly;
Ubiquitous language (common language)
We realize that it is absolutely necessary for software experts and domain experts to cooperate to develop domain models, but this method is usually difficult because of some basic communication obstacles. Developers are full of classes, methods, algorithms, patterns, architectures and so on. And always want to correspond to the concepts and program artifacts in real life. They want to know which object classes to build and how to model the relationships between them. They will get used to thinking according to the concepts in object-oriented programming, such as encapsulation, inheritance and polymorphism, and they will talk like this anytime and anywhere, which is normal for them. Developers are developers. But domain experts usually don't know anything about this. They have no concept of software class library, framework, persistence or even database. They only know their unique domain expertise. For example, in the case of air traffic monitoring, domain experts know the plane, route, altitude, latitude and longitude, know that the plane deviates from the normal route, and know the launch of the plane. They discuss these things in their own terms, which is sometimes difficult for laymen to understand directly. If a person says something that others can't understand, or worse, misinterprets it into something else, what chance is there to ensure the success of the project?
In the process of communication, translation is needed to make others understand these concepts. Developers may try to analyze some design patterns in layman's language, but this is not always successful. Domain experts may also create a new jargon to try to express these ideas. In this painful communication process, this type of translation can not help the process of knowledge construction.
The perspective of thinking in domain modeling
"User needs" cannot be equated with "users", and capturing "models in users' minds" cannot be equated with "designing domain models with users as the core". There is a point in Laozi: If you think it's beneficial, you think it's useless. The advantage here is to establish a domain model; It's useless, just accommodating the needs of users. For example, a cup should be filled with a glass of water. When we make cups, we make empty cups, that is, we have to pour out the water before we can put it into the water. For another example, the house needs people. When we built the house, it was empty, and only when it was empty could people live. Therefore, when establishing the domain model, we should also put users outside the model, so as to accommodate the needs of users.
So, my understanding is:
0000 1.? When designing a domain model, we can't think about the problem from the user's point of view, and we can't always think about what users will do to the system. Instead, according to the needs of users, we should explore related things in the field from an objective point of view and think about the essential relationship and changing law of these things as the starting point of thinking.
00002.? Domain model is an objective world model that excludes people, but it contains the participant role played by people, but generally speaking, the participant role should not occupy a major position in the domain model. If the participant role played by people occupies the main position in the domain model, then the domain models of various systems will become difficult to distinguish, because the software system is a human-computer interaction system, and all activities are mainly recorded or tracked by people. For example, if the forum is dominated by people, then the domain model is: people post, people reply, people attach, and so on; Taking DDD as an example, if people are the center, it becomes: the shipper consigns the goods, the consignee receives the goods, the payer pays, and so on; So when we talk about the domain model, we have ruled out the human factor by default, because the domain is only meaningful to people, and people are outside the scope of the domain. If people are also included in the domain, it will be difficult for the domain model to remain objective. Domain model is an objective model, which has nothing to do with who uses it and how to use it. To sum up, domain modeling is to build a virtual model for our real people to use, rather than building a virtual space to imitate reality.
Classical hierarchy of domain-driven design
User interface/presentation layer
Responsible for presenting information to users and interpreting user commands. More specifically, it is:
0000 1.? Request the application layer to obtain the data that users need to show;
00002.? Sending a command to the application layer to request it to execute the user command;
application layer
A thin layer that defines all tasks to be completed by the software. Provide various application functions (including queries or commands) to the presentation layer externally, and call the domain layer (domain objects or domain services) internally to complete various business logics. The application layer does not contain business logics.
Domain layer
Be responsible for expressing business concepts, business status information and business rules. Domain model is at this level, which is the core of business software.
Infrastructure layer
This layer provides general technical capabilities for other layers; Provide inter-layer communication; Realize the persistence mechanism of domain layer; In short, the infrastructure layer can support the technical requirements of other layers through architecture and framework;
Patterns used in domain-driven design
Overview of all modes
Associated design
Association itself is not a pattern, but it is very important in the process of domain modeling, so it is necessary to discuss how to design associations between objects before discussing various patterns. I think the design of object association can follow the following principles:
0000 1.? The fewer associations, the better. Complex associations between objects are easy to form a relational network of objects, which is not conducive to our understanding and maintenance of a single object, and it is difficult to divide the boundaries between objects. In addition, reducing association at the same time helps to simplify the traversal between objects;
00002.? Many-to-many relationships may be natural in business. Usually we use a set to represent the many-to-many relationship of 1. However, we often need to consider performance issues, especially when there are many elements in the collection, and at this time we often need to obtain the associated collection information through a separate query;
00003.? Try to keep one-way association;
00004.? When establishing association, we need to dig deep into whether there are restrictions on association. If so, it is better to add this restriction to the association. Often such restrictions can simplify the association, that is, many-to-many can be simplified as 1 many, or 1 many can be simplified as 1 to1;
Entity; entity
Entity is a domain concept, which needs a unique identification in the domain. Because sometimes we need to distinguish which entity it is. There are two entities, if their unique identities are different, then even if all other attributes of the entities are the same, we think they are two different entities; Because an entity has a life cycle, it may persist in the database after it is created and then be taken out at some time. Therefore, if we don't define a unique identifier for an entity, then we can't judge whether it is this entity or which entity.
In addition, don't define too many attributes or behaviors for entities, but look for associations, find other entities or value objects, and pass attributes or behaviors to other associated entities or value objects. For example, the client entity has some address information. Because address information is a complete concept with business significance, we can define an address object and then pass the information related to the customer address to the address object. If there is no address object, but these address information is directly placed on the customer object, if other information with similar addresses is also directly placed on the customer, the customer object will be confused and unclear in structure, and it will be difficult to maintain and understand finally;
Value object (value object)
In the field, not everything must have a unique logo, that is, we don't care which object is what, but only what it is. Take the above address object as an example. If two customers have the same address information, we will assume that the addresses of these two customers are the same. In other words, as long as the address information is the same, we think it is the same address. Expressed programmatically, if all the attributes of two objects have the same value, we will think that they are the same object, then we can design this object as a value object. Therefore, the value object has no unique identification, which is the biggest difference between it and the entity.
In addition, the value object is judged by whether all its attributes are the same, and if they are the same, it is considered to be the same value object; When we distinguish whether it is the same entity, we only look at whether the unique identification of the entity is the same, regardless of whether the attributes of the entity are the same; Another obvious feature of value objects is invariance, that is, all properties are read-only. Because the attribute is read-only, * * * can be enjoyed with confidence; * * * When enjoying the value object, there are generally two methods: copying and * * * enjoying. The specific method depends on the actual situation; In addition, the design of the value object should be as simple as possible, and don't let it refer to many other objects, because it is just a value, just like int a = 3; Then "3" is a value in our traditional sense, and the value object can actually be understood as "3" here, which is also a value, but only represented by an object. So when we compare whether two value objects are equal in C# language, in order to compare the values of the objects, we will rewrite the methods of GetHashCode and Equals. Although the value object is read-only, it can be completely replaced. Just like you change the value of A to "4" (A = 4; ), directly replace the value of "3" with "4". The same is true for value objects. When you want to modify the reference of the customer's address object, it is not done by the customer. Address.Street, because the value object is read-only, is a complete and indivisible whole. We can do this: customers. Address = new address (…);
Application layer service
0000 1.? Get input (such as an XML request);
00002.? Send a message to the domain layer service, asking it to realize the call of business logic;
00003.? If the domain layer service is processed successfully, the basic layer service is called to send an email notification;
Domain layer service
0000 1.? Obtain a source account and a target account, and notify the source account and the target account to deduct and add money respectively;
00002.? Providing the returned result to the application layer;
Basic layer service
According to the request of the application layer, send an email notification;
So it can be clearly seen from the above example that the responsibilities of each service;
Polymerization and polymerization root (polymerization)
Aggregation, by defining the clear ownership and boundaries between objects, realizes the cohesion of domain models and avoids the formation of an intricate object relationship network that is difficult to maintain. Aggregation defines a group of related objects with cohesive relations, and we regard aggregation as a unit to modify data.
Aggregation has the following characteristics:
0000 1.? Every aggregation has a root and a boundary. A boundary defines an entity or value object in an aggregate. A root is an entity in an aggregate.
00002.? Objects in the aggregation can refer to each other, but if the aggregation outside wants to access the objects in the aggregation, it must start to navigate through the aggregation root. It is absolutely impossible to directly access the objects in the aggregation without bypassing the aggregation root, which means that the aggregation root is the only element that the outside can keep a reference to it.
00003.? The unique identifiers of entities other than the root in the aggregation are local identifiers, that is, as long as they remain unique in the aggregation, because they are always subordinate to the aggregation;
00004.? Aggregation root is responsible for handling other external objects and maintaining its own internal business rules;
00005.? Based on the above concept of aggregation, we can infer that the unit when querying from the database is also an aggregation unit, that is to say, we can't directly query non-root objects within an aggregation;
00006.? Objects in an aggregate can keep references to other aggregate roots;
00007.? When deleting an aggregate root, all related objects in the aggregate must be deleted at the same time, because they all belong to an aggregate and are a complete concept;
How to identify the aggregation root?
If an aggregate has only one entity, then this entity is the aggregate root; If there are multiple entities, then we can think about which object in the aggregate has the meaning of independent existence and can directly interact with the outside world.
factory
DDD factory is also a model that embodies the packaging concept. The reason why the factory pattern was introduced into DDD is that sometimes it is complicated to create a domain object, not just a simple new operation. Just like an object encapsulates its internal implementation (we can use its behavior without knowing its internal implementation), a factory is used to encapsulate the knowledge needed to create a complex object, especially aggregation, and its role is to hide the details of creating an object. The customer passes some simple parameters to the factory, and then the factory can create a complex domain object internally and return it to the customer.
Other elements in the domain model are not suitable for this, so we need to introduce this new model, the factory. When a factory creates a complex domain object, it usually knows what business rules to meet (it knows how to instantiate an object first, and then what initialization operation to do with it, which is the detail of creating the object). If the passed parameters meet the business rules for creating objects, the corresponding objects can be successfully created; However, if the expected object cannot be created due to invalid parameters and other reasons, an exception should be thrown to ensure that an incorrect object will not be created. Of course, we don't always need to create objects through factories. In fact, the creation of domain objects is not too complicated in most cases, and we only need to simply use constructors to create objects. The benefits of hiding the creation object are obvious, so that the business logic of the domain layer will not be leaked to the application layer, and the burden of the application layer can be reduced. It simply calls the domain factory to create the required objects.
Storage (repository)
0000 1.? The purpose of warehouse design is based on this reason: the objects in the domain model will not remain active in memory from the beginning of creation, but persist in the database when they are inactive, and then we will rebuild the objects when necessary; Rebuilding an object is a process of recreating an object according to its state stored in the database. Therefore, it can be seen that rebuilding an object is a process of processing a database. From a broader perspective, we often get one or some objects from a place similar to a collection, add objects to the collection or remove objects according to certain conditions. In other words, we need to provide a mechanism that can provide a collection-like interface to help us manage objects. Warehousing is designed based on this idea;
General steps of designing domain model
0000 1.? Establish a preliminary domain model according to the requirements, and determine some obvious domain concepts and their associations. Associations may have no direction for the time being, but these relationships are needed (1: 1, 1: n, m: n). You can accurately describe the meaning of each domain concept and its main information in words;
00002.? Analyze the main software application functions and determine the main application layer classes; This helps to find out early which are the responsibilities of the application layer and which are the responsibilities of the domain layer;
00003.? Further analyze the domain model to determine which are entities, which are value objects and which are domain services;
00004.? Analyze the correlation, through a deeper analysis of business and various software design principles and performance trade-offs, clarify the correlation direction or remove some unnecessary correlations;
00005.? It is very difficult to find the aggregation boundary and the aggregation root. Because you often encounter many ambiguous choice problems that are difficult to judge clearly in the process of analysis, it is necessary for us to accumulate some analysis experience in peacetime and find out the correct aggregation root;
00006.? Equip the aggregate root with a warehouse. Usually, warehouses are assigned to a summary. At this time, just design the interface of the warehouse.
00007.? Browse the scenario to ensure that the domain model we designed can effectively solve the business requirements;
00008.? Consider how to create domain entities or value objects, whether through factories or directly through constructors;
00009.? Stop and rebuild the model. Look for some problems or lame places in the model, such as thinking about whether some objects should be obtained through associative navigation or from the warehouse? Is the aggregation design correct? Consider the performance of the model, and so on;
Several realization methods of work unit
0000 1.? Snapshot-based implementation, that is, after the domain object is taken out, a backup object will be saved first, and then the state of the latest object will be compared with the state of the backup object during the persistent operation. If it's not the same, it's considered modified, and then it's persistent. The advantage of this design is that the object doesn't have to tell the work unit that its state has been modified, but the disadvantage is also obvious, that is, the performance may be low, and in the case of complex objects themselves, the process of backing up and comparing the state of the object is often a time-consuming step, and it is still difficult to truly realize the deep copy of the object and judge whether the attribute has been modified.
00002.? It is not based on snapshots, but when the relevant update or add or delete interface of the warehouse is called, the warehouse informs the work unit that an object has been added or updated or deleted. In this way, the work unit can also know which objects need to be persisted when doing data persistence; Theoretically, this method does not need the support of ORM framework, nor does it tilt the domain model, and it also supports the mode of work unit well. For friends who don't want to use the advanced ORM framework, this method is quite good;
For the query function that will not affect the state of domain objects in the domain layer
You can query the required data directly through the warehouse. However, the query function provided by the warehouse in the general domain layer may not meet the needs of interface display, and it may take many times to call different warehouses to obtain the data to be displayed; In fact, for this kind of query, I will talk about it later, and it can be directly implemented through the architecture of CQRS.
That is to say, for the query, we can directly complete the query through some other query engine implemented by another technical architecture, without calling anything in the domain layer at the application layer, such as constructing parameterized SQL, and directly query any data we want to display from one table or multiple tables in the database. This not only has high performance, but also reduces the burden on the domain layer. Domain model is not suitable for providing various query services for application layer, because the data to be displayed on the interface is often the combination information of many objects, which is a kind of non-object conceptual information, just like reports;
The essence of object-oriented is boundary division and encapsulation, which can not only quantify the change of demand and narrow the influence area; Because boundary division will also limit the scope of errors, OO is also beneficial to bugs and other errors in the later stage of software.
There will always be bugs in the software world, which can't be cleaned up, just as there will always be imperfections and dark sides in the human world. The crux of the problem is: God uses the boundary between space and time to limit the imperfections of the human world, such as suffering and disaster, to a range; In the software industry, if you don't use OO and other methods to draw a line, once something goes wrong, how bad will it be to trace it?
In fact, the software world is similar to the real world of human beings, and sometimes there are mistakes. We look at the reasons, which turned out to be two seemingly unrelated factors. The ancients should always pray to God and worship Buddha. When our software is running on the Internet, we programmers are probably praying to God and not making big mistakes. If our software is packaged in OO, we will be calm and will definitely make mistakes, but we have drawn the boundaries in advance, so there will be no serious consequences.
Four-color prototype analysis mode
Moment interval prototype
Represents activities that occur at a certain moment or within a certain period of time. In pink, abbreviated as MI.
Prototype of things in some places
It means the person or thing involved in the activity, and the place is the place where the activity takes place. It's in green. Short for PPT.
Descriptive prototype
Represents the essential description of PPT. Not the classification of PPT! Description is a set of immutable attributes abstracted from PPT. It is expressed in blue and abbreviated as DESC.
For example, there is a man named Zhang San. If aliens ask you what Zhang San is? What would you say? It may be said that Zhang San is a person, and aliens don't know what a "person" is. So what would you do? You will say: Zhang San is an objective existence composed of a head, two hands, two feet and a body. Although aliens don't know what people are at this time, I can already use this example to explain what "description" is. In this example, Zhang San is a PPT, "an objective existence consisting of a head, two hands, two feet and a body" is a description of Zhang San, and the head, hands, feet and body are a collection of unchangeable attributes of human nature. However, we humans are smart and good at abstract generalization and naming. We changed this description to a word, which is "people". So there is a saying that Zhang San is a person.
Role prototype
Role is what we usually understand as "identity". Use yellow, abbreviated as Role. Why is there the concept of role? Because of some activities, only PPT (participants) with specific roles (identities) can participate in this activity. For example, a person can only go to class (an activity) if he has the role of a teacher; A person can only participate in and be elected as a legal citizen; But some activities don't need a role, for example, a person can sleep without any role (an activity). Of course, it is also wrong to say that people can sleep without a role. What's the matter? Because we can understand that an objective existence can sleep as long as it has the role of "human". In fact, at this time, we have regarded DESC as a role. Therefore, in fact, the concept of role is very broad, which is beyond the narrow sense of "identity" that we usually understand, because "teacher", "legal citizen" and "person" can all be regarded as roles. Therefore, it should be said that any activity requires the participation of participants with certain roles.
To sum up the four-color prototype in one sentence is: what kind of people, organizations or objects participate in an activity in a certain role at a certain moment or time. Among them, "what" is DESC, "person or organization or object" is PPT, "role" is role, and "an activity at a certain moment or time" is MI.
If you study these things after learning DDD, you will have a deeper understanding of DDD, but I think DDD is relatively basic. It will be more effective and easier to master to study these things on the basis of knowing DDD.