I have been following the excellent BTW podcast and thinking a lot about CQRS and Event Sourcing. Inspired by Greg Youngs lecture on Functional Programming with DDD I have tried to distill what is the minimal things I need to implement an Aggregate with Event Sourcing in Java. In this blog post I will focus on the command side of things. The purpose here is to explain Event Sourcing in a way that is easy to understand without any unnecessary overhead.

If you want to get directly to the example code it is available at GitHub.

A simple domain

To start we need a minimal domain that is simple to understand, but still interesting enough to be challanging. Udi Dahan has said many times that CQRS should only be used in a collaborative domain. Since I really enjoy developing games a really simple game that came to mind was rock-paper-scissors.

To keep it really simple the game only has two commands:

Player 1: Create game and make first move

Player 2: Make move

The business rules:

The players of a game must be different

When the second player has moved no more moves can be made

When the second player has moved either it is a tie or one of the players is declared winner

I will save queries and projections for another time.

Overview

To implement command processing I need the following pieces:

Commands which request that something should happen, ie some state change

which request that something should happen, ie some state change Events which indicate that something has happened

which indicate that something has happened Aggregates that handles Commands and generates Events based on the current state

that handles Commands and generates Events based on the current state Event store which stores all events that has happened

which stores events that has happened Application services that receives Commands and routes it to the appropriate aggregate

I want all updates to the aggregate to be consistent, which I implement by processing all commands sent to an aggregate serially using optimistic locking. This is consistent with Eric Evans view of aggregates. In fact, the extent of the aggregate is defined by the amount of data that is updated consistently. A Command is always sent to a single Aggregate.

I have the following commands:

CreateGameCommand(UUID gameId, String playerEmail, Move move)

MakeMoveCommand(UUID gameId, String playerEmail, Move move)

CreateGameCommand always generate these events:

GameCreatedEvent(UUID gameId, String playerEmail)

MoveDecidedEvent(UUID gameId, String playerEmail, Move move)

MakeMoveCommand also generate a MoveDecidedEvent and depending who wins one of the following events is generated:

GameWonEvent(UUID gameId, String winnerEmail, String loserEmail)

GameTiedEvent(UUID gameId)

By using multiple events to describe what happens (for example GameCreated + MoveDecided) I separate how the events get produced from what has happened. In this way I can change the workflow of the commands without changing the events that get generated. For example, I could introduce a new command that only creates a game without making a move.

Code

Time for some code. Notice how each command is sent to a specific aggregate:

public interface Command { UUID aggregateId(); }

Commands are immutable data. I can of course add more validation of the input in the constructor. Notice how UUID is created by the one that is sending the command:

public class CreateGameCommand implements Command { public final UUID gameId; public final String playerEmail; public final Move move; public CreateGameCommand(UUID gameId, String playerEmail, Move move) { this.gameId = gameId; this.playerEmail = playerEmail; this.move = move; } @Override public UUID aggregateId() { return gameId; } }

This does not mean that the client is creating UUIDs. Instead it could be done in the REST API, for example like this using JAX-RS:

@POST public Response createGame(Move move, @Context UriInfo uriInfo) { String playerEmail = getCurrentUserEmail(); UUID gameId = UUID.randomUUID(); sendCommand(new CreateGameCommand(gameId, playerEmail, move)); return Response.created(pathToGame(gameId, uriInfo)); }

For events I currently have a simple marker interface:

public interface Event { }

The events are just immutable data:

public class GameCreatedEvent implements Event { public final UUID gameId; public final String playerEmail; public GameCreatedEvent(UUID gameId, String playerEmail) { this.gameId = gameId; this.playerEmail = playerEmail; } }

The aggregate implement handlers for commands that generate events. Notice that no state is modified!

public List extends Event> handle(CreateGameCommand c) { if (state != State.notStarted) throw new IllegalStateException(state.toString()); return Arrays.asList( new GameCreatedEvent(c.gameId, c.playerEmail), new MoveDecidedEvent(c.gameId, c.playerEmail, c.move)); }

The aggregate implement handlers for events that modify state. Notice that no validation is done! The event has happened and the aggregate must simply accept this fact:

public void handle(GameCreatedEvent e) { state = State.created; creatorEmail = e.playerEmail; }

For the command processing I have a very simple interface for the EventStore:

public interface EventStore { EventStream loadEventStream(UUID aggregateId); void store(UUID aggregateId, long version, List extends Event> events); }

An EventStream which is an immutable collection of events up until a specific version of an aggregate. The purpose of the version is to implement optimistic locking:

public interface EventStream extends Iterable { long version(); }

So far I have only implemented an in-memory event store.

The final piece of the puzzle is the Application Service that:

Load events for the event store

Instantiate a new aggregate

Applies all events on the aggregate

Sends the command to the aggregate

Store the new events

public void handle(Command command) throws Exception { EventStream eventStream = eventStore.loadEventStream(command.aggregateId()); Object target = newAggregateInstance(command); for (Event event : eventStream) { handle(target, event); } List events = handle(target, command); if (events != null && events.size() > 0) { eventStore.store(command.aggregateId(), eventStream.version(), events); } else { // Command generated no events } }

The handle methods are invoked using reflection. There are couple of nice things to notice here:

The Application Service can easily handle retries if there is a ConcurrentModificationException (optimistic lock violation) or in fact any other exception

Command processing can easily be done asynchrously

Command processing can be distributed and run concurrently since all shared state is within the Event Store

There are of course problems as well. For example always loading and applying all events for an aggregate could be a performance problem. I will write about immutability and caching some other time!

Analysis

That was all the pieces that are necesseary to implement Event Sourcing. Do you think it is a complex programming model? Well, lets have a look at the bulk of the business rules in the Game aggregate which are implemented when the opponent makes a move:

enum State { notStarted, created, completed; } private State state = State.notStarted; private String creatorEmail; private Move move; public List extends Event> handle(MakeMoveCommand c) { if (State.created != state) throw new IllegalStateException(state.toString()); if (creatorEmail.equals(c.playerEmail)) throw new IllegalArgumentException("Player already in game"); return Arrays.asList( new MoveDecidedEvent(c.gameId, c.playerEmail, c.move), makeEndGameEvent(c.gameId, c.playerEmail, c.move)); } private Event makeEndGameEvent(UUID gameId, String opponentEmail, Move opponentMove) { if (move.defeats(opponentMove)) { return new GameWonEvent(gameId, creatorEmail, opponentEmail); } else if (opponentMove.defeats(move)) { return new GameWonEvent(gameId, opponentEmail, creatorEmail); } else { return new GameTiedEvent(gameId); } }

Event processing must never fail since the events have happened:

public void handle(MoveDecidedEvent e) { move = e.move; } public void handle(GameWonEvent e) { state = State.completed; } public void handle(GameTiedEvent e) { state = State.completed; }

Notice the following things:

Because we are doing CQRS we only store state in the aggregate that we actually use for command procesing. For example, the opponent or winner is not stored.

The event processing is always trivial!

Implementing the command processing is not that difficult, only different. Instead of directly manipulating state we generate events.

Ok that was a long blog post! I’m planning to write more about projections, event storage, immutability and lots of other stuff. Let me know what you think so far!