为什么命令和事件是分开表示的?

在强调事件的体系结构中,命令和事件之间有什么区别?我能看到的唯一区别是,命令通常由系统外的参与者来源/调用,而事件似乎由系统中的处理程序和其他代码来源。然而,在我见过的许多示例应用程序中,它们具有不同(但功能相似)的接口。

22297 次浏览

Commands can be rejected.

Events have happened.

This is probably the most important reason. In an event-driven architecture, there can be no question that an event raised represents something that has happened.

Now, because Commands are something we want to happen, and Events are something that has happened, we should be using different verbs when we name these things. This drives separate representations.

I can see is that commands are usually sourced/invoked by actors outside the system, whereas events seem to be sourced by handlers and other code in a system

This is another reason they are represented separately. Conceptual clarity.

Commands and Events are both Messages. But they are in fact separate concepts, and concepts should be modeled explicitly.

They are represented separetly because they represent very different things. As @qstarin said commands are messages that can be rejected, and that on success will produce an event. Commands and events are Dtos, they are messages, and they tend to look very similar when creating and entity, however from then on, not necessarily.

If you are worried about reuse, then you could use commands and events as envelopes to your (messge) payload

class CreateSomethingCommand
{
public int CommandId {get; set;}


public SomethingEnvelope {get; set;}
}

however, what I d like to know is why are you asking :D ie do you have too many commands/events?

After working through some examples and especially the Greg Young presentation (http://www.youtube.com/watch?v=JHGkaShoyNs) I've come to the conclusion that commands are redundant. They are simply events from your user, they did press that button. You should store these in exactly the same way as other events because it is data and you don't know if you will want to use it in a future view. Your user did add and then later remove that item from the basket or at least attempt to. You may later want to use this information to remind the user of this at later date.

In addition to the conceptual differences mentioned above, I think there is another difference related to common implementations:

Events are typically processed in a background loop that needs to poll the event queues. Any party interested in acting on the event may, usually, register a callback that is called as a result of the event queue processing. So an event may be one to many.

Commands may not need to be processed in such a manner. The originator of the command will typically have access to the intended executor of the command. This could be, for example, in the form of a message queue to the executor. Thus a command is intended for a single entity.

I think something to add to quentin-santin's answer is that they:

Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.

Source.

Also, in addition to all the answers here exposed, an event handler may be able to trigger a command as well after receiving notification that an event occurred.

Say for example that after you create a Customer, you also want to initialize some accounts values, etc. After your Customer AR add the event to the EventDispatcher and this is received by a CustomerCreatedEventHandler object, this handler can trigger a dispatch of a command which will execute whatever you need, etc.

Also, there are DomainEvents and ApplicationEvents. The difference is simply conceptual. You want to dispatch all your domain events first (some of them may produce Application Events). What do I mean by this?

Initializing an account after a CustomerCreatedEvent has occurred is a DOMAIN event. Sending an email notification to the Customer is an Application Event.

The reason you shouldn't mix them is clear. If your SMTP server is temporarily down, that doesn't mean that your DOMAIN OPERATION should be affected by that. You still want to keep a non-corrupted state of your aggregates.

I usually add events to my Dispatcher at the Aggregate Root level. This events are either DomainEvents or ApplicationEvents. Can be both and can be many of them. Once my command handler is done and I am back in the stack to the code that execute the Command handler, then I check my Dispatcher and dispatch any other DomainEvent. If all of this is successful, then I close the transaction.

If I have any Application Events, this is the time to dispatch them. Sending an email doesn't necessarily need an open connection to a database nor a transaction scope open.

I strayed away a little bit from the original question but it is also important for you to understand how events may also be conceptually treated differently.

Then you have Sagas.... but that's WAYYYY OFF of the scope of this question :)

Does it make sense?

The event is a fact from the past.

The command is only a request, and thus may be refused.

Commands Events
Purpose Invoke Behavior Something Happened
Ownership Command Owned by Consumer Event Owned by Publisher
Consumers One Consumer Zero or Many Consumers
Senders Many Senders Single Publisher
Naming Verb Past Tense

An important characteristic of a command is that it should be processed just once by a single receiver. This is because a command is a single action or transaction you want to perform in the application. For example, the same order creation command should not be processed more than once. This is an important difference between commands and events. Events may be processed multiple times because many systems or microservices might be interested in the event. 'msdn'

You cannot recompute a state based on commands, because in general they can produce different outcomes each time they are processed.

For example, imagine a GenerateRandomNumber command. Each time it's invoked it will produce a different random number X. Thus, if your state depends on this number, each time you recompute your state from the commands history, you'll get a different state.

Events solve this problem. When you execute a command, it produces a sequence of events that represent the outcome of the command execution. For example, the GenerateRandomNumber command could produce a GeneratedNumber(X) event that logs the generated random number. Now, if you recompute your state from the events log, you'll always get the same state, because you'll always use the same number that was generated by a particular execution of the command.

In other words, commands are functions with side-effects, events record the outcome of a particular execution of a command.

Note: You can still record a history of commands for audit or debugging purposes. The point is that to recompute the state, you use the history of events, not the history of commands.

Just to add to these great answers. I'd like to point out differences with regards to coupling.

Commands are directed towards a specific processor. Thus there is some level of dependence/coupling with the Command initiator and the processor.

For example, a UserService upon creating a new user sends a "Send Email" Command to the EmailService.

The fact that the UserService knows that it needs the EmailService, that is already coupling. If EmailService changes its API schema or goes down, it directly affects the UserService function.


Events are not directed towards any specific event handler. Thus the event publisher becomes loosely coupled. It does not care what service consumes its event. It's even valid to have 0 consumer of an Event.

For example, a UserService upon creating a new user publishes a "User Created Event". Potentially an EmailService can consume that event and sends an email to the user.

Here the UserService is not aware of the EmailService. They are totally decoupled. If the EmailService goes down, or changes business rules, we only need to edit the EmailService


Both approaches have merits. A purely Event Driven Architectural design is harder to track since it is too loosely coupled, especially on large systems. And a Command heavy Architecture have high level of coupling. So a good balance is ideal.

Hope that makes sense.