31
25 NOVEMBRE 2016 The Fine Art of Time Travelling: implementing Event Sourcing Andrea Saltarello Solution Architect @ Managed Designs https://twitter.com/andysal74

The Fine Art of Time Travelling: implementing Event Sourcing - Andrea Saltarello - Codemotion Milan 2016

Embed Size (px)

Citation preview

25 NOVEMBRE 2016

The Fine Art of Time Travelling: implementing Event Sourcing

AndreaSaltarelloSolutionArchitect@Managed Designs

https://twitter.com/andysal74

There’s nosilverbullet

Not the waytoimplement Event Sourcing,but a working waytodoit nonetheless

Demoapp available onGithub (GPL3),BTW

The(ambiguous)LordoftheRings

Afew fancy dressed blokes making ajaunt

ItreallybecamecleartomeinthelastcoupleofyearsthatweneedanewbuildingblockandthatistheDomainEvent.

[EricEvans]

Aneventissomethingthathashappenedinthepast.[GregYoung]

Adomainevent…capturesthememoryofsomethinginterestingwhichaffectsthedomain

[MartinFowler]

Insteadoffocusingonasystem’slastknownstate,wemightnotedowneveryoccurringevent:thisway,wewouldbeableto(re)buildthestatethesystemwasinatanypointintimejustreplayingthoseevents

Tocutalongstoryshort:we’denduprecordinganeventstream

Event Sourcing inanutshell

JobOrderStarted InvoiceIssuedJobOrderExtended JobOrderCompleted

What’s anevent,anyway?

The(immutable)composition of:• A(meaningful)name• (Typed)Attributes

InvoiceIssued

DateOfIssue

Customer

Price

ProjectStarted

DateOfStart

ProjectId

ProjectCompleted

DateOfCompletion

ProjectId

ProjectRegistered

DateOfRegistrationDateOfEstimatedCompletionProjectIdCustomerIdPrice

demoEventStream

Events vs.Relations

INSERTINTOX(M,L,G)VALUES(1,0,1)UPDATEXSETM=X,L=Y…WHERE…UPDATEXSETM=42…WHERE…UPDATEXSETJ=K…WHERE…

INSERTJobOrderStarted VALUES()INSERTJobOrderExtended VALUES()INSERTInvoiceIssued VALUES()INSERTJobOrderCompleted VALUES()

Although replaying aDBMSevent logoradopting atemporal databasewould allow torestore aspecific system state,we would missthereason behind every occurred change nonetheless

Still,my users aremoreinterested inknowing ajoborder’s balanceorwhether aninvoice has been paid.(cit.)

That is,we need awaytoproduceanentity state

EventStreamvs.«Myapplication»

Event Sourcing <3DDD

DDD’s Aggregates provide aconvenient waytoencapsulate eventmanagement

Aggregate:Acollection ofobjects that arebound together byaroot entity,otherwise known as anaggregateroot.Theaggregateroot guarantees theconsistency ofchanges being madewithin theaggregate.

[Wikipedia]Anaggregateis responsible for:• encapsulating businesslogic pertaining toan“entity”• generating events tohave them available forsaving• replaying events inorder torebuild aspecific state

demoAggregates

Aggregates vs.Events vs.Repos

var aggr =repository.GetById<TAggr>(id); //Triggers [timetravelling capable]event replayaggr.DoSomething(); //Domainlogic +events raisingrepository.Save(aggr); //Updates theevent stream +events dispatching

Repository:Mediates between thedomainanddatamapping layers using acollection-like interfaceforaccessing domainobjects.[DDD]

demoTimeTravelling

Still²,my users aremoreinterested inknowing ajoborder’s balanceorwhether aninvoice has been paid.Quickly.

Waystoachieve that:• Snapshots canhelp• CQRStotherescue:let’s have adatabasestoring theusual «lastknown systemstate»using it as aread model

EventStreamvs.«Myapplication»

demoSnapshots

Enter CQRS

Acronym forCommand QueryResponsibility SegregationBasically,adhocapplication stacks forboth writing andreading:• “Command”stack writes events andsnapshots• “Read”stack reads fromeventually consistent,reading purposesoptimized database(s)

CQRS:the“Read”sideoftheForce

Asabusinessunitmanager,Iwanttocollectcreditsduetounpaidoutgoinginvoices #ubiquitouslanguage #nuffsaid

CQRS/ESwise,this user storycould beimplemented bymeans ofthefollowing real worldC#code:

Database.OutgoingInvoices..PerBusinessUnit(businessUnitId).ExpiredOnly().Select(i=>new{InvoiceNumber =i.Number,CustomerId =i.Customer.Id}).AsParallel().ForAll(i=>bus.Send(newCollectDebtCommand(i.InvoiceNumber,i.CustomerId)));

demoReadModel

CQRS/ESinanutshell

1. Applicationsends acommand tothesystem2. Command execution might alterthesystem’s stateandthen raise

events tostatesuccess/failure3. Eventsarenotified tointerested subscribers (a.k.a.handlers),such

as:• Workflow managers (a.k.a.«Sagas»)which could execute morecommands• Denormalizers,which will updatetheread modeldatabase

Note:command/event dispatch/execution will usually bemanaged byaMediator(«bus»)

ApplicationLayer

Snapshots

Eventstore

Readstack

DomainLayer

Ad-hocDBHandlers

Command Event Data

Handlers

Model ServicesBUS

CQRS/ESataglance

demoHandlers/Denormalizers

Oh,justone morethingJ

TimeTravelling… «Fringe»style

What if we could manage events occurring inparallel,alternativetimelines?

demoSpeculations

THANKYOU!

Encore

Abus!Abus!Mykingdom forabus!

Although buildingasimple busmight befeasible (andtempting as wellJ),3°-partyproducts (e.g.:MassTransit,NServiceBus,Rebus,…)providemuch-neededfeaturessuchas:• Faulttolerance• Scalability• Workflowsupport• Events’scheduling

demoBye,bye,polling(PollingGoodbye)

Grazie!

Contatti:

• https://twitter.com/andysal74• http://blogs.ugidotnet.org/pape• [email protected]

Thank you!Questions?https://twitter.com/ugidotnet