Skip to content

Latest commit

 

History

History
360 lines (215 loc) · 6.93 KB

workshop.md

File metadata and controls

360 lines (215 loc) · 6.93 KB
type tags
slide
dddeurope

Domain modelling with state machines


Who am I?

Marco Perone

@marcoshuttle

marcosh.github.io

working at Tweag


Working environment

We will be using Gitpod

https://github.com/marcosh/ddd-machines-dddeurope


Domain modelling


the picture that explains everything


Domain events

event

Events relevant for domain experts


Commands

command

User intentions/actions/decisions


Read models

read model

Data needed in order to make decisions


Aggregates

aggregate

Decide what happens on commands


Policies

policy

Reactive logic that takes place after an event


Projections

projection

Aggregate data from events


State machines


Mealy machines

data Mealy state input output = Mealy
  { initialState :: state
  , action :: state -> input -> (state, output)
  }

Mealy machine


Our domain


Risk management

We are building a lending application

We collect information about the user and the loan in order to decide wheter to grant the user the requested loan


Workflow

graph TD
  CollectUserData --> CollectLoanDetails
  CollectUserData --> QueryCreditBureau
  CollectLoanDetails --> AllDataCollected
  QueryCreditBureau --> AllDataCollected
Loading

Event storming

![Event storming](https://github.com/marcosh/ddd-machines-dddeurope/raw/main/images/event-storming.jpg =600x600)


Let's cook our ingredients together


Aggregates, projections and policies could be implemented as state machines


Aggregates

aggregate-command-event

From commands to events


Let's implement the aggregate for our domain


To compile the code and run the tests

stack test --file-watch

Events

data RiskEvent
  = UserDataRegistered UserData
  | LoanDetailsProvided LoanDetails
  | CreditBureauDataReceived CreditBureauData

Commands

data RiskCommand
  = RegisterUserData UserData
  | ProvideLoanDetails LoanDetails
  | ProvideCreditBureauData CreditBureauData

What is the state space?

data RiskState = _

Next we need to implement

action :: RiskState
       -> RiskCommand
       -> ([RiskEvent], RiskState)

and

initialState :: RiskState

Projections

projection-event-read-model

From events to read models


We want to project the received data, which could or could not be there

data ReceivedData = ReceivedData
  { userData         :: Maybe UserData
  , loanDetails      :: Maybe LoanDetails
  , creditBureauData :: Maybe CreditBureauData
  }

The projection is a state machine with RiskEvent as input and ReceivedData as output


What is the state space?


We can define it by implementing

action :: ReceivedData -> RiskEvent -> ReceivedData

and

initialState :: ReceivedData

Policies

policy-event-command

From events to commands


Policies are the only one allowing side effects


A policy is an effectful state machine with RiskEvent as inputs and RiskCommand as outputs.


Our policy needs to react to the UserDataRegistered event and send the data to the credit bureau, using the interactWithCreditBureau function


To implement it, we just need to implement

action :: RiskEvent -> IO [RiskCommand]

How do we connect the pieces, now?


Write side

feedback
  :: Mealy command [event]
  -> Mealy event   [command]
  -> Mealy command [event]

Allows us to combine Aggregate and Policy


Whole application

instance Category Mealy where
  (.) :: Mealy b c
      -> Mealy a b
      -> Mealy a c

Sequential composition

Allows us to compose Write and Read sides


Let's try to run it!

-- risk/Main.hs

main :: IO ()
main = print =<< runApplication riskManagerApplication
  [ RegisterUserData myUserData
  , ProvideLoanDetails myLoanDetails
  ]

To execute it

stack exec ddd-machines-dddeurope-risk

Requirements change

Suppose we want to add another projection

userDataUpdatesCounter :: Projection RiskEvent (Sum Int)

Let's adapt our application to incorporate it


We can use

(&&&) :: Projection a b
      -> Projection a c
      -> Projection a (b, c)

to run the two projections in parallel


Time for question and remarks


Thank you all!