# Domain modelling with state machines
---
## Who am I?
Marco Perone
[@marcoshuttle](https://twitter.com/marcoshuttle)
[marcosh.github.io](http://marcosh.github.io/)
working at [Tweag](https://www.tweag.io/)
---
## Working environment
We will be using [Gitpod](https://gitpod.io/#https://github.com/marcosh/ddd-machines-dddeurope)
https://github.com/marcosh/ddd-machines-dddeurope
---
## Domain modelling
---
![the picture that explains everything](http://marcosh.github.io/img/the-picture-that-explains-everything.png)
---
### <span style="color: orange">Domain events</span>
![event](https://github.com/marcosh/ddd-machines-dddeurope/raw/main/images/the-picture-that-explains-everything-event.png)
Events relevant for domain experts
---
### <span style="color: dodgerblue">Commands</span>
![command](https://github.com/marcosh/ddd-machines-dddeurope/raw/main/images/the-picture-that-explains-everything-command.png)
User intentions/actions/decisions
---
### <span style="color: lightyellow">Read models</span>
![read model](https://github.com/marcosh/ddd-machines-dddeurope/raw/main/images/the-picture-that-explains-everything-read-model.png)
Data needed in order to make decisions
---
### <span style="color: yellow">Aggregates</span>
![aggregate](https://github.com/marcosh/ddd-machines-dddeurope/raw/main/images/the-picture-that-explains-everything-aggregate.png)
Decide what happens on commands
---
### <span style="color: orchid">Policies</span>
![policy](https://github.com/marcosh/ddd-machines-dddeurope/raw/main/images/the-picture-that-explains-everything-policy.png)
Reactive logic that takes place after an event
---
### <span style="color: lightgreen">Projections</span>
![projection](https://github.com/marcosh/ddd-machines-dddeurope/raw/main/images/the-picture-that-explains-everything-projection.png)
Aggregate data from events
---
## State machines
---
### Mealy machines
```haskell
data Mealy state input output = Mealy
{ initialState :: state
, action :: state -> input -> (state, output)
}
```
![Mealy machine](https://upload.wikimedia.org/wikipedia/commons/b/b4/Mealy.png?1653382367553)
---
## 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
```mermaid
graph TD
CollectUserData --> CollectLoanDetails
CollectUserData --> QueryCreditBureau
CollectLoanDetails --> AllDataCollected
QueryCreditBureau --> AllDataCollected
```
---
### Event storming
![Event storming](https://github.com/marcosh/ddd-machines-dddeurope/raw/main/images/event-storming.jpg =600x600)
---
## Let's cook our ingredients together
---
## <span style="color: yellow">Aggregates</span>, <span style="color: lightgreen">projections</span> and <span style="color: orchid">policies</span> could be implemented as state machines
---
### <span style="color: yellow">Aggregates</span>
![aggregate-command-event](https://github.com/marcosh/ddd-machines-dddeurope/raw/main/images/the-picture-that-explains-everything-aggregate-command-event.png)
From <span style="color: dodgerblue">commands</span> to <span style="color: orange">events</span>
---
Let's implement the <span style="color: yellow">aggregate</span> for our domain
---
To compile the code and run the tests
```bash
stack test --file-watch
```
---
### Events
```haskell
data RiskEvent
= UserDataRegistered UserData
| LoanDetailsProvided LoanDetails
| CreditBureauDataReceived CreditBureauData
```
---
### Commands
```haskell
data RiskCommand
= RegisterUserData UserData
| ProvideLoanDetails LoanDetails
| ProvideCreditBureauData CreditBureauData
```
---
What is the state space?
```haskell
data RiskState = _
```
---
Next we need to implement
```haskell
action :: RiskState
-> RiskCommand
-> ([RiskEvent], RiskState)
```
and
```haskell
initialState :: RiskState
```
---
### <span style="color: lightgreen">Projections</span>
![projection-event-read-model](https://github.com/marcosh/ddd-machines-dddeurope/raw/main/images/the-picture-that-explains-everything-projection-event-read-model.png)
From <span style="color: orange">events</span> to <span style="color: lightyellow">read models</span>
---
We want to project the received data, which could or could not be there
```haskell
data ReceivedData = ReceivedData
{ userData :: Maybe UserData
, loanDetails :: Maybe LoanDetails
, creditBureauData :: Maybe CreditBureauData
}
```
---
The projection is a state machine with <span style="color: #c7254e">`RiskEvent`</span> as input and <span style="color: #c7254e">`ReceivedData`</span> as output
---
What is the state space?
---
We can define it by implementing
```haskell
action :: ReceivedData -> RiskEvent -> ReceivedData
```
and
```haskell
initialState :: ReceivedData
```
---
### <span style="color: orchid">Policies</span>
![policy-event-command](https://github.com/marcosh/ddd-machines-dddeurope/raw/main/images/the-picture-that-explains-everything-policy-event-command.png)
From <span style="color: orange">events</span> to <span style="color: dodgerblue">commands</span>
---
<span style="color: orchid">Policies</span> are the only one allowing side effects
---
A policy is an effectful state machine with <span style="color: #c7254e">`RiskEvent`</span> as inputs and <span style="color: #c7254e">`RiskCommand`</span> as outputs.
---
Our policy needs to react to the <span style="color: #c7254e">`UserDataRegistered`</span> event and send the data to the credit bureau, using the <span style="color: #c7254e">`interactWithCreditBureau`</span> function
---
To implement it, we just need to implement
```haskell
action :: RiskEvent -> IO [RiskCommand]
```
---
How do we connect the pieces, now?
---
## Write side
```haskell
feedback
:: Mealy command [event]
-> Mealy event [command]
-> Mealy command [event]
```
Allows us to combine <span style="color: yellow">Aggregate</span> and <span style="color: orchid">Policy</span>
---
## Whole application
```haskell
instance Category Mealy where
(.) :: Mealy b c
-> Mealy a b
-> Mealy a c
```
Sequential composition
Allows us to compose <span style="color: #c7254e">`Write`</span> and <span style="color: #c7254e">`Read`</span> sides
---
Let's try to run it!
```haskell
-- risk/Main.hs
main :: IO ()
main = print =<< runApplication riskManagerApplication
[ RegisterUserData myUserData
, ProvideLoanDetails myLoanDetails
]
```
---
To execute it
```bash
stack exec ddd-machines-dddeurope-risk
```
---
## Requirements change
Suppose we want to add another projection
```haskell
userDataUpdatesCounter :: Projection RiskEvent (Sum Int)
```
Let's adapt our application to incorporate it
---
We can use
```haskell
(&&&) :: 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!
{"metaMigratedAt":"2023-06-17T02:23:53.317Z","metaMigratedFrom":"YAML","title":"Domain modelling with state machines","breaks":true,"contributors":"[{\"id\":\"0893b955-bc9c-4ecc-b38c-6072b5bc1ecd\",\"add\":14980,\"del\":7881}]"}