Sponsor: Do you build complex software systems? See how NServiceBus makes it easier to design, build, and manage software systems that use message queues to achieve loose coupling. Get started for free.
One of the building blocks of messaging is, you guessed it, messages! But there are different kinds of messages: Commands and Events. So what’s the difference? Well, they have very distinct purposes, usage, naming, ownership, and more!
Check out my YouTube channel where I post all kinds of content that accompanies my posts including this video showing everything in this post.
The purpose of commands is the intent to invoke behavior. When you want something to happen within your system, you send a command. There is some type of capability your service provides and you need a way to expose that. That’s done through a command.
I didn’t mention CRUD. While you can expose Create, Update, and Delete operations through commands, I’m more referring to specific behaviors you want to invoke within your service. Let CRUD just be CRUD.
Commands have two parts. The first is the actual message (the command), which is the request and intent to invoke the behavior. The second is consumer/handler for that command which is performing and executing the behavior requested.
Commands have only a single consumer/handler that resides in the same logical boundary that defines and owns the schema and definition command.
Commands can be sent from many different logical boundaries. There can be many different senders.
To illustrate this, the diagram below has many different senders, which can be different logical boundaries. The command (message) is being sent to a queue to decouple the sender and consumer.
A single consumer/handler, that owns the command, will receive/pull the message from the queue.
When processing the message, it may interact with its database, as an example.
As mentioned, there can be many senders, so we could have a completely different logical boundary also sending the same command to the queue, which will be processed the same way by the consumer/handler.
Lastly, naming is important. Since a command is the intent to invoke behavior, you want to represent it by a verb and often a noun. Examples are PlaceOrder, ReceiveShipment, AdjustInventory, and InvoiceCustomer. Again, notice I’m not calling these commands CreateOrder, UpdateProduct, etc. These are specific behaviors that are related to actual business concepts within a domain.
Events are about telling other parts of your system about the fact that something occurred within a service boundary. Something happened. Generally, an event can be the result of the completion of a command.
Events have two parts. The first is the actual message (the event), which is the notification that something occurred. The second is the consumer/handler for that event which is going to react and execute something based on that event occurring.
There is only one logical boundary that owns the schema and publishes an event.
Event consumers can live within many different logical boundaries. There may not be a consumer for an event at all. Meaning there can be zero or many different consumers.
To illustrate, the single publisher that owns the event will create and publish it to a Topic on a Message Broker.
That event will then be received by both consumers. Each consumer will receive a copy of the event and be able to execute independently in isolation from each other. This means that if one consumer fails, it will not affect the other.
Naming is important. Events are facts that something happened. They should be named in the past tense which reflects what occurred. Examples are OrderPlaced, ShipmentReceived, InventoryAdjusted, and PaymentProcessed. These are the result of specific business concepts.
So how do commands and events fit together? Since Commands are about invoking intent, and Events are about indicating that something occurred, you can see how the result of a command can be publishing an event.
First, we have a client/browser making a call to our HTTP API. Let’s say its to place an order.
In this specific case, we want to just accept the incoming HTTP request and capture the relevant data and send a PlaceOrder command to a queue on our message broker so we can process the message asynchronously. At which point we can then immediately return the client/browser that we accepted the request and are processing it.
Asynchronously the command handler can pull the message from the queue and execute whatever behavior is required to place the order.
The result of this is now we are going to publish an OrderPlaced event to a topic on the message broker.
We have 2 different consumers for the OrderPlaced event. One is to send an email to the customer saying thank you for your order. The other consumer might be to process their credit card and charge them for the order.
Commands & Events
To summarize commands and events we can compare and contrast their purpose, ownership, consumers, senders, and naming.
Developer-level members of my YouTube channel or Patreon get access to a private Discord server to chat with other developers about Software Architecture and Design as well as access to source code for any working demo application that I post on my blog or YouTube. Check out the YouTube Membership or Patreon for more info.