Archive

Domain Driven Development

I posted this question.

The link above reflects a question that I had regarding how to enforce reliance on a function to create a value for a client.

The solution is to have the client rely on Active Patterns that’s publicly exposed while maintaining the privacy of the Discriminated Union type. This will prevent a client from creating a value of it explicitly.

Here’s the solution:

namespace Mynamespace

[<AutoOpen>]
module File1 =

    type EmailAddress = 
        private
        | Valid   of string 
        | Invalid of string

    let createEmailAddress (address:string) =
        if   address.Length > 0
        then Valid   address 
        else Invalid address

    let (|Valid|Invalid|) = function
        | Valid   input -> Valid   input
        | Invalid input -> Invalid input

module File2 =

    let result = createEmailAddress "XXX" |> function
                 | Valid    email -> true
                 | Invalid  email -> false

Intro



I have been studying Event Sourcing recently and would like to document my understanding. As I understand, Event Sourcing is a technique used as an alternative to a CRUD (i.e. Create, Read, Update, Delete) model. I would like to think of event sourcing as a ledger for recording code execution that ultimately hydrates an aggregate (aka: business entity) into existence. This is an interesting concept because this technique enables a business to observe each event that contributed to the actual state of an aggregate. The events that influence an aggregate’s state is called an Event Stream. An event stream is a set of ordered events that can be “played” to generate an aggregate’s state.

Domain

As I understand, Event Sourcing is an architecture that is reflected within the domain module of an enterprise system. I have attempted to learn Event Sourcing by building a sample banking account program.

The domain is the following:

namespace Domain

module Account =

    (*Types*)    
    type AccountId = AccountId of string
    type FirstName = FirstName of string
    type LastName =  LastName  of string

    type Credentials = { UserId:string; Password:string }

    type Account = {
         AccountId: AccountId
         FirstName: FirstName
         LastName:  LastName
         Balance:   decimal  }

    and Event = 
        | LoggedIn  of Credentials
        | Deposited of balance: decimal
        | Withdrew  of balance: decimal

    (*Functions*)
    let emptyAccount = {
         AccountId= AccountId ""
         FirstName= FirstName ""
         LastName=  LastName  ""
         Balance=   0.00m }

    let getAccount credentials = {
        AccountId= AccountId "myAccountId"
        FirstName= FirstName "Scott"
        LastName= LastName   "Nimrod"
        Balance=  0.00m                    }

    let update = function
        | account , LoggedIn  credentials ->   getAccount credentials
        | account , Deposited balance     -> { account with Balance = account.Balance + balance }
        | account , Withdrew  balance     -> { account with Balance = account.Balance - balance }

    let nextUpdate account event = update (account , event)

Client

I wrote a client to interact with the domain by supplying the domain with a set of events that influences an aggregate’s state.

The client is the following:

    (*Client*)
    let credentials = { UserId="Bizmonger"; Password="MyPassword" }
    let account =       credentials |> getAccount 
    let events =
        [
            LoggedIn  credentials
            Deposited 1000m
            Deposited 5000m
            Withdrew  500m
        ]

    let hydratedAccount = (emptyAccount , events) 
                          ||> List.fold nextUpdate

Replaying events via a fold of the events (i.e. hydratedAccount) is the following:

let hydratedAccount = (emptyAccount , events) 
                      ||> List.fold nextUpdate
> 

val hydratedAccount : Account = {AccountId = AccountId "myAccountId";
                                 FirstName = FirstName "Scott";
                                 LastName = LastName "Nimrod";
                                 Balance = 5500.00M;}

> 

Conclusion

In conclusion, I attempted to document my understanding of Event Sourcing. The code that I provided is an example of how to hydrate an aggregate via an Event Stream. However, this post does not address how events actually get created within the system. I will attempt to address this in my next post.