Functional DDD in F#


After watching Greg Youngs presentation on Functional DDD (http://skillsmatter.com/podcast/design-architecture/ddd-functional-programming) I decided to give it a try using F#

I have to say I was sort of pleasantly surprised how well the entire concept works with a functional language.

This is only a spike on my part so don’t expect too much, but the code shows how Gregs ideas can be implemented using F#

//state for order line items
type LineItem =
    {
        Quantity : float;
        ProductId : int;
    }

//events that can be consumed by the order aggregate root
type OrderEvents =
    | Created of System.DateTime
    | RemovedItemId of int
    | ItemAdded of LineItem

type Order = 
    { //the order state 
        Id : int;
        CreatedDate : System.DateTime;
        Items : list<LineItem>;
    }

    //helper func to create new instances
    static member Create() = 
        { 
            Id = 1; 
            CreatedDate = System.DateTime.Now; 
            Items = []; 
        }

    //event handler, this consumes an event and uses it to construct a new version of the "this" argument
    static member Apply (this,event) = 
        match event with
        | Created(createdDate)      -> 
            {this with CreatedDate = createdDate; }
        | ItemAdded(item)           -> 
            {this with Items = item :: this.Items; }
        | RemovedItemId(productId)  -> 
            {this with Items = this.Items |> List.filter(fun i -> i.ProductId <> productId); }

    
    static member AddItem (productId,quantity) this =
        if quantity <= 0.0 then 
            failwith  "quantity must be a positive number"

        this,ItemAdded { Quantity = quantity; ProductId = productId; }
    
    static member RemoveProduct (productId) this =
        this,RemovedItemId(productId)

[<EntryPoint>]
let main argv =
    let o = Order.Create() 
            |> Order.AddItem (123,5.0) 
            |> Order.Apply
            |> Order.AddItem (555,3.0)
            |> Order.Apply
            |> Order.AddItem (22,2.2)
            |> Order.Apply 
            |> Order.RemoveProduct(123)
            |> Order.Apply

    //do stuff with the order
   

The idea here is that instead of using “Do” functions like Greg does, I use an “Apply” function wich consumes an event which is an F# discriminated union type.
The actual entity state is implemented using F# records, the apply function creates new versions of such record based on previous state and the consumed event.

4 thoughts on “Functional DDD in F#

  1. Thanks for the follow on Twitter!

    I’m really new to F# myself – I really wanted to pick up some more languages to put on my belt, and become more code agnostic; what better way than to pick up another paradigm as well!

    Thankfully I sit next to the author of “F# for Fun and Profit” (http://fsharpforfunandprofit.com/) at work, so I’ve an excellent resource available to me.

    In either case, just looking at your example – something that I’ve been pointed out is how to make some of that _even_more_ type safe. Something you might know, or not care about – so forgive me, but I’ll go ahead and write it anyway!

    Take the example of having Record types with an “Id” – instead of making Id type of int, you can create an even more basic type for Id which is int. So “Order.Id: OrderId”

    That way Order.Id can still = an int, but an Order.Id can never = LineItem.ProductId (which would be of type “ProductId”)… If you catch my drift. It may be overkill, but it _could_ help catch more issues at compile time rather than runtime.

  2. @Matt, I fully agree with the idea of an OrderId type, I’m simply too used with most O/R Mappers not supporting complex types as entity identity when designing my models.
    It would work perfect in this case.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s