Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Event Sourcing: Don't want to miss a thing

Event Sourcing: Don't want to miss a thing

An introduction into Event Sourcing

Garrett Heinlen

September 05, 2018
Tweet

More Decks by Garrett Heinlen

Other Decks in Technology

Transcript

  1. Events Cart [] ! [ ] ➕ # ! [

    # ] ➕ # ! [ #, # ]
  2. Events Cart [] ! [ ] ➕ # ! [

    # ] ➕ # ! [ #, # ] ➕ $ ! [ #, #, $ ]
  3. Events Cart [] ! [ ] ➕ # ! [

    # ] ➕ # ! [ #, # ] ➕ $ ! [ #, #, $ ] ➖ # ! [ #, $ ]
  4. Events Cart [] ! [ ] ➕ # ! [

    # ] ➕ # ! [ #, # ] ➕ $ ! [ #, #, $ ] ➖ # ! [ #, $ ] ➕ & ! [ ]
  5. Events Total computers sold [] 0 ➕ " 1 ➕

    " 2 ➕ # 2 ➖ " 1 ➕ % 1
  6. currentState: { currentMap: 1, currentPosition: 6, currentActivity: 2 } id

    student_id lesson_ position activity_ position 1 3202 6 2
  7. currentState: { currentMap: 1, currentPosition: 6, currentActivity: 2 } id

    student_id lesson_ position activity_ position quiz_ position 1 3202 6 2 1
  8. currentState: { currentMap: 1, currentPosition: 3, currentActivity: 2 } id

    student_ id lesson_ position activity_ position quiz_ position manual_ reset_ position 1 3202 6 2 1 3
  9. Kid finishes lesson 3.. currentState: { currentMap: 1, currentPosition: 4,

    currentActivity: 1 } id student_ id lesson_p osition activity_ position quiz_ position manual _reset _position 1 3202 4 1 1 3
  10. Reporting.. ☞ What's the highest lesson a kid has done?

    ☞ What's the last quiz a kid has taken? ☞ What's the average growth of lessons in a month?
  11. currentState: { currentMap: 1, currentPosition: 6, currentActivity: 1 } id

    student_id event_type payload 1 3202 placeStudent { lesson: 6, activity: 1 }
  12. currentState: { currentMap: 1, currentPosition: 6, currentActivity: 2 } id

    student_id event_type payload 1 3202 placeStudent { lesson: 6, activity: 1 } 1 3202 activityComple ted { lesson: 6, activity: 1 }
  13. currentState: { currentMap: 1, currentPosition: 6, currentActivity: 3 } id

    student_id event_type payload 1 3202 placeStudent { lesson: 6, activity: 1 } 1 3202 activityComple ted { lesson: 6, activity: 1 } 1 3202 activityComple ted { lesson: 6, activity: 2 }
  14. currentState: { currentMap: 1, currentPosition: 7, currentActivity: 1 } id

    student_id event_type payload 1 3202 placeStudent { lesson: 6, activity: 1 } 1 3202 activityComplete d { lesson: 6, activity: 1 } 1 3202 activityComplete d { lesson: 6, activity: 2 } 1 3202 lessonCompleted { lesson: 6 }
  15. currentState: { currentMap: 1, currentPosition: 3, currentActivity: 1 } id

    student_id event_type payload 1 3202 placeStudent { lesson: 6, activity: 1 } 1 3202 activityCompleted { lesson: 6, activity: 1 } 1 3202 activityCompleted { lesson: 6, activity: 2 } 1 3202 lessonCompleted { lesson: 6 } 1 3202 resetProgress { lesson: 3, activity: 1 }
  16. The pieces ☞ Clients issue commands ☞ Aggregates build and

    hold current state ☞ Command handlers validate incoming commands against current state ☞ Event handlers transform the command into event/s and trigger the aggregate to update their state
  17. Obligatory code snippet app.post('/progress/commands', (req: Request, res: Response) => {

    const currentState = new ProgressAggregate(req.user); const newCommand = new ProgressCommand(req.body); if (isValid(currentState, newCommand)) { const newEvents = commandHandler(currentState, newCommand); const newState = eventHandler(currentState, newEvents); res.send(newState); } else { res.send({ error: 'invalid command' }); } });
  18. Top questions ☞ Isn't this slow? ☞ What happens when

    theres too many events? ☞ What about bad data?
  19. Speed - Optimize aggregates ☞ on login build the aggregates

    in memory ☞ partition the events table by user id / aggregation type ☞ build rollups / snapshots
  20. Snapshots ☞ Always keep the raw events table ☞ After

    calculating current state, store that aggregation in a snapshot table. ☞ Read from snapshot table and apply the new events to that to derive new current state. ☞ Do this nightly, weekly, after every event - w/e works for you
  21. Bad data ☞ Make your command handlers more strict ☞

    Create new events to undo oldE events ☞ [soft] delete them (if you really have to)