Session: Event Sourcing Applicative Profunctors - Jeremy Chassaing

February 4th, 2021

Session: Event Sourcing Applicative Profunctors - Jeremy Chassaing

 

Event Sourcing in function programming

 

 

no description for image available

 

no description for image available

 

decide

no description for image available

 

pure function, immutable objects

 

evolve

no description for image available

takes 1 event

applies it to the state

 

Link it together

no description for image available

 

---

 

initial state

no description for image available

 

---

 

now we have Event Sourcing

 

command: only what is needed to 'decide'

event: only what is needed to 'evolve'

 

cf Aggregate

 

Take any aggregate, and it has enough information to run, without needing external data

-we can rewrite any aggregate to this

-without needing external data

 

---

Decider

 

no description for image available

decide: command -> event[] -> event[]

 

Decider

composed of 6 things

no description for image available

 

-Command

-Event

-State (list of events, or denormalized)

-decide : Cmd -> State -> Event[]

-evolve: State -> Event -> State

-initialState: State

 

-isTerminal: State -> bool

# sometimes you want to end (suggested)

eg "close the books, and start a new fiscal year"

 

---

Easy way

 

load state

evolve state

save state

log / persist events

-not used for continual state

-used when big state changes (maintenance)

 

performance: only load&save every 10 events

 

---

 

"progressive way of event sourcing"

 

no assumptions about

- what command is

- what event is

- what decide is

- what evolve is

 

---

Communicate outside aggregate boundary

 

example domain: todo-list

 

Bad pattern:

no description for image available

state is 'todo list'

 

"I can't use this, I need to save events I get from the outside"

 

Eventstore: events in exact order

CosmoDB: partitions are not ordered

-> need to save the order in which you noticed the events

 

no description for image available

External events

Ingest

InternalEvents

evolve

state

 

if external source is ordered, no need to save 'internal events'

if not ; you need to save internal events

 

React

no description for image available

state + drift : Event

 

no description for image available

if empty drift (drift is optional)

returns all commands that need to happen

(to recover from crash?)

 

no description for image available

initial state + isTerminal (to check if state needs to be cleaned up)

 

Process

no description for image available

 

---

 

 

no description for image available

Actor --> Process

 

---

 

Aggregate: inside needs to be consistent

no description for image available

smaller boundary = better!

 

no description for image available

outside does not have to be consistent, but can be

 

no description for image availableno description for image available

we can split it whenever we want

but we can combine them for now

(as long as we don't make connections between them that make it impossible to split them later)

 

---

 

Example: Game Uno

no description for image available

Game

Hand 1

Hand 2

Hand 3

Stockpile

 

V1, everything async would be overkill

no description for image available

 

---

 

Functor

you can have a select or map operation

so that

if you have a function A:string -> B:int

list of strings -> list of int

 

---

 

Co-variant functor

function A -> B

F<A> -> F<B>

 

select / map : (f : a -> b)  (List<a>) = List<b>

no description for image available

 

c -> (state -> eventlist)

is incompatible with

c-> d

 

no description for image availableno description for image available

decide

f

 

no description for image available

compose a function that takes d

 

no description for image available

Game (GameCommand)

StockPile (stockpileCommand)

Hands ()

 

no description for image available

-> some ?? -> GameDecider

-> some ?? -> StockpileDecider

 

or if none -> empty list

 

---

 

no description for image available

GameEvent

StockpileEvent

...

 

 

no description for image available

-> some -> evolve Event + State

-> None

 

no description for image available

GameDecicer -> GameEvent -> GameEvent

StockpileDecicer -> StockpileEvent -> StockpileEvent

no description for image available

 

---

 

no description for image available

Commandx, Eventx, ?x, dx, ec, initialStatex, isTerminalx

 

no description for image available

 

 

no description for image available

 

Make a pair of both states

no description for image available

 

no description for image available

Cx -> DecideX Cx StateX |> map Eventx

Cy -> Decide of Cy StateY |> map EventY

 

no description for image available

evolve: E S ->

match E with

| Event for x -> evolve EventForX StateX EventForX |>

{s with x = evolve EventForX StateX }

 

---

 

no description for image available

 


 

>

> at this point I dropped off, next session was starting

>

This post was referenced in: