Da jeg har brugt den seneste tid dybt begravet i CQRS og event sourcing, og da der ikke p.t. på QED.dk findes artikler om emnet – og da vi hos d60 for nylig har udgivet vores egenudviklede CQRS + event sourcing framework, Cirqus, som FOSS på GitHub – så synes jeg lige det er på sin plads at introducere emnet.
Dette indlæg vil give en introduktion til CQRS og event sourcing på et overordnet plan, og de efterfølgende indlæg i serien vil beskrive hvordan man kan komme i gang med Cirqus.
Lad os starte med
Event sourcing
Event sourcing er et ældgammelt princip, som handler om at repræsentere tilstanden i et system – ikke vha. det typiske “snapshot”, f.eks.
konto1.saldo = 10
konto2.saldo = 5
men derimod vha. de hændelser, der har ført frem til den tilstand: F.eks.
konto1.indsatte(20)
konto1.hævede(25)
konto1.indsatte(15)
konto2.indsatte(2000)
konto2.hævede(2200)
konto2.indsatte(2000)
konto2.hævede(1995)
konto2.indsatte(200)
Overordnet set handler event sourcing om at der aldrig foretages destruktive ændringer i systemet – ALT beskrives vha. en append-only strøm af events, selv rettelser og sletninger beskrives ved at tilføje information – bare information om at noget er blevet rettet eller slettet.
Læs evt. software-antropologens udmærkede beskrivelse af event sourcing – den er fin og har et par gode eksempler.
CQRS
CQRS står for “command/query responsibility segregation” og er et arkitekturprincip, der handler om at systemet opdeles i to logisk separerede dele: command-delen, som modtager kommandoer f.eks. affødt af brugerens handlinger og dermed står for alle skrivninger i systemet, samt query-delen, som modtager information om hvad der er sket og holder det separate læse-system opdateret med hvad der skete som konsekvens af at udføre den pågældende kommando.
De fleste er enige om at CQRS blev beskrevet første gang af Greg Young, men der er vist også en forbindelse til Udi Dahan – de to har i hvert fald drøftet og diskuteret CQRS i nogle år omkring begyndelsen af dette årti, og de snakker begge to gerne om det.
Igen kan jeg anbefale Martin Fowlers beskrivelse af emnet – han forstår virkelig at beskrive ting, ham Martin.
På billedet (1) er illustreret hvordan man med en “traditionel arkitektur” har en applikation, som benytter samme model til læsning og skrivning – alle ændringer foretages med andre ord direkte i den model, som efterfølgende skal fremvises på en skærm.
Ved siden af (2) er vist hvordan man kan dirigere skrivninger (W) til en specifik model, hvorefter noget (her blot illustreret med en kasse) sørger for at opdatere en anden model, som herefter kan benyttes til læsning (R).
CQRS + event sourcing = ♡
Det viser sig at CQRS og event sourcing er vanvittigt gode venner da event sourcing i sig selv indebærer en praktisk udfordring – f.eks. kan man ikke umiddelbart besvare spørgsmålet “hvad er saldo?” hvis man skal summere 500.000 kontobevægelser hver eneste gang spørgsmålet skal besvares – men det er jo netop det, CQRS er god til: At holde en læsemodel med en saldo opdateret, baseret på events.
Den anden vej rundt giver det også god mening – CQRS har nemlig også en udfording hvis man midt i en applikations levetid ønsker af indføre en ny læsemodel: Den netop indførte læsemodel skal føres ajour med systemets aktuelle tilstand – men det er jo en triviel problemstilling hvis kilden til al tilstand er en strøm af events, for så kan den nyligt indførte læsemodel blot starte fra tidernes morgen og læse alle events indtil den har indhentet virkeligheden.
CQRS + event sourcing i praksis: Cirqus
For at gøre det nemt og hurtigt at bygge systemer baseret på CQRS og event sourcing har vi ved d60 skabt frameworket Cirqus, som vi har udgivet som gratis open source software, da vi håber på at andre vil tage det i brug og evt. bidrage med et pull request eller to. I de efterfølgende indlæg vil jeg gennemgå Cirqus og vise hvordan også DU kan komme i gang med CQRS or event sourcing.
PS: Prøv at sige “CQRS” meget hurtigt 😉
[…] kan vores arkitektur hjælpe med at støtte op omkring sikkerheden. Fx. ved at benytte CQRS og låse ned på rettighederne på vores data-store så eksisterende data ikke kan ændres eller […]