Domain events are objects that represent something that happened in the domain that is relevant to the business or the users. They usually have a name, a timestamp, an identifier, and some data that describes the event details. Domain events are not commands or queries, as they do not tell the system what to do or ask for information. Instead, they inform the system and the interested parties about what has already happened, and allow them to react accordingly.
-
A domain event is the representation of a change that occurred in the past on an aggregate present in the core domain. They are immutable since once they have been created their state does not change and they only transmit the information of the change to other interested aggregates or bounded contexts.
-
Understanding domain events requires recognizing that they are both passive and informative. Passive, because they do not instruct the system to perform a specific task, but rather record that fact that an event has occurred. Informative, because they carry the data necessary for the system to understand and react to the specific event. When we talk about levels of abstraction and granularity, we're essentially discussing the detail and scope that each event carries. By using different levels, you can create a system that caters to various needs, from high-level overviews to detailed, step-by-step operations, providing both a bird's eye view and a detailed perspective of the processes.
Depending on the complexity and size of your domain, you may need to use different levels of abstraction and granularity for your domain events. Abstraction is about how general or specific your domain events are, while granularity is about how fine-grained or coarse-grained your domain events are. For instance, a high-level and coarse-grained domain event could be "OrderPlaced", while a low-level and fine-grained domain event could be "ItemAddedToCart". Utilizing different levels of abstraction and granularity can assist you in various ways, such as simplifying the domain model by grouping related events into higher-level events, increasing expressiveness and clarity by creating more specific and detailed events, ensuring consistency and reliability by reflecting the true state of the domain, and improving scalability and performance by reducing the frequency and size of the events.
-
Conceptually, a domain event can be modeled in strategic design as a mechanism to communicate between various bounded contexts, or at a tactical level as a mechanism to propagate information about an aggregate.
-
Using different levels of abstraction and granularity in domain events can help manage the complexity of your domain. Abstraction helps to generalize or specify events, while granularity controls the detail level. For example, a high-level "OrderPlaced" event may be suitable for some purposes, while a low-level "ItemAddedToCart" event might be needed for other scenarios. This versatility can enhance the expressiveness, reliability, and performance of your domain model. Varying levels of abstraction and granularity function as the system's lens, altering the focus to either a broad overview or intricate details as needed.
Choosing the right level of abstraction and granularity for your domain events is not a one-size-fits-all solution. You need to consider factors such as the domain context, event sources and consumers, event data, and event handling. Generally, you should use high-level, coarse-grained events when capturing the overall outcome of a process or action and there are few interested parties. Low-level, fine-grained events should be used when capturing individual steps or actions and there are many interested parties. A combination of different levels of abstraction and granularity can be used to support different perspectives or scenarios, and you can leverage techniques such as event hierarchies, composition, filtering, or aggregation.
To illustrate how to design domain events with different levels of abstraction and granularity, let's use an example of an online shopping domain. In this domain, we have two main entities: Customer and Order. A Customer can place an Order with one or more Items, and an Order can have different statuses, such as Pending, Confirmed, Shipped, or Delivered.
We can design domain events for this domain that vary in both abstraction and granularity. For instance, the OrderPlaced event is a high-level and coarse-grained event that represents the completion of a customer's order placement. It has a name, a timestamp, an order ID, a customer ID, and a list of items; it's useful for notifying other parts of the system about the new order. On the other hand, ItemAddedToCart is a low-level and fine-grained event that represents the addition of an item to a customer's cart. It has a name, a timestamp, an item ID, a customer ID, and a quantity; it's useful for tracking the customer's shopping behavior and updating the cart state in the session.
You can also use event patterns or techniques to combine or transform these domain events. For instance, you can create an event hierarchy with parent and child events; you can create composite events that contain other events as properties or fields; you can create filters to handle only specific events; or you can create aggregators to handle multiple events with a single event object. By leveraging these patterns and techniques, you can design domain events with varying levels of abstraction and granularity according to your needs.
Testing domain events is an essential part of ensuring the quality and correctness of your domain model. Different types of testing techniques can be used to verify your domain events, such as unit testing, integration testing, and end-to-end testing. Unit tests can be written and run using frameworks or libraries like xUnit or NUnit for .NET, JUnit or TestNG for Java, or PyTest or unittest for Python. Integration tests can be written and run using similar frameworks or libraries. End-to-end tests can be written and run using frameworks or tools such as Selenium or Cypress for web applications, Appium or Espresso for mobile applications, or Postman or REST Assured for API applications. All of these techniques help you ensure the quality and correctness of your domain model.
-
Testing is a non-negotiable aspect of the software development lifecycle and domain events are no exception. Ensuring that your domain events are triggering correctly, carrying the right data, and being consumed effectively is vital to maintaining the robustness and reliability of your system. Different testing techniques serve unique roles in this process: unit tests ensure that individual components are working as expected, integration tests verify the correct interaction between components, and end-to-end tests validate the entire system's behaviour under a variety of scenarios. It's essential to use a combination of these testing methodologies to ensure your domain events are functioning correctly.
-
Since domain events are an abstract modelling tool, it is often the case that performance considerations are overlooked, even though crucial to the final system. Depending on scale and complexity, a large volume of fine-grained events can lead to performance issues, while a small number of coarse-grained events may not provide detail required for some use cases. It's also crucial to consider how domain events will be stored and managed; will they be persisted in a database, published to a message queue, or broadcast over a network? These factors can significantly influence the appropriateness of a particular event structure for a system, and if not considered early and often, can lead to significant problems in later development stages.
Rate this article
More relevant reading
-
Model-view-viewmodel (MVVM)How do you ensure consistency and reliability of events in event aggregator pattern in MVVM?
-
Domain-Driven Design (DDD)How do you document and share domain events and aggregates with other developers and stakeholders?
-
Domain-Driven Design (DDD)How do you evolve domain events over time without breaking existing subscribers?
-
User ExperienceHow do you use card sorting to improve your information architecture?