Proud událostí a projekce
Ukládat, co se dělo, ne výsledný stav – a stav pak kdykoli spočítat projekcí (event sourcing v malém).
Na této stránce
V jedné větě: Modul Journeys neukládá „jak formulář nakonec vypadal“, ale seznam všeho, co uživatel udělal. Časovou osu, souhrn i přehrání z něj počítají projekce.
Jak se to liší od běžného ukládání
| Běžně (stav) | Proud událostí |
|---|---|
tabulka Orders – řádek se přepisuje |
tabulka JourneyEvents – řádky jen přibývají |
| víte, jak to je | víte, jak se to stalo |
| nový pohled na data = často nedostupný | nový pohled = nová projekce nad stejným proudem |
Přirovnání: Výpis z účtu. Banka si nepamatuje jen zůstatek, ale každý pohyb. Zůstatek kdykoli spočítá – a stejně tak třeba „kolik jsem utratil za jídlo v březnu“, na což při ukládání nikdo nemyslel.
Projekce = fold
flowchart LR
e1["FormOpened"] --> e2["FieldFocused<br/>jméno"] --> e3["FieldChanged<br/>E, Ev, Eva"] --> e4["SubmitClicked"] --> e5["OrderSubmitted"]
e5 --> p1["OrderJourneyProjection<br/>časová osa + souhrn"]
e5 --> p2["JourneyReplayProjection<br/>scénář přehrání"]
click p1 "/Docs/architektura/moduly/journeys"
click p2 "/Docs/architektura/moduly/journeys"
Projekce začne s prázdným stavem a pro každou událost v pořadí zavolá Apply, která stav posune dál.
Kód: OrderJourneyProjection,
JourneyReplayProjection.
Stejný princip má i kopie katalogu – jen se výsledek projekce ukládá do tabulky.
Důležité detaily
- Čas = milisekundy od otevření formuláře (hodiny prohlížeče). Pořadí a pauzy jsou přesné, i když dávky dorazí na server pozdě nebo v jiném pořadí.
- Idempotence přes unikátní
EventIdz prohlížeče – dávka poslaná dvakrát (fetchisendBeacon) se nezdvojí. - Nové typy událostí jen na konec
JourneyEventType(ukládají se jako text, staré proudy musí jít číst dál). - Některé události zapisuje jen server (
ValidationFailed,OrderSubmitted) – prohlížeči se nevěří.
Proč takhle
Pro průběh formuláře je proud ideální: zajímá nás právě jak uživatel postupoval (kde váhal, co opravoval). Plný event sourcing (i objednávky jako proud) MiniShop nepoužívá – přináší složitost (verzování událostí, snapshoty), která by výuku ostatních konceptů zbytečně zatemnila.