Why F# ?
tldr; I wanted to implement Functional Event Sourcing, and needed a functional language for this. F#'s DSL oriented syntax proved useful on the way.
2014-08-10
Event Sourcing
Back in 2008, this thing called event sourcing started to draw my attention as I started to feel the limits of doing Domain Driven Design using an ORM.
Discussion after discussion on the DDD yahoo group with Greg Young and others; things started to make sense. But a lot of points remained a bit fuzzy.
Taking Greg's course in Paris made all this a lot clearer, but still I was not totally comfortable with the implementation. I put a first attempt in production and it's still running, but I was not totally OK with the result.
Then I met Rinat Abdullin, and we created #cqrsbeers in Paris. Rinat had a wonderfuly efficient implementation of Event Sourcing in C# locally or on Azure open sourced from the company he was working in at that time.
It was lean and mean, very inspiring, in production; and yet it was not enough.
Functional Event Sourcing
Then at Skillsmatter's DDDx 2013, Greg did a presentation about DDD Functional Programming. I was starting to learn F# at that time, and here things matched perfectly.
Functional event sourcing is defined around two functions:
The first one is in charge of deciding what's happening:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: |
|
Simple enough, and with immutable values, decide is a pure function without side effects.
Its signature indicates it's meaning:
1:
|
|
can be read as given my current state and what you ask me to do, here is what happens.
This is something that had always bugged me with OO Event Sourcing; you have to be careful not to mutate your state before building your events. But nothing prevents you from doing so and shooting yourself in the foot.
Then comes the event application function.
1: 2: 3: 4: |
|
Here again, a pure function without side effects.
The signature is :
1:
|
|
and can be read as given my current state and what happened, here is my new state
No risk of corruption of internal state if something bad happens during processing; all is immutable.
And rebuilding the current state is as easy as
1:
|
|
F#
So I started to try implementing Greg's SimpleCQRS sample in F# and could see that much of the pain went away, even if I was still a noob in F#.
A central aspect of F# is that it has a type system that eerily seems almost purpose-built for DDD. Have a look at Scott Wlaschin's presentation on DDD with F# and the associated series on his blog.
Another one is that F# has immutable and Non Null types by default.
It also has a DSLly feeling due to the low noise -- no curlies - and currying.
It's also a language that can be put into production on many platforms thanks to Xamarin.
All this combined together makes it a good way to implement Event Sourcing. It's robust, clean and fast. It's also a great way to teach Event Sourcing, even to people who don't speak F#.
I've done several presentations in F# in front of Java people - "You don't talk C# and I don't talk Java, let's do this in F# !" - and it was totally ok.
This being said, most of the things here can be applied outside of F# with possibly minor adjustments. If you find any, let's chat, and I can talk about it here.
val string : value:'T -> string
Full name: Microsoft.FSharp.Core.Operators.string
--------------------
type string = System.String
Full name: Microsoft.FSharp.Core.string
Full name: Why FSharp.State.empty
Full name: Why FSharp.Command
module Event
from Microsoft.FSharp.Control
--------------------
type Event = | SomethingHappened
Full name: Why FSharp.Event
--------------------
type Event<'T> =
new : unit -> Event<'T>
member Trigger : arg:'T -> unit
member Publish : IEvent<'T>
Full name: Microsoft.FSharp.Control.Event<_>
--------------------
type Event<'Delegate,'Args (requires delegate and 'Delegate :> Delegate)> =
new : unit -> Event<'Delegate,'Args>
member Trigger : sender:obj * args:'Args -> unit
member Publish : IEvent<'Delegate,'Args>
Full name: Microsoft.FSharp.Control.Event<_,_>
--------------------
new : unit -> Event<'T>
--------------------
new : unit -> Event<'Delegate,'Args>
Full name: Why FSharp.decide
module Event
from Microsoft.FSharp.Control
--------------------
type Event<'T> =
new : unit -> Event<'T>
member Trigger : arg:'T -> unit
member Publish : IEvent<'T>
Full name: Microsoft.FSharp.Control.Event<_>
--------------------
type Event<'Delegate,'Args (requires delegate and 'Delegate :> Delegate)> =
new : unit -> Event<'Delegate,'Args>
member Trigger : sender:obj * args:'Args -> unit
member Publish : IEvent<'Delegate,'Args>
Full name: Microsoft.FSharp.Control.Event<_,_>
--------------------
new : unit -> Event<'T>
--------------------
new : unit -> Event<'Delegate,'Args>
Full name: Microsoft.FSharp.Collections.list<_>
Full name: Why FSharp.apply
Full name: Why FSharp.replay
module List
from Microsoft.FSharp.Collections
--------------------
type List<'T> =
| ( [] )
| ( :: ) of Head: 'T * Tail: 'T list
interface IEnumerable
interface IEnumerable<'T>
member GetSlice : startIndex:int option * endIndex:int option -> 'T list
member Head : 'T
member IsEmpty : bool
member Item : index:int -> 'T with get
member Length : int
member Tail : 'T list
static member Cons : head:'T * tail:'T list -> 'T list
static member Empty : 'T list
Full name: Microsoft.FSharp.Collections.List<_>
Full name: Microsoft.FSharp.Collections.List.fold
{MyCurrentState: string;}
static member empty : State
Full name: Why FSharp.State