Slide 1

Slide 1 text

A Functional Foundation for Event Sourced Applications Photo by Tom Van Hoogstraten on Unsplash 1/24

Slide 2

Slide 2 text

Who am I? Renato Cavalcanti * Member of Lagom Team at Lightbend * Founder of BeScala, the Belgian Scala User Group * Author of Fun.CQRS [email protected] @renatocaval Reactive Summit, Austin, 2017 2/24

Slide 3

Slide 3 text

Before we start... What we are going to see is not an implementation. We are going to analyse some functions and types at a higher level. Reactive Summit, Austin, 2017 3/24

Slide 4

Slide 4 text

Event Sourcing, CQRS and DDD Reactive Summit, Austin, 2017 4/24

Slide 5

Slide 5 text

Event Sourcing, CQRS and DDD — Event Sourcing happens when you store every single domain event. Reactive Summit, Austin, 2017 4/24

Slide 6

Slide 6 text

Event Sourcing, CQRS and DDD — Event Sourcing happens when you store every single domain event. — CQRS is only about having two models, write and read models. Reactive Summit, Austin, 2017 4/24

Slide 7

Slide 7 text

Event Sourcing, CQRS and DDD — Event Sourcing happens when you store every single domain event. — CQRS is only about having two models, write and read models. — Aggregate is a term borrowed from DDD and very often used as synonym to write-model Reactive Summit, Austin, 2017 4/24

Slide 8

Slide 8 text

The Functions // Command handler validates and emits events Aggregate => Command => Seq[Event] Reactive Summit, Austin, 2017 5/24

Slide 9

Slide 9 text

The Functions // Command handler validates and emits events Aggregate => Command => Seq[Event] // Event handler applies an event on the Aggregate Aggregate => Event => Aggregate Reactive Summit, Austin, 2017 6/24

Slide 10

Slide 10 text

The Functions // Command handler validates and emits events Aggregate => Command => Seq[Event] // Event handler applies an event on the Aggregate Aggregate => Event => Aggregate // why not this one instead? Aggregate => Command => (Aggregate, Seq[Event]) Reactive Summit, Austin, 2017 7/24

Slide 11

Slide 11 text

A Command emits zero, one or more events, but it can also be rejected // Command handler wraps Events in F[G[_]] Aggregate => Command => F[G[Event]] // Event handler Aggregate => Event => Aggregate Reactive Summit, Austin, 2017 8/24

Slide 12

Slide 12 text

Understanding F[G[Event]] — F is a Context that can express success or failure — G is a Context that can express quantity (zero, one or more) For example... Aggregate => Command => Try[Seq[Event]] // F = Try, G = Seq Reactive Summit, Austin, 2017 9/24

Slide 13

Slide 13 text

Understanding F[G[Event]] — F is a Context that can express success or failure — G is a Context that can express quantity (zero, one or more) But if I want to emit one single Event and express the fact that it always succeeds? Reactive Summit, Austin, 2017 10/24

Slide 14

Slide 14 text

Understanding F[G[Event]] — F is a Context that can express success or failure — G is a Context that can express quantity (zero, one or more) type Id[T] = T Aggregate => Command => Id[Id[Event]] // F = Id, G = Id Aggregate => Command => Event Aggregate => Command => Id[Seq[Event]] // F = Id, G = Seq Aggregate => Command => Seq[Event] Reactive Summit, Austin, 2017 11/24

Slide 15

Slide 15 text

Understanding F[G[Event]] — F is a Context that can express success or failure — G is a Context that can express quantity (zero, one or more) Aggregate => Command => Try[Id[Event]] // F = Try, G = Id Aggregate => Command => Try[Event] Aggregate => Command => Try[Option[Event]] // F = Try, G = Option Aggregate => Command => Try[Seq[Event]] // F = Try, G = Seq Reactive Summit, Austin, 2017 12/24

Slide 16

Slide 16 text

Understanding F[G[Event]] — F is a Context that can express success or failure — G is a Context that can express quantity (zero, one or more) type Error = String type Result[T] = Either[Error, T] Aggregate => Command => Result[Id[Event]] // F = Result, G = Id Aggregate => Command => Result[Option[Event]] // F = Result, G = Option Aggregate => Command => Result[Seq[Event]] // F = Result, G = Seq Reactive Summit, Austin, 2017 13/24

Slide 17

Slide 17 text

Different Contexts Different Commands may require different Fs and Gs type Id[T] = T case class Account(balance: Double) Account => Deposit => Id[Id[Deposited]] // F = Id, G = Id Account => Deposit => Deposited Account => Withdraw => Try[Id[Withdrawn]] // F = Try, G = Id Account => Withdraw => Try[Withdrawn] Reactive Summit, Austin, 2017 14/24

Slide 18

Slide 18 text

In the beginning, there is None type State = Option[Aggregate] // Command handler State => Command => F[G[Event]] // Event handler State => Event => State Reactive Summit, Austin, 2017 15/24

Slide 19

Slide 19 text

An Aggregate aggregates its past type History = Seq[Event] // all events since the seed-event type State = Option[Aggregate] Reactive Summit, Austin, 2017 16/24

Slide 20

Slide 20 text

An Aggregate aggregates its past type History = Seq[Event] // all events since the seed-event type State = Option[Aggregate] — when History == Seq.empty then Option[Aggregate] == None Reactive Summit, Austin, 2017 16/24

Slide 21

Slide 21 text

An Aggregate aggregates its past type History = Seq[Event] // all events since the seed-event type State = Option[Aggregate] — when History == Seq.empty then Option[Aggregate] == None — when History != Seq.empty then Option[Aggregate] == Some[Aggregate] Reactive Summit, Austin, 2017 16/24

Slide 22

Slide 22 text

An Aggregate aggregates its past type History = Seq[Event] // all events since the seed-event type State = Option[Aggregate] — when History == Seq.empty then Option[Aggregate] == None — when History != Seq.empty then Option[Aggregate] == Some[Aggregate] — given any History and a Event Handler we can foldLeft over the past events and rebuild the Aggregate. Reactive Summit, Austin, 2017 16/24

Slide 23

Slide 23 text

An Aggregate aggregates its past type History = Seq[Event] type State = Option[Aggregate] val eventHandler: State => Event => State = ... val pastEvents: History = ... pastEvents.foldLeft(None:State) { (agg, evt) => eventHandler(agg)(evt) } Reactive Summit, Austin, 2017 17/24

Slide 24

Slide 24 text

Being Opinionated Those are the foundation functions, but you may implement them in many different forms according to your own style, taste and/or constraints. Reactive Summit, Austin, 2017 18/24

Slide 25

Slide 25 text

Being Opinionated Option[Aggregate] => Command => F[G[Event]] Option[Aggregate] => Event => Option[Aggregate] // We can split the functions () => Command => F[G[Event]] Aggregate => Command => F[G[Event]] () => Event => Aggregate Aggregate => Event => Aggregate Reactive Summit, Austin, 2017 19/24

Slide 26

Slide 26 text

Being Opinionated Option[Aggregate] => Command => F[G[Event]] Option[Aggregate] => Event => Option[Aggregate] // Or decide to always have a default initial state val initialState: Aggregate = ... Aggregate => Command => F[G[Event]] Aggregate => Event => Aggregate Reactive Summit, Austin, 2017 20/24

Slide 27

Slide 27 text

Being Opinionated Option[Aggregate] => Command => F[G[Event]] Option[Aggregate] => Event => Option[Aggregate] // initial state + exception throwing Aggregate => Command => Event Aggregate => Command => Seq[Event] Aggregate => Event => Aggregate Reactive Summit, Austin, 2017 21/24

Slide 28

Slide 28 text

Event Sourcing is about persistence, no? Those functions are not expressing in any way how events are persisted. Or how they are replayed. That's made on purpose. Reactive Summit, Austin, 2017 22/24

Slide 29

Slide 29 text

Event Sourcing is about persistence, no? Those functions are not expressing in any way how events are persisted. Or how they are replayed. That's made on purpose. — we must read events from journal to reconstruct State Reactive Summit, Austin, 2017 22/24

Slide 30

Slide 30 text

Event Sourcing is about persistence, no? Those functions are not expressing in any way how events are persisted. Or how they are replayed. That's made on purpose. — we must read events from journal to reconstruct State — we must persist events before continue Reactive Summit, Austin, 2017 22/24

Slide 31

Slide 31 text

Event Sourcing is about persistence, no? Those functions are not expressing in any way how events are persisted. Or how they are replayed. That's made on purpose. — we must read events from journal to reconstruct State — we must persist events before continue — we may want to save snapshots to avoid replaying from scratch each time Reactive Summit, Austin, 2017 22/24

Slide 32

Slide 32 text

Event Sourcing is about persistence, no? Those functions are not expressing in any way how events are persisted. Or how they are replayed. That's made on purpose. — we must read events from journal to reconstruct State — we must persist events before continue — we may want to save snapshots to avoid replaying from scratch each time — we guarantee consistency in case of concurrent access Reactive Summit, Austin, 2017 22/24

Slide 33

Slide 33 text

Event Sourcing is about persistence, no? Those functions are not expressing in any way how events are persisted. Or how they are replayed. That's made on purpose. — we must read events from journal to reconstruct State — we must persist events before continue — we may want to save snapshots to avoid replaying from scratch each time — we guarantee consistency in case of concurrent access — we may want to distribute the aggregates over different nodes and keep the same consistency guarantees Reactive Summit, Austin, 2017 22/24

Slide 34

Slide 34 text

Takeaways Reactive Summit, Austin, 2017 23/24

Slide 35

Slide 35 text

Takeaways — We need informed opinions. We must understand the foundation functions so we can choose what to expose and how to expose. Reactive Summit, Austin, 2017 23/24

Slide 36

Slide 36 text

Takeaways — We need informed opinions. We must understand the foundation functions so we can choose what to expose and how to expose. — The closest we are to the foundation, the more options we have. Reactive Summit, Austin, 2017 23/24

Slide 37

Slide 37 text

Takeaways — We need informed opinions. We must understand the foundation functions so we can choose what to expose and how to expose. — The closest we are to the foundation, the more options we have. — Not offering options is not bad in itself. It's a design decision. Reactive Summit, Austin, 2017 23/24

Slide 38

Slide 38 text

Takeaways — We need informed opinions. We must understand the foundation functions so we can choose what to expose and how to expose. — The closest we are to the foundation, the more options we have. — Not offering options is not bad in itself. It's a design decision. — We should free ourselves from everything that is not domain related. This should be provided by libraries/frameworks. Reactive Summit, Austin, 2017 23/24

Slide 39

Slide 39 text

Thank You [email protected] @renatocaval Photo by Janko Ferlič on Unsplash 24/24