Event Sourcing (och händelsedriven arkitektur) i praktiken

Sun, Mar 7, 2021

Jag har hittat två stycken vittnesmål om hur det är att jobba med Event Sourcing (ES) i praktiken.

Mikael Sundberg

I ett föredrag från JFocus 2017 (YouTube), berättar Mikael Sundberg om erfarenheter från att ha implementerat ES på Klarna.

Sundberg lyfter fem stycken problem (tre stycken relaterad till händelsedriven arkitektur, följt av två kring ES):

  1. Automatisk testning av dina historiska modeller blir ett problem om du uppdaterar dina tester till att testa den nya modellen när du utökar den. I produktion kommer den nya modellen finnas, men även historiska permutationer. Sundbergs förslag på lösning är att skapa data enligt historiska modeller i testerna.
  2. Monitorering - hur skiljer jag på att en händelse inte har hänt och att någonting gått fel? Sundbergs förslag på lösning är ett skapa ett “spår” genom systemet, genom att parallellt skapa metahändelser som berättar vilka händelser som har inträffat.
  3. Eventual Consistency blir ett problem i en händelsedriven arkitektur om data persisteras vid sidan om själva händelserna. Sundbergs förslag på lösning är att skapa ett synkront dataflöde där händelsen persisteras utanför händelseströmmen innan det lägges på strömmen.
  4. Du måste värna din domän och inte utöka dina aggregat med data som inte hör hemma där, bara för att händelseflödet redan finns på plats. Sundbergs förslag på lösning är att säga “nej”, men hjälpa till att lösa problemet på rätt sätt.
  5. Om dina händelser beskrivs och verifieras via schema så är det lättare att kommunicera dina domänmodeller med t ex andra team. Sundberg lyfter detta som det största misstaget - att inte tillämpa schmeman från start.

Sundberg avslutar med att lyfta vad han tycker är bra med ES:

  1. Dina datafrågor är alltid snabba eftersom du aldrig riskerar att sakna ett databasindex.
  2. Att replikera data som inte kan muteras är lätt.
  3. Att det är svårt att ställa frågor är “bra”, eftersom det tvingar dig att göra “rätt” genom att skapa dedikerade modeller för läsning genom t ex Elastic Search.
  4. Uppmuntrar bra domänmodeller.
  5. Ingenting raderas.

David Schmitz

I ett föredrag från Devoxx 2018(?) (YouTube), sammanfattar David Schmitz sina erfarenheter från att implementera ES. Schmitz argumenterar för att ES är komplicerat, och att du är dömd att göra misstag på vägen. Han konstaterar även att ES i praktiken handlar om att skapa löst kopplad affärslogik redan på verksamhetsnivå.

Schmitz radar upp ett antal insikter kring ES, blandat med tips för att lyckas implementera det:

  1. Separata “läsmodeller” är överskattat. Skapa en händelseström per aggregat istället. Dina strömmar kommer att vara tillräckligt små.
  2. Dina aggregat bildar avgränsningar för dina transaktioner, eftersom dom skrivs i sin helhet eller inte alls.
  3. Apache Kafka kan inte garantera ordningen på händelser som skrivs till en ström på ett sådant sätt att den som skriver händelsen kan säga att “den här händelsen måste hamna direkt efter den där händelsen, annars misslyckas skrivningen”. Det gör att om du har flera producenter som skriver till samma ström så kan du inte upprätthålla affärslogik som kräver att händelser ibland inte skrivs i en viss ordning (exempelvis övertrasering av bankkonto).
  4. Att använda “Upcaster” som mönster för att hantera flera parallella versioner av händelser (på verksamghetsnivå) blir väldigt komplext över tid.
  5. Undvik flera versioner av händelser på verksamhetsnivå. Utöka befintliga händelser på ett bakåtkompatiblet schema istället och realisera det i en lösning med “svaga” scheman (så som JSON schema) som i första hand hjälper till att beskriva din domänmodell. Lita på den som skriver händelsen.
  6. Om du behöver förstå ES, prata med din ekonomiavdelning. Bokföring är i praktiken ES.
  7. För att hantera fallet att väldigt mycket händelsedata skapas över tid, eller att du har behova av att skapa om din domänmodell, så är det möjligt att migrera din ström till en aggregerad (eller ommodellerad) ström. Det kan dock innebära utmaningar om systemet används samtidigt.
  8. Om en händelse har ett namn som innehåller “och”, så rör det sig nog egentligen om två olika händelser.
  9. Använd korrigeringshändelser för att rätta till “fel” i strömmen, men korrigera bara hela händelser - aldrig delar. Att göra “hela” korrieringar är mer explicit och lättare att förstå och resonera kring (och även hur det görs i bokföring).
  10. När det kommer till personuppgifter så innebär kryptering av hela strömmar väldigt hög komplexitet i form av nyckelhantering och svårigheter att sköta drift. Separera istället publikt data från privat data, så att du har möjlighet att bara radera dom händelser som innehåller det privata datat.