CQRS a event sourcing vs. jednoduchý CRUD: kdy a proč

CRUD je nejrychlejší cesta k funkční aplikaci. CQRS s event sourcingem zase lépe zvládají složitá pravidla, audit a škálování čtení. Pojďme srozumitelně vysvětlit, co tyto přístupy opravdu dělají, v čem se liší a kdy který zvolit.

CQRS a event sourcing vs. jednoduchý CRUD: kdy a proč
Photo by Sven Mieke / Unsplash

Co je CRUD – a proč je pro začátek často nejlepší

CRUD je přímý způsob práce s daty: vytvořit, přečíst, upravit, smazat. V praxi to znamená jeden společný datový model a jednu databázi, nad kterou probíhá jak zápis, tak čtení. Aplikace mívá několik formulářů, které ukládají data do tabulek, a přehledy, které z těch samých tabulek data zobrazují.

Proč je CRUD tak oblíbený? Protože je rychlý na vývoj i údržbu. Není nutné řešit žádnou složitou infrastrukturu, nový vývojář se v projektu zorientuje během pár dní a první verze produktu (MVP) jde na svět v krátkém čase. U menších interních nástrojů, jednoduchých evidencí, administrace webu nebo podpory backoffice je to přesně to, co chcete: minimum architektury, maximum doručené hodnoty.

CRUD má ale i limity. Jakmile se doména začne komplikovat (např. rezervace, platby, stavy objednávek) a výrazně naroste počet čtecích dotazů, společný model se musí ohýbat pro obě potřeby najednou. Zápis vyžaduje přísná pravidla a transakce, čtení potřebuje rychlé přehledy, agregace a denormalizovaná data pro UX. Přidá-li se požadavek na detailní audit, začne se konstrukce s pomocnými tabulkami, triggery a cachemi rychle komplikovat.

Co je CQRS – dvě oddělené části se specializací

Zkratka CQRS znamená Command and Query Responsibility Segregation, tedy oddělení odpovědnosti za zápis a čtení. Pro srozumitelnost budeme používat jednotné pojmy:

  • část pro zápis – zpracovává požadavky, které mění stav systému (např. „vytvoř objednávku“, „přidej položku“, „zruš rezervaci“). Tady platí byznysová pravidla a transakce;
  • část pro čtení – poskytuje rychlé dotazy pro obrazovky, přehledy a exporty. Může mít vlastní, pro čtení optimalizované datové struktury (často denormalizované).

Hlavní myšlenka je jednoduchá: co zapisuje, ať hlídá správnost; co čte, ať je rychlé. Díky tomu lze čtení a zápis škálovat nezávisle a část pro čtení navrhnout přesně podle potřeb uživatelského rozhraní – třeba mít zvláštní „pohled“ pro dashboard, jiný pro fulltext a další pro reporting.

Je tu ale důsledek, který je třeba vědomě přijmout: změna provedená v části pro zápis se do části pro čtení propaguje asynchronně. Krátkou chvíli tedy můžete vidět „starší“ data – tomu se říká eventuální konzistence. Dá se s ní dobře žít, když s ní počítá uživatelské rozhraní: po uložení třeba hned ukáže stav „zpracováváme“ a po aktualizaci pohledu změnu „dohoní“ (např. přes WebSockety).

Co je event sourcing – historie jako zdroj pravdy

Event sourcing jde ještě o krok dál: místo ukládání „aktuálních řádků v tabulce“ ukládáte nezměnitelné události, které se v čase staly: „Objednávka vytvořena“, „Položka přidána“, „Platba potvrzena“. Aktuální stav je pak pouze výsledkem promítnutí (replay) těchto událostí. S CQRS se to přirozeně doplňuje: část pro zápis publikuje události, část pro čtení si z nich skládá vlastní pohledy.

Proč to dělat? Kvůli dvěma věcem:

  1. Audit a dohledatelnost. Nevidíte jen „co platí teď“, ale celý příběh: kdy k čemu došlo a v jakém pořadí. To je velmi cenné ve financích, logistikách nebo všude tam, kde potřebujete vysvětlit, proč došlo k výsledku X.
  2. Zpětné přepočty. Když se změní pravidla reportingu či výpočtu metrik, nepřicházíte o historii – prostě události znovu „přehrajete“ a vytvoříte nové projekce.

Má to i nároky: je potřeba poctivá disciplína v návrhu událostí (jasná jména, verze, neměnitelnost), dobrá provozní dohledovost (monitoring projekcí, front, chyb) a tým, který rozumí práci s asynchronními procesy.

Jak se rozhodnout: jednoduché příklady „kdy co“

Představte si interní evidenci školení. Několik formulářů, pár seznamů, pár rolí. Tady je CRUD ideální: implementace je rychlá a přínos okamžitý.

Teď rezervace sportovišť s různými tarify, slevami, storny a s tisíci návštěvníky, kteří si jen prohlížejí dostupné časy. Část pro zápis musí přísně hlídat pravidla (nelze přeprodat), ale část pro čtení má velmi odlišné nároky – katalogy, vyhledávání, přehledy obsazenosti. CQRS se tu vyplatí: nebudete ohýbat jeden model pro obě potřeby, ale každou optimalizujete zvlášť.

Pokud navíc potřebujete dokazovat, co se přesně stalo – například ve finanční aplikaci, kde je pořadí operací zásadní – dává smysl přidat event sourcing. Díky němu lze kdykoli vysvětlit, odkud se vzal konkrétní zůstatek, a v případě změny výpočtu provést zpětné přepočty bez ztráty informací.

Praktické důsledky pro návrh, tým a provoz

Zavedení CQRS a případně event sourcingu znamená o něco větší architektonickou výbavu: messaging (fronty), projekce pro část pro čtení, mechanismy opakování a idempotence, nástroje pro „dohnání“ zpožděných projekcí a observabilitu (metriky, logy, trasování). Bez těchto věcí je těžké udržet systém spolehlivý.

To ale neznamená, že musíte začít „velkým třeskem“. Velmi dobře funguje evoluční postup:

  1. začněte CRUDem a dodejte rychle hodnotu;
  2. identifikujte nejpomalejší dotazy a pro ty vytvořte samostatný pohled pro část pro čtení (materializovanou tabulku, indexovaný pohled, dokumentovou kolekci);
  3. až budete potřebovat audit, začněte emitovat události – nejprve třeba jen pro auditní log;
  4. teprve když se to vyplatí, přejděte k plnému event sourcingu.

Tento přístup drží náklady i rizika pod kontrolou a dává výsledky rychle. O tom, proč je trefný návrh architektury důležitý už na začátku, píšeme podrobněji v samostatném textu na blogu.

Jak to obvykle vypadá technologicky (zkráceně)

V projektech na .NET často kombinujeme relační SQL Server pro část pro zápis s append-only uložištěm událostí (specializovaný event store nebo tabulky v SQL) a denormalizovanými pohledy pro část pro čtení. Důležitější než konkrétní produkt je konzistentní jazyk událostí a spolehlivé doručení do projekcí. Pokud vás zajímá širší kontext volby technologií na front-endu, mrkněte na náš rozcestník k Blazoru a klasickým frameworkům; pro jasný běh na dlouhou trať doporučujeme i text o dokumentaci.

Shrnutí: žádná ideologie, ale přiměřenost fázi projektu

  • CRUD je skvělý, pokud chcete rychle hotový produkt a vaše doména je spíše přímočará.
  • CQRS dává smysl, když potřebujete současně přísnou správnost zápisů a velmi rychlé, různorodé čtení.
  • Event sourcing přidejte tam, kde je klíčový audit historie a možnost zpětných přepočtů.

Nejlepší zpráva nakonec: nemusíte se rozhodnout jednou provždy. Architektura může růst spolu s vaším byznysem – a měla by.

Chcete probrat, co je pro váš případ nejvhodnější?
Rádi s vámi projdeme vaše use-case a navrhneme nejmenší změnu s největším efektem – od rychlého CRUDu až po CQRS s event sourcingem. Zastavte se na našem webu nebo nám rovnou napište.

Read more