// thinkbeforecoding

SimpleCQRS the F# version

2012-06-21T21:57:27 / jeremie chassaing

Here it is ! As promised after greg’s talk at dddx  (you can already see all the presentations online !), a F# version of SimpleCQRS, a simple, quick EventSourcing + CQRS sample to see it in action.

 

Why rewrite it in F# ?

 

This is not just a simple copy of the C# version. The point was first to write it in a functional language, because event sourcing is inherently functional.

 

In C#, an aggregate method looks like this :

 

public void CheckIn(int count)
{
   if(count <= 0)
        throw new InvalidOperationException(
              "must have a count greater than 0 to add to inventory");
   ApplyChange(new ItemsCheckedInToInventory(_id, count));
}

 

The ApplyChange method is defined in the AggregateRoot base class.

It dispatches the event to a state denormalizer and add the Event to uncommitted changes.

 

Here is a denormalizer to apply a state change following an event :

 

private void Apply(InventoryItemDeactivated e)
{
   _activated = false;
}
 

 

All this is fine, but why should the aggregate be mutable when the event stream is highly a append only store of immutable events.

 

Watch greg’s talk carefully, both methods can be transformed to an immutable equivalent easily.

 

First the goal of the public method is to determine which event to raise based on command parameters and current state. The CheckIn method can be defined by the following method signature:

int –> State –> Event  or Func<int,State,Event>

 

Instead of calling an Apply change internally, the method simply returns an event :

 

let checkIn count s =
    if count <= 0 then
       raise (InvalidOperationException
           "must have a count greater than 0 to add to inventory")
       fire {ItemsCheckedInToInventory.Id= s.Id; Count = count}

 

where the fire function simply creates a Event array from a single event :

 

let fire o =
    [o :> Event]

(notice the [o:> smiley here !)

An array is returned here so that a method can fire/return several events using a simple :: syntax.

 

The state application can also become immutable. The function gives next state based on event and previous state :

 

State –> Event –> State or Func<State,Event,State>

 

let applyOnInventoryItem s (e: Event) =
   match e with
   | :? InventoryItemCreated as e -> {Id = e.Id; Activated = true }
   | :? InventoryItemDeactivated as e -> {s with Activated = false; }
   | _ –> s

no need for several methods here, every thing is straight forward. Match the event using its type.

The first event is a creation, so a state record is creates.

The second events copies state s with Activated set to false. No change occurs here, a copy is returned.

The _ match specifies that any other event simply return previous state.

 

Done.

 

The current state is a left fold of passed events

Sure and the replayWith method is simply here to do this :

 

let replayWith  =

    Seq.fold

let replayInventoryItem =

    replayWith applyOnInventoryItem { Id = Guid.Empty; Activated = false}

 

the replayInventoryItem is a function that takes a Event seq aka IEnumerable<Event>. It will start with the empty state, then for each event, call the applyOnInventoryItem function with previous state, current event, and iterate with new state.

 

The result is the current state.

 

Command handlers

The event handlers use the following functions :

 

let load id =
   eventStore.GetEventsForAggregate id |>
   replayInventoryItem

let save = eventStore.SaveEvents

let applyOn id version f =
   load id |>
   f |>
   save id version

load simply pass events for the aggregate with identifier id to the replayInventoryItem

save is simply a short cut for the event store SaveEvents method

applyOn loads an aggregate to current state, pass state to f, a function that returns an event seq, then save it to the event store.

 

Here is a sample of its use :

 

member x.Handle (c: CheckInItemsToInventory) =

   checkIn c.Count |>

   applyOn c.InventoryItemId c.OriginalVersion

The checkIn function actually expect an second State argument, it signature is int –> State –> Event seq

 

After passing the c.Count integer argument this is now a State –> Event seq function.

When passed to the applyOn function, the state issued from the load call will be passed to it, resulting in an Event seq that will be passed to the save function.

 

Conclusion

There are a few things to notice in this implementation.

  1. It is very short, much shorter that C# version.
  2. There is no InventoryItem class. The InventoryItem module contains a State record, the representation of the aggregate internal state, functions to determine raised events, and functions to determine next state based on previous state and event. No base class is needed for event dispatch and uncommitted event handling.
  3. There is no repository. Actually the load and save methods do what a repository does, but it’s so simple that no class is required.

I did not talk about the read model that is a bit less interesting here.