30
EVENT SOURCING MICHAEL NEWTON @MAVNN LTD

EVENT SOURCING - sddconf.comsddconf.com/brands/sdd/library/Event_Sourcing.pdf · EVENT SOURCING Finally... EVENT SOURCING BASICS Store the domain events as "lists" (normally called

  • Upload
    others

  • View
    15

  • Download
    0

Embed Size (px)

Citation preview

Page 1: EVENT SOURCING - sddconf.comsddconf.com/brands/sdd/library/Event_Sourcing.pdf · EVENT SOURCING Finally... EVENT SOURCING BASICS Store the domain events as "lists" (normally called

EVENT SOURCINGMICHAEL NEWTON

@MAVNN LTD

Page 2: EVENT SOURCING - sddconf.comsddconf.com/brands/sdd/library/Event_Sourcing.pdf · EVENT SOURCING Finally... EVENT SOURCING BASICS Store the domain events as "lists" (normally called

MONOIDSErm... what?

Page 3: EVENT SOURCING - sddconf.comsddconf.com/brands/sdd/library/Event_Sourcing.pdf · EVENT SOURCING Finally... EVENT SOURCING BASICS Store the domain events as "lists" (normally called

SIMPLE RULESTake an operation (Op)Take a type ('T)Op : 'T -> 'T -> 'T (Closure)Op t1 (Op t2 t3) = Op (Op t1 t2) t3(Associativity)There is a t0 such that: Op t0 t1 = Op t1 t0 (Zero)

Page 4: EVENT SOURCING - sddconf.comsddconf.com/brands/sdd/library/Event_Sourcing.pdf · EVENT SOURCING Finally... EVENT SOURCING BASICS Store the domain events as "lists" (normally called

EXAMPLE 1 - INTEGER ADDITION1 + (2 + 3) = (1 + 2) + 3

1 + 0 = 0 + 1

Page 5: EVENT SOURCING - sddconf.comsddconf.com/brands/sdd/library/Event_Sourcing.pdf · EVENT SOURCING Finally... EVENT SOURCING BASICS Store the domain events as "lists" (normally called

EXAMPLE 2 - STRING CONCATINATION("Bob" + "Fred") + "Smith" = "Bob" + ("Fred" + "Smith")

"Bob" + "" = "" + "Bob"

Page 6: EVENT SOURCING - sddconf.comsddconf.com/brands/sdd/library/Event_Sourcing.pdf · EVENT SOURCING Finally... EVENT SOURCING BASICS Store the domain events as "lists" (normally called

POP QUIZ 1 - EMAIL SUCCESS COUNT1: 2: 3: 4: 5: 6: 7:

type EmailsSent = { SuccessCount : int FailCount : int }

let addEmailsSent es es' = { SuccessCount = es.SuccessCount + es'.SuccessCount FailCount = es.FailCount + es'.FailCount }

Monoid? Yes or no?

Page 7: EVENT SOURCING - sddconf.comsddconf.com/brands/sdd/library/Event_Sourcing.pdf · EVENT SOURCING Finally... EVENT SOURCING BASICS Store the domain events as "lists" (normally called

POP QUIZ 2 - MEANS1: 2: let mean (x : int) (y : int) = (float x + float y) / 2.0

Monoid? Yes or no?

Page 8: EVENT SOURCING - sddconf.comsddconf.com/brands/sdd/library/Event_Sourcing.pdf · EVENT SOURCING Finally... EVENT SOURCING BASICS Store the domain events as "lists" (normally called

FAIL!

Page 9: EVENT SOURCING - sddconf.comsddconf.com/brands/sdd/library/Event_Sourcing.pdf · EVENT SOURCING Finally... EVENT SOURCING BASICS Store the domain events as "lists" (normally called

MEANSNo closure: int -> int -> floatNot associative: mean 1 (mean 2 3) <> mean (mean 1 2) 3... even if you ignore the type error

Page 10: EVENT SOURCING - sddconf.comsddconf.com/brands/sdd/library/Event_Sourcing.pdf · EVENT SOURCING Finally... EVENT SOURCING BASICS Store the domain events as "lists" (normally called

BUT...1: 2: 3: 4: 5: 6: 7:

type MeanTracker = { Total : int Divisor : int }

let addMean mt mt' = { Total = mt.Total + mt'.Total Divisor = mt.Divisor + mt'.Divisor }

Page 11: EVENT SOURCING - sddconf.comsddconf.com/brands/sdd/library/Event_Sourcing.pdf · EVENT SOURCING Finally... EVENT SOURCING BASICS Store the domain events as "lists" (normally called

THAT'S GREAT......but why are we doing this?

BECAUSE LISTS.(or IEnumerable<'T>, if you're that way inclined)

Page 12: EVENT SOURCING - sddconf.comsddconf.com/brands/sdd/library/Event_Sourcing.pdf · EVENT SOURCING Finally... EVENT SOURCING BASICS Store the domain events as "lists" (normally called

REDUCEOF MAP/REDUCE FAME

1: 2: 3: 4: 5: 6: 7: 8: 9: 10:

let currentMean = [{ Total = 10; Divisor = 1 } { Total = 20; Divisor = 1 }] |> List.reduce addMean

// Some more data comes in... let newMean = [currentMean { Total = 15; Divisor = 1}] |> List.reduce addMean

Incremental and parallel processing are trivial

Page 13: EVENT SOURCING - sddconf.comsddconf.com/brands/sdd/library/Event_Sourcing.pdf · EVENT SOURCING Finally... EVENT SOURCING BASICS Store the domain events as "lists" (normally called

THIS COMPILES...1: 2: 3:

// No data yet... [] |> List.reduce addMean

Page 14: EVENT SOURCING - sddconf.comsddconf.com/brands/sdd/library/Event_Sourcing.pdf · EVENT SOURCING Finally... EVENT SOURCING BASICS Store the domain events as "lists" (normally called

PARTIAL FUNCTIONS ARE EVILA partial function is one that can't create a valid output forevery "valid" inputReduce is a partial function as it can't operate on emptylists

Page 15: EVENT SOURCING - sddconf.comsddconf.com/brands/sdd/library/Event_Sourcing.pdf · EVENT SOURCING Finally... EVENT SOURCING BASICS Store the domain events as "lists" (normally called

LET'S TURN IT UP TO ELEVEN

FOLD1: 2: 3:

// Still no data [] |> List.fold addMean { Total = 0; Divisor = 0 }

Page 16: EVENT SOURCING - sddconf.comsddconf.com/brands/sdd/library/Event_Sourcing.pdf · EVENT SOURCING Finally... EVENT SOURCING BASICS Store the domain events as "lists" (normally called

SUMMARY SO FARIf you have, or you can make a monoid:

You can always reduce lists down to a single summaryvalueYou can incrementally process the listFor (lots) more on monoids, read the series by ScottWlaschin

Page 17: EVENT SOURCING - sddconf.comsddconf.com/brands/sdd/library/Event_Sourcing.pdf · EVENT SOURCING Finally... EVENT SOURCING BASICS Store the domain events as "lists" (normally called

EVENT SOURCING?Nearly... but �rst!

Page 18: EVENT SOURCING - sddconf.comsddconf.com/brands/sdd/library/Event_Sourcing.pdf · EVENT SOURCING Finally... EVENT SOURCING BASICS Store the domain events as "lists" (normally called

GENERALISING FOLDaddMean had type: MeanTracker -> MeanTracker -> MeanTrackerBut the �rst parameter to fold has signature: 'State ->'T -> 'State

Page 19: EVENT SOURCING - sddconf.comsddconf.com/brands/sdd/library/Event_Sourcing.pdf · EVENT SOURCING Finally... EVENT SOURCING BASICS Store the domain events as "lists" (normally called

EXAMPLE "PROJECTION" FOLD1: 2: 3:

// Not a monoid operator - no closure let emailsSent total es = total + es.SuccessCount

Page 20: EVENT SOURCING - sddconf.comsddconf.com/brands/sdd/library/Event_Sourcing.pdf · EVENT SOURCING Finally... EVENT SOURCING BASICS Store the domain events as "lists" (normally called

INCREMENTAL SEND TOTALS! 1: 2: 3: 4: 5: 6: 7: 8: 9: 10:

let currentOutput = [{ SuccessCount = 10; FailCount = 0 } { SuccessCount = 22; FailCount = 1 }] |> List.fold emailsSent 0

// More emails get sent let newCurrentOutput = [{ SuccessCount = 112; FailCount = 2 } { SuccessCount = 100; FailCount = 5 }] |> List.fold emailsSent currentOutput

Page 21: EVENT SOURCING - sddconf.comsddconf.com/brands/sdd/library/Event_Sourcing.pdf · EVENT SOURCING Finally... EVENT SOURCING BASICS Store the domain events as "lists" (normally called

And then...

...the customer tells you they want to know the percentagefailure rate of sends. Preferably with historic data. And, of

course, live updates.

Page 22: EVENT SOURCING - sddconf.comsddconf.com/brands/sdd/library/Event_Sourcing.pdf · EVENT SOURCING Finally... EVENT SOURCING BASICS Store the domain events as "lists" (normally called

NO PROBLEM!1: 2: 3: 4:

// Remember our MeanTracker object?let averageEmailSuccess mt es = { Total = mt.Total + es.SuccessCount Divisor = mt.Divisor + (es.SuccessCount + es.FailCount) }

Page 23: EVENT SOURCING - sddconf.comsddconf.com/brands/sdd/library/Event_Sourcing.pdf · EVENT SOURCING Finally... EVENT SOURCING BASICS Store the domain events as "lists" (normally called

INCREMENTAL AVERAGE SUCCESS RATES! 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:

// We already have this data let currentRate = [{ SuccessCount = 10; FailCount = 0 } { SuccessCount = 22; FailCount = 1 } { SuccessCount = 112; FailCount = 2 } { SuccessCount = 100; FailCount = 5 }] |> List.fold averageEmailSuccess { SuccessCount = 0; FailCount = 0 }

// Now more starts coming in let newCurrentRate = [{ SuccessCount = 15; FailCount = 4 } { SuccessCount = 30; FailCount = 0 }] |> List.fold averageEmailSuccess currentRate

Page 24: EVENT SOURCING - sddconf.comsddconf.com/brands/sdd/library/Event_Sourcing.pdf · EVENT SOURCING Finally... EVENT SOURCING BASICS Store the domain events as "lists" (normally called

EVENT SOURCINGFinally...

Page 25: EVENT SOURCING - sddconf.comsddconf.com/brands/sdd/library/Event_Sourcing.pdf · EVENT SOURCING Finally... EVENT SOURCING BASICS Store the domain events as "lists" (normally called

EVENT SOURCING BASICSStore the domain events as "lists" (normally called streams)Build projections of them using folds

Page 26: EVENT SOURCING - sddconf.comsddconf.com/brands/sdd/library/Event_Sourcing.pdf · EVENT SOURCING Finally... EVENT SOURCING BASICS Store the domain events as "lists" (normally called

DOMAIN EVENTSA thing that has already happenedEmailSent; InvoicePaidDomain events can't fail - they've already happened!Compare with command: SendEmail; PayInvoice

Page 27: EVENT SOURCING - sddconf.comsddconf.com/brands/sdd/library/Event_Sourcing.pdf · EVENT SOURCING Finally... EVENT SOURCING BASICS Store the domain events as "lists" (normally called

SIMPLE INTERFACEno object relational impedance mismatch

Page 28: EVENT SOURCING - sddconf.comsddconf.com/brands/sdd/library/Event_Sourcing.pdf · EVENT SOURCING Finally... EVENT SOURCING BASICS Store the domain events as "lists" (normally called

SIMPLE INTERFACE1: 2: 3: 4: 5: 6: 7: 8: 9:

open System

type IRepository<'state, 'event> = abstract member LoadAggregate<'state> : Guid -> Async<'state * int> abstract member RefreshAggregate<'state> : Guid -> int -> 'state -> Async<'state * abstract member AppendEvents<'event> : Guid -> int -> 'event seq -> Async<int>

Page 29: EVENT SOURCING - sddconf.comsddconf.com/brands/sdd/library/Event_Sourcing.pdf · EVENT SOURCING Finally... EVENT SOURCING BASICS Store the domain events as "lists" (normally called

LET'S SEE AN EXAMPLE IN ACTION...

Page 30: EVENT SOURCING - sddconf.comsddconf.com/brands/sdd/library/Event_Sourcing.pdf · EVENT SOURCING Finally... EVENT SOURCING BASICS Store the domain events as "lists" (normally called

QUESTIONS?@mavnn ltd

blog

qvitoo