Events

Domain Events, Event Sourcing, and CQRS

Domain Events

A Domain Event
  • Represents something significant that has happened within a specific Bounded Context.

  • Named in the past tense to indicate that they have already occurred.

Domain Event Examples
  • OrderPlaced

  • ProductShipped

  • CustomerRegistered

Events capture meaningful changes in the domain and provide a clear historical record of what has happen.

Events between Aggregates

domain model ordering microservice
Figure 1. Using domain events to achieve consistency between different aggregates within the same domain

Image from Microsoft Learn

Benefits of Identifying Domain Events

  1. Reduces coupling

    • Events, allow decoupling different parts of your system.

  2. Audit Trails and Debugging

    • Domain Events serve as an audit trail of everything that has happened in your system.

  3. Scalability

    • In a distributed system or microservices architecture, Domain Events are instrumental.

Events between Microservices

aggregate domain event handlers
Figure 2. Management of multiple actions by domain

Image from Microsoft Learn

Implementing Events in Java

public abstract class Event implements Serializable {
    private static final long serialVersionUID = 1L
    public final UUID id = UUID.randomUUID();
    public final Date created;

    public Event() {
        this.created = new Date();
    }
}

Event Sourcing

Event Sourcing
  • New way of persisting application state as an ordered sequence of events.

  • The application can selectively query these events and reconstruct the state of the application at any point in time.

  • To make this work, we need to represent every change to the state of the application as events

Event Sourcing

Image from Baeldung

Event are Facts

  • Events here are facts that have happened and can not be altered: they must be immutable.

    • Recreating the application state is just a matter of replaying all the events.



This also opens up the possibility to replay events selectively, replay some events in reverse, and much more.
As a consequence, we can treat the application state itself as a secondary citizen, with the event log as our primary source of truth.

Command Query Responsibility Segregation (CQRS)

CQRS
  • About segregating the command and query side of the application architecture.

  • Based on the Command Query Separation (CQS) principle which was suggested by Bertrand Meyer.

  • CQS suggests that we divide the operations on domain objects into two distinct categories: Queries and Commands


  • Queries return a result and do not change the observable state of a system.

  • Commands change the state of the system but do not necessarily return a value.

Achieving Segregation

CQRS
Figure 3. CQRS

Image from Baeldung

  • We achieve this by cleanly separating the Command and Query sides of the domain model.

  • We can take a step further, splitting the write and read side of the data store as well, of course, by introducing a mechanism to keep them in sync.

A Simple Application

A Simple Application
Figure 4. A Simple Application

CRUD Repository

Diagram

Problems with this Approach

  • Same domain model for read and write operations

  • Only the last state is persisted

Introducing CQRS

CQRS in Application 3
Figure 5. CQRS in Application

Image from Baeldung

Implementing Commands

User Commands
Figure 6. User Commands

Implementing the Aggregate

The User Aggregate
Figure 7. The User Aggregate

Implementing Queries

Diagram

Query Domain Model

Diagram

The Query Repository

Diagram

The User Projection

Diagram

Synchronizing Read and Write Data

Diagram
Diagram

Benefits and Drawbacks of CQRS

Benefits
  • Provides a convenient way to select separate domain models appropriate for write and read operations;

    • We don’t have to create a complex domain model supporting both

  • Helps to select repositories that are individually suited for handling the complexities of the read and write operations, like high throughput for writing and low latency for reading

  • Naturally complements event-based programming models in a distributed architecture by providing a separation of concerns as well as simpler domain models

Benefits and Drawbacks of CQRS

Drawbacks
  • Only a complex domain model can benefit from the added complexity of this pattern; a simple domain model can be managed without all this

  • Naturally leads to code duplication to some extent, which is an acceptable evil compared to the gain it leads us to; however, individual judgment is advised

  • Separate repositories lead to problems of consistency, and it’s difficult to keep the write and read repositories in perfect sync always; we often have to settle for eventual consistency

Introducing Event Sourcing

  • Dramatically changes the way we think of the application state storage.

ES in Application 3

Image from Baeldung

Implementing Events and Event Store

Diagram

The Event Store

Diagram
There are several in-memory databases to handle domain events, e.g. Apache Druid, Apache Kafka, or Apache Cassandra.

Generating and Consuming Events

The User Service
Figure 8. The User Service

User Creation

Diagram

User Update

Diagram

Benefits and Drawbacks of Event Sourcing

Benefits
  • Makes write operations much faster as there is no read, update, and write required; write is merely appending an event to a log

  • Removes the object-relational impedance and, hence, the need for complex mapping tools; of course, we still need to recreate the objects back

  • Happens to provide an audit log as a by-product, which is completely reliable; we can debug exactly how the state of a domain model has changed

  • It makes it possible to support temporal queries and achieve time-travel (the domain state at a point in the past)!

  • It’s a natural fit for designing loosely coupled components in a microservices architecture that communicate asynchronously by exchanging messages

Benefits and Drawbacks of Event Sourcing

Drawbacks
  • There’s a learning curve associated and a shift in mindset required to adopt event sourcing; it’s not intuitive, to begin with

  • It makes it rather difficult to handle typical queries as we need to recreate the state unless we keep the state in the local cache

  • Although it can be applied to any domain model, it’s more appropriate for the event-based model in an event-driven architecture

CQRS with Event Sourcing

ES CQRS in Application 3

Image from Baeldung

Bringing CQRS and Event Sourcing Together

  • We already implemented:

    • CQRS and

    • Event Sourcing

  • Now, we can put things together:

    • The Aggregate generates Events

    • The Projector processes events instead of Domain Object instances

Adapting the Aggregate for Event Sourcing

The New User Aggregate
Figure 9. The New User Aggregate

User Creation

Diagram
Now, the Aggregate generates events

Adapting the User Projector for Event Sourcing

Diagram

Conclusion

CQRS

Use different repositories for writing and querying models

Event Sourcing

Persist models as a sequence of events


  • Not adapted for simple domain models, like the User/Address/Contact example

  • Benefits only appear for reasonably complex domain models