Commands and Events in Domain Driven Design

In Domain Driven Design we have 2 main types of messages: commands and events. Also you can think of queries as a type of message used to retrieve information from somewhere, but I won't go there on this post.



A command is a message that represents an intention, a desire to modify something in the domain. Commands must always be named as an action with a verb (e.g: AddProduct ). They are naturally synchronous in a way that they have a response that determines whether a command has been accepted or rejected.

An event is a message that represents the change that can happen or has already happened. Events must always be named using the participle of a verb (e.g: ProductAdded). They are facts, and they are naturally asynchronous in a way that they don't have a response since they're produced in a fire and forget manner.

Whether you use Command or Event suffix on your names is up to you. I personally think that the concept is implicit in the name so there is no need.

A command is a message sent to the domain to do something on it. As I already mentioned, it represents an intention and that means that a command can be rejected if, for example, does not pass a business validation or it is trying to modify something on a stale version of the domain model (i.e: the aggregate root's version is higher than the version specified on the command). If it is not rejected it will generally end up indirectly producing zero, one or more events. I say indirectly because the command does not know anything about an event, it is the the domain model (i.e: the aggregate root) the one that produces events in order to change its state.

Ideally we should aim for a one to one relationship between a command and an event, but sometimes it makes sense that as a result of a single command there are two or more events that have been raised within the same transaction in order to keep always the domain model (i.e: the aggregate root) in a transactionally consistent state.

Let's see an example to clarify this. Suppose we have a business that requires that the payment of an invoice results also in the completion of the booking. We could think of our aggregate root being Booking and we would send a command to a specific booking to have it paid, for example PayBooking. The result of the business method on a Booking would typically produce zero or two events: BookingPaid and BookingCompleted.

Could we simply produce the BookingPaid event at the end of the transaction and later on (maybe through a domain policy event handler) subscribe to that event and produce a new transaction to complete the booking and produce the BookingCompleted event? According to business no. They have clearly stated that a booking that is paid must be completed, and if we didn't have these two events as the result of the same transaction we would not be transactionally consistent because there would be a specific point on time where our Booking has been paid but not yet completed.

Always consider business requirements in order to model your domain and the flow properly and avoid situations where your domain objects are in an inconsistent state, even if it's temporary inconsistent. Beware this consistency concept has nothing to do with the term eventual consistency which has to do with the delay between the point in which the domain is at certain state and the time in which this state is projected and available in a read model.

Comments