当前位置:网站首页>Beyond crud: command, event and bus

Beyond crud: command, event and bus

2021-05-04 15:50:11 Jiedao jdon

One of the reasons why it's sometimes difficult to write software on time within budget is , Lack of attention to business language as the domain experts say . Most of the time , Identifying requirements means mapping understood requirements to some kind of relational data model . then , Build business logic to tunnel data between persistence layer and presentation layer , And make necessary adjustments in the process . Although not perfect , But the pattern is still in use for a long time , And the increasing complexity makes this CRUD The mode of adding, deleting, changing and checking has been unable to adapt to the changing needs , in any case , Introduce it DDD Is still the most effective way to deal with any software project today .

From Microsoft Msdn Website article : Leading technology - transcend CRUD: command 、 Events and buses How to use command event and bus instead of traditional CRUD System . Transfer and adjust as follows :

The event shows its purpose in the above situation , Because they force different forms of domain analysis , More mission oriented , And there's no need to quickly find the perfect relational data model for storing data .

For example, in the case of hotel room reservation , Whenever a room is reserved , The system will record the information about a given reservation ID Events created by the subscription of . To retrieve aggregations ( That's reservation ) All events for , Just query the specified booking ID Event data storage for , It's enough to get all the information . It really works , But it's a very simple solution .

Aggregation and objects

event / Aggregate associations are written in the common language of the business domain . No matter what , Compared to a simpler one-to-one association , One to many associations are more likely to happen . say concretely , The one to many correlation between events and aggregations means that events are sometimes related to multiple aggregations , And there may be more than one aggregate concern handling the event , And may change its state due to the event .

for example , Imagine a plan : Register the invoice as the cost of the work order in progress in the system . It means , There may be two aggregations in your domain model - Invoices and work orders . The registered event invoice will capture the attention of the invoice aggregation as the new invoice enters the system , But if the invoice involves some activities related to the order , It may also capture JobOrder Aggregate attention . Obviously , Only after fully understanding the business domain , To determine if the invoice is related to the work order . There may be domain models that exist independently here ( And Applications ) And the invoice may be registered in the accounting of the work order and then change the domain model of the current balance ( And Applications ).

however , Knowing that events can be associated with many aggregations completely changes the architecture of the solution and the prospects for viable technologies .

Scheduling events decomposes complexity

The major constraint that events are bound to a single aggregation is CRUD and H-CRUD The foundation of this is . When business events involve multiple aggregations , You write business logic code to ensure that the state is changed and tracked appropriately . When the number of aggregations and events exceeds the critical threshold , The complexity of business logic code can become difficult to handle and evolve .

In this context ,CQRS The model represents the first step in the right direction , Because it basically suggests that you know the current state of the system “ Read only ” or “ Modify only ” Operation to infer separately . Event sources are another popular pattern , It suggests that you record all actions that occur in the system as events . Tracking the entire state of the system , The actual state of aggregation in the system is constructed as a projection of events . let me put it another way , You map the content of the event to other properties , Together, they make up the object states available in software . Event sources are built around a framework that knows how to save and retrieve events . The event source mechanism is to only append , Support replay of event stream , And know how to save relevant data that may have very different layouts .

Such as EventStore (bit.ly/1UPxEUP) and NEventStore (bit.ly/1UdHcfz) The event storage framework abstracts the real persistence framework , And provide advanced API To use events directly in your code . In essence , The flow of events that you see has some relevance , The purpose of focusing on these events is to aggregate . It's going to work . however , When an event has an impact on multiple aggregations , You should find a way , Enable each aggregation to track all events it focuses on . Besides , You should try to build a software infrastructure , This structure is not only concerned with event persistence , It also allows all running aggregations to be notified of the events of interest .

To achieve proper scheduling of events to aggregation and appropriate event persistence ,H-CRUD It's not enough. . It's important to revisit the patterns behind business logic and the techniques used to hold event-related data .

Define aggregation

The concept of aggregation comes from DDD, In short , Cluster of domain objects that are grouped together to match transaction consistency . Transaction consistency simply means , Ensure that any transactions formed within the aggregation are consistent and up-to-date at the end of the business operation . The following code snippet demonstrates an interface that summarizes the main aspects of any aggregation class . There may be more , But I'm sure that's the minimum :

public interface IAggregate
{
Guid ID { get; }
bool HasPendingChanges { get; }
IList<DomainEvent> OccurredEvents { get; set; }
IEnumerable<DomainEvent> GetUncommittedEvents();
}

No matter when , Aggregations contain a list of events that have occurred , And you can distinguish between submitted events and uncommitted Events ( Causes pending changes ). Realization IAggregate The base class of the interface needs non-public member settings ID And implement a list of submitted and uncommitted Events . Besides , Aggregate base classes also have some RaiseEvent Method , Used to add events to the internal list of uncommitted Events . Interestingly , How can events be used internally to change the aggregation state ? Suppose you have a customer aggregation , And want to update the customer's public name . stay CRUD In the plan , Just do the following simple assignment :

customer.DisplayName = "new value";

If you use events , It's going to be a more complicated route :

public void Handle(ChangeCustomerNameCommand command)
{
var customer = _customerRepository.GetById(command.CompanyId);
customer.ChangeName(command.DisplayName);
customerRepository.Save(customer);
}

At the moment , Let's skip Handle Method and the person who runs it , And focus on Implementation . At first ,ChangeName It looks like it's just a previous check CRUD Wrapper for style code . It's not exactly like this :

public void ChangeName(string newDisplayName)
{
var evt = new CustomerNameChangedEvent(this.Id, newDisplayName);
RaiseEvent(e);
}

Defined on an aggregate base class RaiseEvent Method appends events to the internal list of uncommitted Events . Uncommitted events are eventually handled when the aggregation is saved .

Save state through events

With a deeper understanding of the event , You can make the structure of a repository class generic . The design described so far is for repositories that run with aggregate classes Save Method only iterates through the list of aggregated uncommitted Events , And call the new methods that aggregation must provide - ApplyEvent Method :

public void ApplyEvent(CustomerNameChangedEvent evt)
{
this.DisplayName = evt.DisplayName;
}

The aggregate class will have a ApplyEvent An overload of method . In the past CRUD The style code will find its location here .

There is also a missing link : How to arrange front end use cases 、 End user actions with multiple aggregations 、 Business workflow and persistence ? You need a bus component .

Introduce the bus components

Bus components can be defined as shared paths running between instances of known business processes . The end user performs operations through the presentation layer , And set instructions for the system to process . The application layer receives these inputs and translates them into specific business operations . stay CRUD In the plan , The application layer will directly call the business process responsible for the requested operation ( Workflow ).

When there are too many aggregation and business rules , The bus will greatly simplify the overall design . The application layer pushes commands or events to the bus , So that the listener can respond correctly . Listeners are often called “sagas” The components of , It is the final instance of a known business process .Saga Know how to respond to a large number of commands and events .Saga Have access to the persistence layer , And push commands and events back to the bus .Saga Is the above Handle Class of method . Usually , Every workflow or use case has one saga class , It can be fully recognized by the events and commands it can handle . The overall generated architecture is shown in the figure 1 Shown .


Finally, please note , Events must also be saved and returned to their source for querying . And that leads to another point : Is a classic relational database an ideal place to store events ? Different events can be added at any time during development and later production . Besides , Each event has its own architecture . In this context , Non relational data storage is suitable for ( Although using a relational database is still an option - At least according to the scheme of sufficient evidence to consider and exclude ).

summary

I dare say , Most of the ideas about software complexity come from the fact that : Although based on abbreviations ( establish 、 Read 、 to update 、 Delete ) The basic four operations in are no longer as simple as reading and writing individual tables or aggregations , But we continue to think about using the system CRUD Method . This article is a preview of a deeper analysis of patterns and tools , I'll continue to talk about it next month , I'll show you the framework that tries to make this kind of development faster and sustainable .

版权声明
本文为[Jiedao jdon]所创,转载请带上原文链接,感谢
https://chowdera.com/2021/05/20210504154434898e.html

随机推荐