Why are commands and events separately represented?
What is the difference between commands and events in architectures that emphasize events? The only distinction 开发者_JS百科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. However, in many example applications I have seen, they have different (but functionally similar) interfaces.
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.
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'
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?
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.
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.
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?
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.
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.
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.
I'd like to supplement the already good answers with another aspect, esp. for those familiar with the functional core, imperative shell pattern.
Events correlate to the functional core and commands to the imperative shell. That is, events reside in the pure and commands in the impure. The shell, like any CLI, handles all impurities.
This can be seen in that commands are validated and sometimes rejected. It can also be seen in that commands can rely on randomization while events cannot. For example, rolling dice in a game of Backgammon would involve issuing a roll
command and its result when generated would be immediately memorialized in a rolled
event. The value of this separation can be further seen in the ability one has to source or replay events.
While it is possible for live events to bubble up to the shell and for them to cause new commands to be issued and new side effects to happen, for this very reason it should not be possible for replayed events to bubble up.
精彩评论