Alle artikels
Software

Wat is een projectie?

Cover: wat is een projectie
"Ok, dus alles zit in dat logboek. Maar hoe krijg ik dan gewoon een lijstje van mijn openstaande offertes?"

Dat is zowat de eerste bedenking bij iedereen die voor het eerst over event sourcing leest. En het is de juiste vraag, want een logboek is fantastisch om in te schrijven en waardeloos om in te zoeken.

Het antwoord heet een projectie.

Wat is een projectie precies?

Bij event sourcing is de waarheid een rij feiten die effectief gebeurd zijn: OfferteVerstuurdOfferteGoedgekeurdOrderIngeplandOrderGeleverd. Ze worden achteraan toegevoegd, in volgorde, en er wordt nooit iets overschreven.

Wil je weten welke offertes vandaag nog openstaan, dan kan je die vraag niet zomaar aan die rij stellen. Je zou het volledige logboek van begin tot eind moeten doorlopen. Elke keer opnieuw.

Dus doe je dat één keer. Je loopt de events in volgorde af en houdt ondertussen een tabel bij: bij OfferteVerstuurd komt er een rij bij, bij OfferteGoedgekeurd gaat ze eruit. Wat je overhoudt is een doodgewone tabel die je applicatie in één query uitleest.

Die tabel is de projectie.

Eén event log die drie verschillende leesmodellen voedt: een scherm met openstaande offertes, een doorlooptijdrapport en een zoekindex.


Twee eigenschappen doen al het werk.

Een projectie is afgeleid, nooit de waarheid. Je mag ze weggooien. Verwijder de tabel, speel de log opnieuw af, en ze staat er weer precies zoals ze was. Dat klinkt als een detail, maar het verandert alles aan hoe je met fouten omgaat.

Er mogen er zoveel zijn als je vragen hebt. Dezelfde events voeden je offertescherm, je doorlooptijdrapport en je zoekindex. Elk in de vorm die die ene vraag het snelst beantwoordt. Geen enkel schema hoeft nog een compromis te zijn tussen wat de verkoper op zijn scherm wil en wat de zaakvoerder in zijn rapport wil.

Is dat uniek aan event sourcing?

Nee. En dat is belangrijk om te weten voor je ergens aan begint.

Het idee "een afgeleide leesvorm bovenop een bron van waarheid" zit overal:

  • Een materialized view in PostgreSQL is exact hetzelfde principe, alleen bovenop tabellen in plaats van events.
  • Een zoekindex in Elasticsearch die je synchroon houdt met je database.
  • Een rapportagetabel die 's nachts wordt bijgewerkt.
  • Zelfs je boekhouding: een balans is niets anders dan een projectie van je grootboek.

Projecties horen strikt genomen bij CQRS, en CQRS kan perfect zonder event sourcing.

Wat event sourcing wél verandert, is dat de bron volledig is. In een klassieke database heeft elke UPDATE de vorige waarde vernietigd. Je materialized view kan dus alleen projecteren wat je huidige tabellen nog bewaren. Met een event log bouw je een projectie voor een vraag die niemand had gesteld toen die events geschreven werden.

Daar zit de hele winst.

Wat levert het je op?

Nieuwe vragen over oude data. Je zaakvoerder vraagt in maart: "hoe lang blijven offertes eigenlijk hangen bij ons?" Bewaar je alleen de huidige status, dan is het antwoord "dat weet ik vanaf vandaag, kom in september terug". Met een event log schrijf je een nieuwe projectie, speelt ze de geschiedenis af, en heb je het antwoord over de voorbije drie jaar.

Fouten worden goedkoop. Zit er een bug in je rapportlogica, of moet de structuur anders? Code aanpassen, tabel weggooien, opnieuw afspelen. Geen migratiescripts, geen archeologie op corrupte data.

Lezen en schrijven raken los van elkaar. De schrijfkant bewaakt je businessregels. Elke leeskant is gevormd naar één vraag. Die twee hoeven niet meer in hetzelfde schema te passen.

En de snelheid dan?

Hier zit het grootste misverstand. "Dus die trage rapporten zijn dan opgelost?" Deels.

De leesquery wordt inderdaad veel sneller. Een join over zeven tabellen met wat vensterfuncties erbovenop wordt een simpele opzoeking in een tabel die precies de vorm van dat scherm heeft. Belangrijker nog: de snelheid wordt voorspelbaar. Ze zakt niet meer weg naarmate je database groeit, want het queryplan verandert niet meer van vorm.

Maar het rekenwerk is niet verdwenen. Het is verhuisd van leestijd naar schrijftijd. Je betaalt het nu één keer per event in plaats van één keer per vraag.

Zonder projectie rekent elke leesvraag opnieuw; met een projectie reken je één keer bij het schrijven en zijn alle leesvragen goedkoop.


Die ruil is uitstekend zolang je veel vaker leest dan schrijft. Een overzichtsscherm dat bij elke paginaweergave laadt: perfect. Maar een rapport dat twaalf keer per jaar gedraaid wordt en dat je continu moet bijhouden over miljoenen events: slechte deal. Draai gewoon die trage query twaalf keer.

En let op wat een projectie níét oplost: ad-hocvragen. Een projectie is een vooraf berekend antwoord op een bekende vraag. Zet iemand een BI-tool op je data met vrije queries, dan heb je nog altijd een gewone doorzoekbare database of een datawarehouse nodig.

Ze lost ook geen query op die traag is omdat er simpelweg een index ontbreekt.

De valkuilen

Vertraging. Werk je je projecties asynchroon bij, dan kan iemand iets opslaan en het nog niet zien staan. Dat is geen detail dat je later wel eens fixt, dat raakt elk scherm in je applicatie. Je hebt er een antwoord voor nodig, en dat antwoord kost werk.

Versionering van je events. Een event dat je vandaag schrijft, moet over vijf jaar nog te begrijpen zijn door code die dan bestaat. Dat vraagt discipline: ofwel vertaal je oude events bij het inlezen, ofwel schrijf je lezers die tegen ontbrekende velden kunnen.

Herbouwtijd groeit mee. "Speel gewoon de log opnieuw af" is een mooie eigenschap bij honderdduizend events en een planningsprobleem bij vijftig miljoen. Dan heb je snapshots nodig, of je bouwt de nieuwe versie naast de oude en schakelt pas om als ze bij is.

Hetzelfde event komt twee keer voorbij. Bij vrijwel elke manier van bijwerken gebeurt dat vroeg of laat. Elke projectie moet daar tegen kunnen, anders tel je omzet dubbel.

Hoe wij het aanpakken

We beginnen niet bij event sourcing. Als het concrete probleem "dit scherm laadt acht seconden" is, dan gaan we van goedkoop naar duur: eerst het queryplan bekijken en de ontbrekende index leggen, dan de query herschrijven, dan een materialized view met een verversstrategie. Dat laatste is een namiddag werk en pakt in de praktijk het grootste deel van de traagheid weg.

Event sourcing zetten we in wanneer geschiedenis echt bij het domein hoort. Offertetrajecten, dossieropvolging, boekhouding, alles waar "wat is er precies gebeurd en wanneer" een echte vraag is. Dan is de snelheid van je projecties een aangename bijkomstigheid, geen argument op zich.

Wat we daarbij vasthouden:

  • Elke projectie is herbouwbaar, en die herbouw testen we. Een projectie die je in de praktijk niet durft weg te gooien, is geen projectie meer.
  • Elke projectie houdt haar eigen positie bij, zodat ze apart kan achterlopen of herbouwd worden zonder de rest te raken.
  • We zeggen op voorhand waar je de vertraging gaat zien in het scherm, en hoe we dat opvangen. Liever een vervelend gesprek vooraf dan een verrassing bij oplevering.
  • Alles draait op Europese servers, zonder vendor lock-in, en jij blijft eigenaar van code, data en infrastructuur.

Wil je weten hoe we met datzelfde model ook je businessregels consistent houden, lees dan Wat is DCB (Dynamic Consistency Boundary)?. En dat het snel én betaalbaar blijft op gewone Europese infrastructuur, toonden we met een benchmark.

Zit jij vast op een rapport dat elke maand trager wordt, of op een vraag die je data niet kan beantwoorden? Praat met ons, we kijken graag samen waar het vastloopt.

Gepubliceerd op 04 aug 2026
Profile picture of cofounder Mathias
Engineering
Mathias Beke

Bouwt software die snel draait, weinig kost, en volledig op Europese servers staat.