Reprint CQRS (Command query separation of duties) and EDA (event-driven architecture)
Previous: "IDDD realization Domain driven design-soa, REST and hexagon Architecture"
Read the catalogue:
cqrs-Command query separation of duties
Eda-Event-Driven architecture
Domin event-Field Events
Long-running process (Saga)-long-time processing
Event sourcing-Events Traceability
CQRS journey-Microsoft Sample Project
Enode-netfocus Practical Projects
The existence is the reason, each kind of architecture produces has a specific scene, or solves one kind of practical application question, the accumulation of experience has contributed to the generation of one kind of architecture.
1. cqrs-command query separation of duties
Description: This figure is from MSDN
CQRS (Command & query Responsibility segregation) command query separation of duties, and REST belong to the architectural style, if the simple understanding of CQRS, is relatively easy, another way to explain is that, A method is either a command to perform some action, or a query that returns data, the command is a modification of the state of the system, and the query does not, the separation of responsibilities is more conducive to the refinement of the domain model, the flexibility and scalability of the system are further enhanced.
Why do you want to separate command and query responsibilities?
- Design dilemma: A hint from Repository, Domain Model re-design
- Repository warehousing, where exactly is your destination? (a)-concept of warehousing
- Repository warehousing, where exactly is your destination? (b)-Can you accept this application layer code?
- Repository warehousing, where exactly is your destination? (c)-select ...
If you have time, you can read the above several posts and related comments first.
We all know that Repository's job is to manage aggregate root (Aggregate) objects, typically one by one correspondence, and the business logic in the domain layer to operate on an aggregate root object, which must pass through Repository, while the application layer accepts user requests for data object display, It is also necessary to convert the aggregate root object through Repository, which generally does not involve domain business operations, but simply obtains aggregated root object data. The business logic in the domain layer requires Repository to implement the management of the aggregated root state, so we typically define ADD, Update, GetById, and so on in the domain layer IRepository interface, and then implement Repository in the infrastructure layer. And the requirements from the application layer, need to get aggregate root object data, so in Repository also need to add some GetList, but according to IRepository interface contract, the returned type must be the aggregate root, in this scenario, do not need to get the aggregate root object, Just get the data (DTO) on it ...
I outline a series of questions that appear in the above description:
- Repository duties became erratic.
- IRepository will be contaminated, and the result is that the domain layer will also be contaminated.
- Repository will present a concept of dtos that should not have occurred.
- Repository will be swallowed by a lot of GetList operations.
- Repository will eventually become "people not like people, ghosts not like ghosts."
If you take these questions to understand CQRS, there will be such a feeling: "God, this is a god sent a savior Ah!" ”。
Back to the beginning of the picture, it seems to feel very simple, the request from the user UI is divided into query (query) and command (commands), these request operations are received by the service Interfaces (services interface, just a collectively known), and then distributed processing, The update data store is updated for the command operation, because the read and write separation, and in order to maintain the consistency of the data, we also need to apply the update to the "read data store." For the general application system, the query will be a large proportion, because the read and write separation, so we can further performance optimization for the query, but also to maintain the flexibility and independence of the query, which is very important in dealing with large business systems, at this level, CQRS is not used in DDD The architecture seems to be possible because it is a style that is not limited to an architecture implementation, so you can refine its valuable stuff and apply it to a suitable architecture system.
What would happen if CQRS contained the concept of domain (domain)?
Description: This figure was excerpted from Axonframework
The above picture contains a lot of concepts, but the essence is the same as the first diagram, but on the basis of the expansion and extension, first of all, to enumerate the concepts involved:
- Command bus: The diagram does not, and should be placed before command Handler, can be seen as a command publisher.
- command Handler: Handles requests from command Bus distribution and can be thought of as command subscribers, processors.
- Event bus: Typically, after Command Handler is complete, it can be considered an event publisher.
- Event Handler: Handles requests from the event Bus distribution and can be considered as event subscribers, processors.
- Event Store: Corresponds to the concept event Sourcing, which can be used for event playback processing to restore the specified object state.
Some of the above is the concept of EDA (event-driven architecture), this will be explained in detail later, I briefly describe the processing process, first of all to draw off two important concepts: command and Event (events), command is the tone of commands (itself is the meaning of the command, hehe), Its effect is to modify the state of an object, the command Bus collects command commands from the UI, and is distributed to the specific command Handler according to the specific commands, which will produce some domain operations and modify the corresponding domain objects, Command Handler only modifies the operation, does not involve the modified operation (such as Save, event release, etc.), the command Handler is completed does not mean that the command is finished, it needs to take the next action to the Event Bus (after the completion of the operation), and distributed to the corresponding Event Handler subscribers for processing, typically data preservation, event storage and so on.
Let's look at a piece of code in IDDD (P126):
public void commitBacklogItemToSprint( String aTenantId, String aBacklogItemId, String aSprintId) { TenantId tenantId = new TenantId(aTenantId); BacklogItem backlogItem = backlogItemRepository().backlogItemOfId( tenantId, new BacklogItemId(aBacklogItemId)); Sprint sprint = sprintRepository().backlogItemOfId( tenantId, new SprintId(aSprintId)); backlogItem.commitTo(sprint);}
Commitbacklogitemtosprint can be seen as a command Handler, notice its name (COMMITXXXXTOXXXX), see the past is the meaning of the order, Committo after the operation is submitted to the Event Bus , and then distributed to the appropriate Event Handler subscribers to complete the actions determined after the state modification, so that changes to the state of the domain object are completed.
About the Event Handler save Domain state operation, actually said simple also simple, said the complexity will be very complex, for it's implementation generally will adopt the asynchronous way, namely the domain state's preservation operation does not delay the domain the business operation, the data consistency uses the Unit of work, The specific domain state preservation is implemented with Repository.
Combing the Command the whole process, you will find a keyword: status, in the previous post on the REST concept, there is a similar concept: the application State (application), one of the meaning of rest is the state transition, From the start of the polite side of the request, to the end of the server response request, the application state in its process will be continuously converted, the entire request response process is the application of state transition process, for the Command processing process, the domain object state and application state is actually similar. I give an example, in the REST architecture style, the application state is not saved to the server side, the client initiates the request (contains the application state information), the service side to make the corresponding processing, the state will be converted to the resource State presented to the client, this is the expression layer state transition, back to the Command processing process, Command Bus receives a request from the UI, distributes it to the appropriate Command Handler, and, during processing, modifies the domain object, but it does not save the modified state information but instead gives it the Event Handler to save the state information.
Compared to Command, query processing process is much simpler, query Service receives from the UI queries, this query processing can be implemented in various ways, you can use ORM, or directly write SQL code, anyway: How to improve performance, how to come! The returned result type is typically a DTO (data transfer object), designed according to the UI, to reduce unnecessary data transfer.
2. eda-Event-Driven architecture
Event-driven Architecture (Event-driven architecture), from the definition of the solution channel:
Events represent events that occurred in the past, events that are both technical architecture concepts and business concepts, and event-driven programming models are called event-driven architectures for EDA.
Three features of the EDA architecture:
- Asynchronous
- Realtime
- Complete decoupling
The core of the EDA architecture is the message-based publish-subscribe model, which implements a one-to-many flexible distribution of events through the publish subscription pattern. The message consumer is completely transparent to the sender, the message sender just sends the message to the message middleware, all other things do not care, because the message middleware in the MQ and other technologies, even when the message is sent, the message receiver is not available, but still can send normally, this is called complete decoupling. The second one-to-many release subscription model is also a core focus, for the message of the Subscriber and subscription mechanism, the message middleware can be flexibly configured and managed, and for the message sender and the sending logic basically has no impact.
EDA requires that through business processes, we first identify valuable business events that conform to basic event characteristics such as asynchronous, real-time, and publish subscriptions, followed by detailed analysis and definition of events, definition of event-specific message formats, and definition of the event's publish-subscribe mechanism. Finally, it is based on the message event pattern development and testing work.
In the previous blog post on the SOA, we know that the client and the service side, the client initiates the request to the server, the service side to make the corresponding response, that is, the client is active, the server is passive, this situation will cause the dispersion of services, that is, we generally design services, According to the client's response and forced to split the business logic, the result is that each business module belongs to the service, is dispersed in the various business systems, this design will lead to a lot of problems occur. For the EDA architecture, subscribers subscribe to event bus events and tell the event buses that I want this, and that when the subscription is received, it is not processed immediately, but when it is processed, the initiative is in the hands of event bus, when event bus wants to When processing, generally accept requests from Command Handler, and then publish the notification to the designated subscribers, telling them that I have handled it, and you can do the following.
From the above description, we can see the obvious difference between SOA and EDA, compared to SOA, EDA is more conducive to the aggregation of the domain, the initiative in the field hands, we can calmly face a lot of situations, simply draw a picture:
In addition, it should be noted that CQRS can be combined with EDA, or can not be combined, but in turn for the EDA, it must be combined with CQRS use.
2.1 Domin event-Field events
Domain Events and domain service (Domain Services) are similar to the DDD Tactical model, which is described in detail in the eighth chapter of IDDD, as I have not yet learned that part, which is briefly explained here. In the definition of EDA, the event represents an event that happened in the past, in other words, it represents the completed event, and, in preparation, it should contain the events that are being completed, since it belongs to the DDD Tactical model, which must be useful in the domain design.
I use plain English to describe the role of domain events in the field: we know that marching battles require a choice, that is to say, a command is required after the command has been negotiated, and then handed over to the respective operational centers, the Army, the Navy, the Air Force, the missile forces, etc., which are the implementers of the order, and the command's decision maker , this is the same as the domain event, after dealing with some business logic in the domain, it will make some changes to the state of the domain object, which is equivalent to the Combat command, and then according to the Battle command assigned by the Combat Center to complete, that is, the domain event subscribers to complete the domain object state changes after the operation, in short, Domain events are "runners" in the field.
In the above EDA introduction, there is such a piece of code: backlogItem.commitTo(sprint);
, in general language expression is: pending items submitted to the sprint, this is an operation completed in the field, by Command Handler delegated completion, Backlogitem is an aggregate root object, Committo is an action in the aggregation root, when this operation is completed, the state of the Backlogitem aggregation root object will be modified, and in Committo, what is the specific operation? Take a look at the sample code:
PublicvoidCommitto (Sprint asprint) {This.assertargumentnotnull (Asprint,"Sprint must not being null.");This.assertargumentequals (Asprint.tenantid (),This.tenantid (),"Sprint must be of same tenant.");This.assertargumentequals (Asprint.productid (),This.productid (),"Sprint must be of same product.");if (!this.isscheduledforrelease ()) {throw new illegalstateexception ( "must be scheduled for release to commit to Sprint."); } if (this.iscommittedtosprint ()) { if (!asprint.sprintid (). Equals (this.sprintid ())) {this.uncommitfromsprint (); }} this.elevatestatuswith (backlogitemstatus.committed); this.setsprintid (Asprint.sprintid ()); Domaineventpublisher. Instance (). Publish (new backlogitemcommitted (this.tenantid (), this.backlogitemid (), This.sprintid ()))}
Note that Committo is in the Backlogitem aggregation root, preceded by some state operations on the aggregate root object, and we will see Domaineventpublisher (the domain event publisher), backlogitemcommitted inherit from domainevent,backlogitemcommitted the corresponding domain event, the subscription in the Backlogitemapplicationservice, is generally the aggregation root object at the time of initialization.
According to the above code example, and then combined with the three features of EDA can be well understood, first of all, the processing of domain events is asynchronous completion, so that the aggregate root of the other business operations, and when the domain event is published, will inform subscribers in real-time processing, Because it does not matter what the subscribers are dealing with, the Subscriber and publisher specifications are in Domainevent, rather than enforced as interface definitions and implementations, so when domain events are published, it means that subscribers have been told and processed, so their direct relationships can be completely decoupled.
In the previous short message project, I did not use the domain event, nor is it very deep understanding, in the later post, the detailed explanation.
2.2 long-running Process (Saga)-long-time processing
From the definition in IDDD:
Event-driven, distributed, parallel processing mode.
About the Saga, there is almost no domestic (netfocus there is a relevant note), long-time processing, indicating that it is a time-consuming, multi-task parallel processing process, in the field, when will it have its use? A seemingly simple business logic, for example, may involve complex business operations in the domain, and it can take a long time to process.
In the electronic mall to submit an order operation, the user may seem very simple, but in the field of processing, will involve the order operation, customer operations, commodity operations, inventory operations, message notification operations, and some will be processed in a timely manner, but some do not, such as message notification operations, etc. We can take this business operation to separate, for some time-consuming operation of the fine-pick, the reduction of the corresponding inventory reduction, the reduction will be a cordon judgment, if below the alert, will send a message to the inventory manager, merchandise reduced the corresponding commodity statistics also to be updated, The customer will also send a message notification after the purchase, we can use a saga to deal with, because it is event-driven, so a saga will subscribe to multiple events, the saga will be tracking these events, for some event processing failure, but also to make appropriate remedies, When all of the operations are complete, the Saga returns a status to the realm, and perhaps the return operation has already started several days later.
Description: This figure is from MSDN
Description: A business process for meeting the purchase of a seat, the middle Order process Manager is a Saga, and in the CQRS architecture is the process manager, which we typically use to handle the business logic of multiple aggregated root interactions, such as Netfocus the Transferprocesscommandhandlers operations listed in the blog post, as well as the purchase of seat business operations in, then how should we design a Saga? Or in the design of the time, you should pay attention to what areas? I'll make a rough list:
- Try to design the Saga as a combination of tasks, and you can think of it as a combination of tasks and keep track of each task within.
- A Saga can also be represented in a set of aggregations, the example shown above.
- Stateless processing, because it is event-driven, state information is wrapped in events and can be treated as stateless for the entire Sage process.
- can be applied to distributed design.
2.3 Event sourcing-Events Traceability
A literal understanding:
An event is a verb, which can be understood as the meaning of the trace, and the source represents the original, source meaning, which together represents an event tracking process.
We all know that in source code control, you can use SVN, Git, CVS for code modification Tracking operations, from the creation of a code file, we can see the revision of the code changes, and even can specify the version of the restore operation, this is the benefit of code tracking. For the domain object, we should also know the evolution of its entire life cycle, so that it is advantageous to view and restore a "moment" of the domain object, in the EDA architecture, the domain object state preservation is done through the domain event, so we want to record the domain object's state record, You need to save all the events experienced by the domain object, which is the event store, which is the equivalent of a Git code server that stores events that are experienced by all domain objects and can be considered a "snapshot" of the corresponding domain object for an event.
In general, ES event traceability can be summarized as two points:
- Recording
- Restores
Finally, paste a CQRS, EDA, Saga, ES combination diagram:
Description: This image is from Netfocus
CQRS Reference:
- CQRS Architecture
- The basic understanding of CQRS
- Introducing the Command Query Responsibility segregation Pattern
- A brief talk on command query duty separation (CQRS) mode
- CQRS Journey
- NCQRS framework-the CQRS Framework for. NET
- Cqrs-journey
EDA Reference:
- EDA Event-driven architecture
- Domain Event Domin events and Eventsourcing
- Event Sourcing Pattern
- Enode 1.0-Introduction to the overall architecture
- Enode 2.0-Introduction to the overall architecture
- Thinking about how to design an event-driven architecture
- What is the source of events (event Sourcing)
- The thought and realization of Enode 1.0-saga
- A Saga on Sagas
Unfinished two points:
- 3. CQRS journey-Microsoft Sample Project
- 4. Enode-netfocus Practice Project
I would also like to analyze these two projects, at least to understand a business process, such as Conference project Assignseats, Conferencepublish, Enode project Banktransfersample example, but analyzed , there are some difficulties, sometimes the concept is on the one hand, the practice is on the other hand, there is time to understand, and then the two-point content to be supplemented.
The content of this blog is a bit empty, we can learn from the useful place on the line, also welcome to shoot brick Treatise.
CQRS (Command query separation of responsibilities) and EDA (event-driven architecture)