Skip to content

Commands

Modules: occurrent-command-composition

A command is used to represent an intent in an event sourced system, i.e. something that you want to do. They’re different, in a very important way, from events in that commands can fail or be rejected, where-as events cannot. A typical example of a command would be a data structure whose name is defined as an imperative verb, for example PlaceOrder. The resulting event, if the command is processed successfully, could then be OrderPlaced. However, in Occurrent, as explained in more detail in the Command Philosophy section below, you may start off by not using explicit data structures for commands unless you want to. In Occurrent, you can instead use pure functions to represent commands and command handling. Combine this with function composition and you have a powerful way to invoke the domain model (refer to the application service for examples).

Occurrent doesn’t contain a built-in command bus. Instead, you’re encouraged to pick any infrastructure component you need to act as the command bus to send commands to another service. Personally, I typically make a call to a REST API or make an RPC invocation instead of using a distributed command bus that routes the commands to my aggregate. There are of course exceptions to this, such as the need for location transparency or if you’re using Deciders. If you need location transparency, a command bus or an actor model can be of help. But I would argue that you may not always need the complexity by prematurely going down this route if your business requirements doesn’t point you in this direction. Deciders are a nice alternative, that doesn’t require any additional infrastructure.

But what about internally? For example if a service exposes a REST API and upon receiving a request it publishes a command that’s somehow picked up and routed to a function in your domain model. This is where an application service becomes useful. However, let’s first explore the rationale behind the philosophy of Occurrent. In other frameworks, it’s not uncommon that you define your domain model like this:

public class WordGuessingGame extends AggregateRoot {
@AggregateId
private String gameId;
private String wordToGuess;
@HandleCommand
public void handle(StartNewGameCommand startNewGameCommand) {
// Insert some validation and logic
...
// Publish an event using the "publish" method from AggregateRoot
publish(new WordGuessingGameWasStartedEvent(...));
}
@HandleCommand
public void handle(GuessWordCommand guessWordCommand) {
// Some validation and implementation ...
...
// Publish an event using the "publish" method from AggregateRoot
publish(new WordGuessedEvent(...));
}
@HandleEvent
public void handle(WordGuessingGameWasStartedEvent e) {
this.gameId = e.getGameId();
this.wordToGuess = e.getWordToGuess();
}
...
}

Let’s look at a “command” and see what it typically looks like in these frameworks:

public class StartNewGameCommand {
@AggregateId
private String gameId;
private String wordToGuess;
public void setGameId(String gameId) {
this.gameId = gameId;
}
public String getGameId() {
return gameId;
}
public void setWordToGuess(String wordToGuess) {
this.wordToGuess = wordToGuess;
}
public String getWordToGuess() {
return wordToGuess;
}
// Equals/hashcode/tostring methods are excluded for brevity
}

Now that we have our WordGuessingGame implementation and a command we can dispatch it to a command bus:

commandbus.dispatch(new StartNewGameCommand("someGameId", "Secret word"));

From a typical Java perspective one could argue that this is not too bad. But it does have a few things one could improve upon from a broader perspective:

  1. The WordGuessingGame is complecting several things that may be modelled separately. Data, state, behavior, command- and event routing and event publishing are all defined in the same model (the WordGuessingGame class). It also uses framework specific annotations, classes and inheritance inside your domain model which is something you want to avoid. For small examples like this it arguably doesn’t matter, but if you have complex logic and a large system, it probably will in my experience. Keeping state and behavior separate allows for easier testing, referential transparency and function composition. It allows treating the state as a value which has many benefits.
  2. Commands are defined as explicit data structures with framework-specific annotations when arguably they don’t have to. This is fine if you need to serialize the command (in order to send it to another location or to schedule it for the future) but one could argue that you don’t want to couple your commands to some infrastructure. This is of course a trade-off, in Occurrent you’re free to choose any approach you like (i.e. commands/functions can be completely free of framework/library/infrastructure concerns).

So how would one dispatch commands in Occurrent? As we’ve already mentioned there’s nothing stopping you from using a (distributed) command bus or to create explicit commands, and dispatch them the way we did in the example above. For example, if you’re using Deciders, it could be nice to have commands explicitly defined. But if you recognize some of the points described above and are looking for a simpler approach, here’s another way to go about. First let’s refactor the domain model to pure functions, without any state or dependencies to Occurrent or any other library/framework.

public class WordGuessingGame {
public static List<DomainEvent> startNewGame(String gameId, String wordToGuess) {
...
}
public static List<DomainEvent> guessWord(List<DomainEvent> eventStream, String word) {
...
}
}

If you define your behavior like this it’ll be easy to test (and also to compose using normal function composition techniques). There are no side-effects (such as publishing events) which also allows for easier testing and local reasoning.

But where are our commands!? In this example we’ve decided to represent them as functions. I.e. the “command” is modeled as simple function, e.g. startNewGame! This means that the command handling logic is handled by function as well. You don’t need to switch/match over the command since you directly invoke the function itself. Again, you may prefer to actually define your commands explicitly, but in this example we’ll just be using normal functions.

But wait, how are these functions called? Create or copy a generic ApplicationService class like the one below (or use the generic application service provided by Occurrent):

public class ApplicationService {
private final EventStore eventStore;
private final Function<CloudEvent, DomainEvent> convertCloudEventToDomainEvent;
private final Function<DomainEvent, CloudEvent> convertDomainEventToCloudEvent;
public ApplicationService(EventStore eventStore,
Function<CloudEvent, DomainEvent> convertCloudEventToDomainEvent,
Function<DomainEvent, CloudEvent> convertDomainEventToCloudEvent) {
this.eventStore = eventStore;
this.convertCloudEventToDomainEvent = convertCloudEventToDomainEvent;
this.convertDomainEventToCloudEvent = convertDomainEventToCloudEvent;
}
public void execute(String streamId, Function<List<DomainEvent>, List<DomainEvent>> functionThatCallsDomainModel) {
// Read all events from the event store for a particular stream
EventStream<CloudEvent> eventStream = eventStore.read(streamId);
// Convert the cloud events into domain events
List<DomainEvent> domainEventsInStream = eventStream.events().map(convertCloudEventToDomainEvent).toList();
// Call a pure function from the domain model which returns a List of domain events
List<DomainEvent> newDomainEvents = functionThatCallsDomainModel.apply(domainEventsInStream);
// Convert domain events to cloud events and write them to the event store
List<CloudEvent> newCloudEvents = newDomainEvents.stream().map(convertDomainEventToCloudEvent).toList();
eventStore.write(streamId, eventStream.version(), newCloudEvents);
}
}

and then use the ApplicationService like this:

// A function that converts a CloudEvent to a "domain event"
Function<CloudEvent, DomainEvent> convertCloudEventToDomainEvent = ..
// A function that a "domain event" to a CloudEvent
Function<DomainEvent, CloudEvent> convertDomainEventToCloudEvent = ..
EventStore eventStore = ..
ApplicationService applicationService = new ApplicationService(eventStore, convertCloudEventToDomainEvent, convertDomainEventToCloudEvent);
// Now in your REST API use the application service:
String gameId = ... // From a form parameter
String wordToGuess = .. // From a form parameter
applicationService.execute(gameId, events -> WordGuessingGame.startNewGame(gameId, wordToGuess));

We’re leveraging higher-order functions instead of using explicit commands.

Command Composition (Added in 0.2.0)

Section titled “Command Composition”

Many times it’s useful to compose multiple commands into a single unit-of-work for the same stream/aggregate. What this means that you’ll “merge” several commands into one, and they will be executed in an atomic fashion. I.e. either all commands succeed, or all commands fail.

While you’re free to use any means and/or library to achieve this, Occurrent ships with a “command composition” library that you can leverage:

<dependency>
<groupId>org.occurrent</groupId>
<artifactId>occurrent-command-composition</artifactId>
<version>0.34.0</version>
</dependency>

As an example consider this simple domain model:

public class WordGuessingGame {
public List<DomainEvent> startNewGame(List<DomainEvent> events, String gameId, String wordToGuess) {
// Implementation
}
public List<DomainEvent> makeGuess(List<DomainEvent> events, String guess) {
// Implementation
}
}

Imagine that for a specific API you want to allow starting a new game and making a guess in the same request. Instead of changing your domain model, you can use function composition! If you statically import composeCommands from org.occurrent.application.composition.command.ListCommandComposition you can do like this:

String gameId = ...
String wordToGuess = ...
String guess = ...
applicationService.execute(gameId, composeCommands(
events -> WordGuessingGame.startNewGame(events, gameId, wordToGuess),
events -> WordGuessingGame.makeGuess(events, guess)
));

If you’re using Kotlin you can also make use of the andThen (infix) function for command composition (import org.occurrent.application.composition.command.andThen):

applicationService.execute(gameId,
{ events -> WordGuessingGame.startNewGame(events, gameId, wordToGuess) }
andThen { events -> WordGuessingGame.makeGuess(events, guess) })

Events returned from WordGuessingGame.startNewGame(..) will be appended to the event stream when calling WordGuessingGame.makeGuess(..) and the new domain events returned by the two functions will be merged and written in an atomic fashion to the event store.

The command composition library also contains some utilities for partial function application that you can use to further enhance the example above (if you like). If you statically import partial method from org.occurrent.application.composition.command.partial.PartialFunctionApplication you can refactor the code above into this:

String gameId = ...
String wordToGuess = ...
String guess = ...
applicationService.execute(gameId, composeCommands(
partial(WordGuessingGame::startNewGame, gameId, wordToGuess),
partial(WordGuessingGame::makeGuess, guess)
));

With Kotlin, you can also use andThen (described above) to do:

applicationService.execute(gameId,
WordGuessingGame::startNewGame.partial(gameId, wordToGuess)
andThen WordGuessingGame::makeGuess.partial(guess))