Slide 1

Slide 1 text

Designing Towards Event Sourcing Tugberk Ugurlu Senior Software Engineer Deliveroo

Slide 2

Slide 2 text

Hello, I’m Tugberk!

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

Sign up and get £10! https://roo.it/tugberku-dgfd

Slide 5

Slide 5 text

careers.deliveroo.co.uk We’re Growing! Unique challenges, amazing people and great food!

Slide 6

Slide 6 text

So, Event Sourcing....

Slide 7

Slide 7 text

Audit Log

Slide 8

Slide 8 text

Potential Changes to the Information Presentation

Slide 9

Slide 9 text

Growing complexity making it hard to diagnose issues

Slide 10

Slide 10 text

Event Sourcing

Slide 11

Slide 11 text

1 BasketCreated ItemAdded ItemAdded ItemRemoved ItemQuantityIncreased ItemAdded BasketCompleted 2 BasketCreated ItemAdded ItemQuantityIncreased ItemAdded ItemAdded 3 BasketCreated ItemAdded ItemAdded BasketCompleted Event Streams

Slide 12

Slide 12 text

Write Side

Slide 13

Slide 13 text

Append Only Writes BasketCreated { "id": "1", "time": 1559172146 } ItemAdded { "itemId": "10", "quantity": 1, "time": 1559172216 } ItemAdded { "itemId": "20", "quantity": 2, "time": 1559172225 } ItemRemoved { "itemId": "10", "time": 1559172286 } ItemQuantityIncreased { "itemId": "20", "increasedBy": 2, "time": 1559172325 } State { "id": 1, "items": [ { "id": "20", "quantity": 4 } ], "createdOn": 1559172146, "lastUpdatedOn": 1559172325, "version": 5 }

Slide 14

Slide 14 text

Changing Projections BasketCreated { "id": "1", "time": 1559172146 } ItemAdded { "itemId": "10", "quantity": 1, "time": 1559172216 } ItemAdded { "itemId": "20", "quantity": 2, "time": 1559172225 } ItemRemoved { "itemId": "10", "time": 1559172286 } ItemQuantityIncreased { "itemId": "20", "increasedBy": 2, "time": 1559172325 } BasketCreated { "id": "1", "time": 1559172146 } ItemAdded { "itemId": "10", "quantity": 1, "time": 1559172216 } ItemRemoved { "itemId": "10", "time": 1559172286 } BasketCompleted { "itemId": "20", "increasedBy": 2, "time": 1559172325 } State { "completedBasketWithRemovedItems": "50%" } State { "averageItemRemoveDurationInSeconds": 70 } State { "removedItems": [ { "id": "10", "count": 2 } ] }

Slide 15

Slide 15 text

Consistency Checks BasketCreated { "id": "1", "time": 1559172146 } ItemAdded (v1) { "itemId": "10", "quantity": 1, "time": 1559172216 } ItemAdded (v2) { "itemId": "20", "quantity": 2, "time": 1559172225 } ItemRemoved (v3) { "itemId": "10", "time": 1559172286 } ItemQuantityIncreased (v3) { "itemId": "10", "increasedBy": 2, "time": 1559172325 } State { "id": 1, "items": [ { "id": "20", "quantity": 2 } ], "createdOn": 1559172146, "lastUpdatedOn": 1559172286, "version": 4 }

Slide 16

Slide 16 text

1 BasketCreated ItemAdded ItemAdded ItemRemoved ItemQuantityIncreased ItemAdded BasketCompleted 2 BasketCreated ItemAdded ItemQuantityIncreased ItemAdded ItemAdded 3 BasketCreated ItemAdded ItemAdded BasketCompleted Naturally Partitioned

Slide 17

Slide 17 text

Read Side

Slide 18

Slide 18 text

Eventual Consistency ● Read side needs to embrace eventual consistency ● Unless you can reproject over the entire stream every time a read is requested ● Which is especially very inefficient where your projection needs to work across streams

Slide 19

Slide 19 text

Consumer Driven Subscription ● Consumer dictates where the delivery needs to start from ● Unlike AMQP model, event messages can be requested over and over again

Slide 20

Slide 20 text

Event Order Matters ● So that the state can be applied expectedly ● Unless read models pay a special attention to the sequence of the messages and try to BasketCreated { "id": "1", "time": 1559172146 } ItemAdded { "itemId": "20", "quantity": 2, "time": 1559172225 } ItemRemoved { "itemId": "10", "time": 1559172286 } ItemAdded { "itemId": "10", "quantity": 1, "time": 1559172216 } ItemQuantityIncreased { "itemId": "20", "increasedBy": 2, "time": 1559172325 }

Slide 21

Slide 21 text

Implementation

Slide 22

Slide 22 text

Two Sides Low level How to coordinate the flow from request arriving to response going out the door, for both reads and writes. High level How the implementation fits into our end-to-end solution, where the system resources defined and being used.

Slide 23

Slide 23 text

Low Level

Slide 24

Slide 24 text

Aggregate ● Write model ● Represents the consistency boundary ● Stream of events are tied to an aggregate. Why? ○ Aggregate represents our consistency boundary and we can enforce the consistency within an aggregate even when applying multiple events to its state ● Not a strict relationship structure ○ Could result in very large aggregates w/o necessarily needing all the resources ● Repository handles aggregate construction by retrieving and applying all the events

Slide 25

Slide 25 text

Aggregate: Construction https://github.com/jetbasrawi/go.cqrs/blob/e4d812d57f090ecede016aa36d70c73626a8eb17/examples/simplecqrs/simplecqrs/inmem_repo.go#L22-L37

Slide 26

Slide 26 text

Aggregate: Construction https://github.com/jetbasrawi/go.cqrs/blob/e4d812d57f090ecede016aa36d70c73626a8eb17/examples/simplecqrs/simplecqrs/inventoryitem.go#L97-L118

Slide 27

Slide 27 text

Commands ● Request to alter the state of a particular aggregate instance ● Command is different than events ○ commands can be rejected (e.g. due to invalidating business invariants) ○ whereas events represent a state change which has already happened ● Application of a command on an aggregate instance can cause one or multiple events to be emitted

Slide 28

Slide 28 text

Command Handler ● Sits in between command sender and the aggregate ● Abstract away the write model from the outside world ● Performs invariant checks which an aggregate simply cannot do ○ E.g. in cases where the check needs to query an external data outside the boundaries of an aggregate instance

Slide 29

Slide 29 text

Example https://github.com/jetbasrawi/go.cqrs/blob/e4d812d57f090ecede016aa36d70c73626a8eb17/examples/simplecqrs/simplecqrs/command_handlers.go#L29-L41

Slide 30

Slide 30 text

https://github.com/jetbasrawi/go.cqrs/blob/e4d812d57f090ecede016aa36d70c73626a8eb17/examples/simplecqrs/simplecqrs/inventoryitem.go#L19-L38

Slide 31

Slide 31 text

Example https://github.com/jetbasrawi/go.cqrs/blob/e4d812d57f090ecede016aa36d70c73626a8eb17/examples/simplecqrs/simplecqrs/inmem_repo.go#L43-L46

Slide 32

Slide 32 text

Example https://github.com/jetbasrawi/go.cqrs/blob/e4d812d57f090ecede016aa36d70c73626a8eb17/examples/simplecqrs/simplecqrs/command_handlers.go#L43-L49

Slide 33

Slide 33 text

Queries ● Construct a read model which satisfy the access pattern ● Listening on events on one aggregate or multiple, across streams ● Doesn’t have to project the data on the fly, can cache and serve data faster in that way ● Projection can also happen offline

Slide 34

Slide 34 text

Example https://github.com/jetbasrawi/go.cqrs/blob/e4d812d57f090ecede016aa36d70c73626a8eb17/examples/simplecqrs/simplecqrs/readmodel.go#L75-L111

Slide 35

Slide 35 text

Example https://github.com/jetbasrawi/go.cqrs/blob/e4d812d57f090ecede016aa36d70c73626a8eb17/examples/simplecqrs/simplecqrs/readmodel.go#L128-L170

Slide 36

Slide 36 text

Example https://github.com/jetbasrawi/go.cqrs/blob/e4d812d57f090ecede016aa36d70c73626a8eb17/examples/simplecqrs/simplecqrs/readmodel.go#L39-L58

Slide 37

Slide 37 text

High Level

Slide 38

Slide 38 text

Hexagonal Architecture (a.k.a. Ports and Adaptors) ● Architectural approach to encapsulate changes ● Prevents infrastructure code to leak into the domain ● Consists of 3 layers: ○ Domain ○ Application ○ Framework ● Hexagonal Architecture != Layered Architecture http://tpierrain.blogspot.com/2016/04/hexagonal-layers.html

Slide 39

Slide 39 text

https://fideloper.com/hexagonal-architecture

Slide 40

Slide 40 text

Hexagonal Architecture and Even Sourcing: Test If you change your data storage system and this results in making a change in the domain layer, you failed! More accurately, your abstractions failed you!

Slide 41

Slide 41 text

More Resources ● CQRS FAQ: https://cqrs.nu/Faq ● Greg Young - CQRS and Event Sourcing - Code on the Beach 2014: https://www.youtube.com/watch?v=JHGkaShoyNs ● Hexagonal Architecture: https://fideloper.com/hexagonal-architecture ● Versioning in an Event Sourced System: https://leanpub.com/esversioning ● CQRS Example in Go: https://github.com/jetbasrawi/go.cqrs ● CQRS Example in C#: https://github.com/gregoryyoung/m-r ● Distributed Sagas: A Protocol for Coordinating Microservices - Caitie McCaffrey: https://www.youtube.com/watch?v=0UTOLRTwOX0

Slide 42

Slide 42 text

Questions?

Slide 43

Slide 43 text

Thank you! Let’s keep in touch! @tourismgeek [email protected] tugberkugurlu.com