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.
There are many different ways to create events in Event Driven Architecture. Events from CRUD or created from specific actions that have occurred. In some cases, consumers only care about the full scope of an entity/data. In other boundaries, consumers only care about what has occurred. When publishing events from CRUD you’ll likely care more about propagating state. However, events derived from tasks/commands are often used more as notifications about business process occurrences.
Check out my YouTube channel where I post all kinds of content that accompanies my posts including this video showing everything that is in this post.
When developers start getting into Event Drive Architecture, I find they most often create events that are represented by Create/Update/Delete of an Entity. Meaning if there is a Product Entity, then they have a ProductCreated event, ProductUpdated event, or ProductDeleted event.
This is most often driven by UI and APIs that are CRUD and Entity oriented. I call these APIs Entity Services and try to avoid them when working in the core of a domain. For more info on Entity Services, check out my post AVOID Entity Services by Focusing on Capabilities
The next most common type of event created for those new to Event Driven Architecture is still driven by CRUD and Entities, but all the updates are property-based. If the Product Entity has a Quantity property, then the event published ends up being a ProductQuantityUpdated event.
In both types of events what’s common about them is the event contains data. If it’s a Created or Update type event, often it will contain the entire Entity that was created. If it’s a Property Updated event, it will likely contain the new value of the property, but it’s also common that people will put the old value as well.
The reason why this is common is that a lot of systems are developed primarily based on CRUD. If you’re UI and APIs are driven by CRUD, you’re going to develop events that are derived from CRUD.
What’s the alternative to CRUD? Taking a more task-driven approach to developing a system. Providing end-users with capabilities that are directly related to the business functions they perform. In my example above with ha Product Entity, a user doesn’t “Update the Quantity”. There is a reason for this that’s related to a task. Did the warehouse do a stock count and realized they found more products on the actual shelves than are stated in the system? If so they would perform an “Inventory Adjustment”. There’s a difference between “Inventory Adjustment” and “Update the Quantity”.
In the events above, they are all behavioral. These events are statements of facts of actual business events. In order to publish these types of events, you need to move away from CRUD and move towards Commands and a Task Based-UI. For more on this check out my post Decomposing CRUD to a Task Based UI.
In the above screenshot, we’ve moved away from CRUD in some aspects. The Name and Description can be saved by a simple update however we can no longer just change the Quantity. We need to specify an action/task that is a business reason why we are changing the Quantity.
From this, we can derive that we are creating and publishing an InventoryAdjusted event which allows us to be much more explicit.
Explicit vs Implicit
CRUD-based events (ProductCreated, ProductUpdated, etc) aren’t inherently bad. They can be useful for referential data that lives on the edge of your system. Data that is not a part of the (sub)domain you’re focusing on. For this reason, you might publish CRUD-based type events because other service boundaries want a local cache copy of that data. However, since they aren’t explicit about the reason or business task that occurred and created the event, you won’t have that insight from a consumer. You would have to imply it, if you could, based on data that changed.
Behavioral Events (ProductShipped, ProductInventoryAdjusted, etc) are explicit. They tell consumers exactly what has occurred. These types of events are generally used as a notification to other service boundaries that might be a part of a long-running business process. They usually only contain a minimal amount of data. They are generally used for data propagation for local cache copies. Check out my post on Event Choreography & Orchestration that covers how behavioral events are used between services.
Developer-level members of my CodeOpinion YouTube channel get access to the full source for any working demo application that I post on my blog or YouTube. Check out the membership for more info.