DDD ve frontendu: kdy Domain-Driven Design dává smysl | POLPROG Přejít na obsah

DDD ve frontendu: kdy Domain-Driven Design dává smysl

Domain-Driven Design není konvence složek ani přístup vyhrazený backendu. Jeho cílem je zvládat složité byznysové domény pomocí společného jazyka, explicitních modelů a jasných hranic kontextů. Ve frontendu může být DDD velmi přínosné ve velkých produktových aplikacích, ale stejně snadno se může změnit v nákladnou nadměrnou architekturu. Klíčové je poznat, kde klient skutečně obsahuje doménovou složitost a kde je hlavně prezentační vrstvou.

Publikováno Autor Čas čtení 20 min čtení

Domain-Driven Design není konvence složek ani přístup vyhrazený backendu. Jeho cílem je zvládat složité byznysové domény pomocí společného jazyka, explicitních modelů a jasných hranic kontextů. Ve frontendu může být DDD velmi přínosné ve velkých produktových aplikacích, ale stejně snadno se může změnit v nákladnou nadměrnou architekturu. Klíčové je poznat, kde klient skutečně obsahuje doménovou složitost a kde je hlavně prezentační vrstvou.

Na této stránce
  1. 1DDD nezačíná složkou `domain`
  2. 2Strategické DDD a taktické DDD pracují na různých úrovních
  3. 3Bounded Context není technická vrstva
  4. 4Kdy DDD ve frontendu dává smysl
  5. 5Kdy se DDD stává zbytečně složitým
  6. 6Ubiquitous Language má být viditelný i v UI kódu
  7. 7Velký frontend organizujte podle domén, ne jen podle typů souborů
  8. 8Oddělte prezentační chování od doménového chování
  9. 9Praktické vrstvy uvnitř jednoho frontendového kontextu
  10. 10API model a doménový model frontendu nemusí být stejné
  11. 11Entities, Value Objects a Aggregates používejte selektivně
  12. 12UI stav není totéž co doménový stav
  13. 13Hranice je potřeba vynucovat, ne jen dokumentovat
  14. 14Frontend a backend mohou sdílet doménu bez identického modelu
  15. 15Testovatelnost je silný důvod pro izolaci doménové logiky
  16. 16Jak zavést DDD do existujícího frontendu bez velkého rewrite

DDD nezačíná složkou `domain`

Eric Evans představuje DDD jako soubor vzorů a definic pro práci s doménovými modely, zatímco Martin Fowler zdůrazňuje modelování složitých domén a rozvoj společného jazyka mezi vývojáři a doménovými experty. [1][2][4]

Struktura `domain/application/infrastructure` tedy sama o sobě neznamená DDD. Kód může mít perfektně pojmenované složky a přitom obsahovat jen DTO a procedurální logiku. Strategické DDD lze použít i bez kanonické vrstvené struktury.

Strategické DDD a taktické DDD pracují na různých úrovních

Strategické DDD řeší rozdělení větší domény na subdomény a Bounded Contexts a jejich vztahy. Microsoft popisuje doménovou analýzu jako identifikaci subdomén a omezených kontextů, zatímco Fowler označuje Bounded Context za centrální strategický vzor. [3][7]

Taktické DDD pracuje uvnitř konkrétního kontextu a zahrnuje například Entities, Value Objects, Aggregates a Domain Services. Microsoft výslovně odděluje strategickou analýzu od taktického modelování. [8]

Ve frontendu je často lepší začít strategickým návrhem a až potom rozhodnout, které kontexty skutečně potřebují bohatý taktický model.

Bounded Context není technická vrstva

Fowler popisuje Bounded Context jako hranici, uvnitř které zůstává model konzistentní a pojmy mají jednoznačný význam. Stejný pojem, například `Customer` nebo `Product`, může mít v různých kontextech odlišný význam. [3]

Proto `frontend`, `backend`, `React app`, `route` ani `micro-frontend` nejsou automaticky Bounded Contexts. Hranice vycházejí z doménového modelu a jazyka, ne z technologie. Praktické zdroje o frontendovém DDD upozorňují na stejnou záměnu. [15][16]

Kdy DDD ve frontendu dává smysl

SignálSměrProč
Mnoho měnících se byznysových pravidelDDDDoménový model brání rozptýlení pravidel
Stejné pojmy znamenají v různých částech produktu něco jinéhoDDDBounded Contexts umožňují několik konzistentních modelů
Spolupracuje více týmů a doménových expertůDDDUbiquitous Language snižuje nejednoznačnost
Jednoduché CRUD a formulářeJednodušší modularitaNáklady taktického DDD mohou převýšit přínos
Frontend převážně zrcadlí APIJednodušší modularitaJe málo vlastní klientské doménové logiky
Malá aplikace s jednou konzistentní doménouJednodušší modularitaDalší hranice a vrstvy mohou přinést malou hodnotu

Nejsilnějším signálem jsou složitá a často se měnící byznysová pravidla na klientovi: konfigurátory, vícekrokové procesy, pricing, oprávnění, přechody stavů, workflow nebo rozdílné modely stejného pojmu v různých částech produktu.

DDD je také užitečné, když na velkém produktu pracuje více týmů a stejná slova mají v různých oblastech jiný význam. Bounded Contexts jsou určeny právě pro správu několika konzistentních modelů. [3]

DDD Crew doporučuje nejprve porozumět doméně, identifikovat strategicky důležité subdomény, potom definovat odpovědnosti Bounded Contexts a teprve následně model kódovat. [10]

Kdy se DDD stává zbytečně složitým

Pokud frontend hlavně načítá data, zobrazuje je, upravuje formuláře a odesílá jednoduché CRUD příkazy bez významné byznysové logiky na klientovi, kompletní sada taktických vzorů DDD obvykle neřeší skutečný problém.

Microsoft výslovně uvádí, že pro jednoduchý CRUD kontext může stačit anemický datový model a složitější vzory DDD nemusí stát za náklady. Bohatší model je vhodnější, když existuje mnoho měnících se byznysových pravidel. [9]

Stejné kritérium platí i ve frontendu: složitost architektury má odpovídat složitosti domény, ne technickým ambicím týmu.

Ubiquitous Language má být viditelný i v UI kódu

Ubiquitous Language je společný a přesný jazyk vytvářený vývojáři a doménovými experty kolem modelu. Fowler zdůrazňuje, že se má vyvíjet spolu s porozuměním doméně. [4]

Ve frontendu by názvy use case, akcí, typů, modulů, obrazovek a stavů měly používat byznysový slovník vždy, když vyjadřují doménové chování.

Pokud byznys říká `approveApplication`, ale kód používá `setFlag2` nebo `handleData`, kód přestává být srozumitelným vyjádřením doménového jazyka.

Velký frontend organizujte podle domén, ne jen podle typů souborů

Fowler uvádí, že struktura nejvyšší úrovně `view/model/data` může stačit u menších systémů, ale s růstem je často lepší mít top-level moduly podle domén, které si uvnitř zachovávají vlastní vrstvy. [5]

Aktuální dokumentace Nx ukazuje podobný směr: složky mohou tvořit hranice ownershipu domén a knihovny uvnitř domény lze klasifikovat jako `feature`, `ui`, `data-access` a `util`. [12]

Praktická struktura tedy může vypadat jako `libs/orders/...`, `libs/billing/...`, `libs/identity/...` místo jednoho globálního stromu `components/`, `services/`, `models/`.

Oddělte prezentační chování od doménového chování

Fowler popisuje oddělení prezentace, doménové logiky a přístupu k datům jako účinnou modularizaci. UI kód se také obvykle testuje obtížněji, proto má doménová logika mimo prezentaci výhodu. [5][6]

Frontendová komponenta by měla primárně renderovat, obsluhovat UI události a delegovat operace. Pravidla jako zda lze objednávku zrušit, jak spočítat slevu nebo jaký přechod stavu je povolený, mají mít explicitní místo mimo JSX, šablony nebo komponentní třídy.

To neznamená zákaz prezentační logiky. Validace pohledu, viditelnost, lokální focus nebo animace jsou jiný typ logiky než byznysová pravidla.

Praktické vrstvy uvnitř jednoho frontendového kontextu

VrstvaOdpovědnostPříklady
presentation / uiRenderování a chování rozhranícomponents, routes, view state
applicationKoordinace use casecommands, use cases, orchestration
domainDoménová pravidla, pojmy a invariantyentities, value objects, policies
infrastructure / data-accessTechnické integraceHTTP, storage, SDKs, mappers

DDD nepředepisuje povinnou strukturu složek. Oddělení `presentation`, `application`, `domain` a `infrastructure` je praktická interpretace separace odpovědností, ne formální požadavek Evansa. [1][5]

Vrstva domain může obsahovat pravidla, pojmy a chování nezávislé na frameworku; application koordinuje use case; infrastructure adaptuje HTTP, storage a externí SDK; presentation obsahuje komponenty, routing a čistě UI stav.

API model a doménový model frontendu nemusí být stejné

Bounded Context může mít vlastní model určitého pojmu a různé kontexty mohou mapovat mezi různými reprezentacemi. Fowler používá `Customer` a `Product` jako typické příklady pojmů s odlišným významem podle kontextu. [3]

Backendové DTO proto nemusí proudit přímo do každé komponenty. Mapper nebo adapter může transportní kontrakt převést do modelu konkrétního frontendového kontextu.

Taková hranice je nejcennější, když API používá více klientů, je legacy, kombinuje více domén nebo se vyvíjí nezávisle. U jednoduchého CRUD endpointu může být další mapping vrstva zbytečná.

Entities, Value Objects a Aggregates používejte selektivně

DDD rozlišuje například Entities, Value Objects, Services a Aggregates. Fowler je uvádí jako součást Evansova slovníku a Microsoft popisuje agregáty jako taktický vzor pro udržování konzistence modelu. [2][8]

Frontend by neměl kopírovat backendový model 1:1 jen kvůli stejným třídám. Value Object je užitečný pro `Money`, `DateRange` nebo `Email`, pokud chrání skutečné invarianty. Aggregate dává smysl, pokud klient skutečně potřebuje hlídat konzistenční pravidla.

Pokud typ slouží jen jako data pro tabulku, může být jednoduchý TypeScript typ lepší než Entity, Factory, Repository a Service.

UI stav není totéž co doménový stav

React považuje organizaci stavu za návrhový problém a doporučuje vyhnout se redundantnímu nebo duplicitnímu stavu. Je to dobrý technický základ, ale reducery, store nebo signals samy o sobě nevytvářejí doménový model. [14]

Stav jako `isModalOpen`, aktivní záložka nebo pozice scrollu patří prezentaci. Životní cyklus objednávky, povolené přechody procesu nebo pravidla konfigurátoru mohou patřit do doménového modelu.

Oddělení těchto kategorií omezuje globální store, které míchají serverová data, byznysové chování a UI detaily.

Hranice je potřeba vynucovat, ne jen dokumentovat

Nx umožňuje definovat projektové tagy a deklarativní omezení závislostí, například blokovat importy mezi scope nebo typy knihoven. `@nx/enforce-module-boundaries` může importy kontrolovat během lintování. [11]

Nx podporuje i více dimenzí tagů, takže lze zvlášť modelovat `scope`, typ knihovny, stabilitu nebo client/server aspekty. [13]

Rozhodnutí DDD se tak mohou stát pravidly CI: `billing` neimportuje interní části `identity`, `ui` nezávisí na `data-access` a `domain` zůstává nezávislý na frameworku.

Frontend a backend mohou sdílet doménu bez identického modelu

Bounded Context je hranicí modelu a jazyka, proto by se neměl automaticky kreslit podél síťové hranice mezi prohlížečem a serverem. Praktické materiály o frontendovém DDD zdůrazňují, že kontexty mohou procházet technickými vrstvami a být realizovány společně frontendem i backendem. [15][16]

Klientská reprezentace se přesto může lišit od serverové kvůli jiným potřebám interakce, lokálního stavu a prezentace. Důležitá je správná sémantika a explicitní mapping, ne kopírování tříd.

Micro-frontend také nemá vzniknout jen proto, že existuje Bounded Context. Doménová hranice a hranice deployovatelného artefaktu jsou dvě různá rozhodnutí.

Testovatelnost je silný důvod pro izolaci doménové logiky

Fowler uvádí testovatelnost jako výhodu oddělení prezentace od domény. Logiku mimo UI lze testovat bez renderování komponent a bez závislosti na detailech rozhraní. [5][6]

Ve frontendu to umožňuje rychlé testy pravidel, Value Objects, use case a přechodů stavů jako běžného TypeScriptu nebo JavaScriptu. Komponentní testy zůstávají potřebné, ale nemusí být jediným místem ověřování byznysových pravidel.

Varovným signálem je stav, kdy každá změna byznysového pravidla vyžaduje mount celé komponenty a mock routeru, store, HTTP a browser API.

Jak zavést DDD do existujícího frontendu bez velkého rewrite

DDD Crew doporučuje iterativní proces: porozumět doméně, určit důležité subdomény, definovat odpovědnosti Bounded Contexts a teprve potom kódovat model. [10]

V existujícím frontendu je bezpečnější vybrat jednu problémovou oblast, pojmenovat její jazyk, stanovit hranici, oddělit prezentaci od pravidel, definovat veřejné API modulu a až poté migrovat další funkce.

Celou aplikaci není nutné převádět. DDD lze použít tam, kde byznysová složitost vrátí náklady na modelování, a jednoduché oblasti ponechat jako lehčí feature moduly.

  • Začněte byznysovým problémem, ne složkami.
  • Identifikujte pojmy, pravidla a nejednoznačné termíny.
  • Definujte jeden Bounded Context a jeho veřejný kontrakt.
  • Oddělte doménová pravidla od komponent a transportních DTO.
  • Přidávejte jen taktické vzory, které řeší konkrétní složitost.
  • Zapište hranice jako lint nebo CI pravidla.
  • Měřte závislosti, cykly, regrese a náklady průřezových změn.
  • Nemigrujte jednoduché CRUD oblasti jen kvůli architektonické symetrii.

DDD ve frontendu dává smysl, když je klient součástí složitého produktu a ne pouze rendererem dat. Největší hodnotu obvykle přináší strategické DDD: společný jazyk, hranice kontextů a skutečně vynucené modulární hranice. Taktické vzory je vhodné přidávat jen tam, kde pravidla, invarianty a chování odůvodňují bohatší model. Pokud je aplikace převážně CRUD, formuláře a přímé zobrazování API, dobrá modularita a oddělení prezentace od dat bývají lepší než plné DDD.

DDD Domain-Driven Design Frontend Architecture Software Architecture Bounded Context Ubiquitous Language TypeScript Nx React Angular

Často kladené otázky

Dává DDD ve frontendu smysl?

Ano, pokud frontend pracuje se složitou doménou a těží z explicitních hranic, společného jazyka nebo klientských byznysových pravidel. DDD není jen pro backend. [1][2][15]

Měl by každý frontend používat DDD?

Ne. Pro jednoduché CRUD aplikace může být plné taktické DDD zbytečné. Microsoft výslovně uvádí, že jednoduché CRUD kontexty ne vždy potřebují bohatý model. [9]

Je frontend samostatný Bounded Context?

Ne automaticky. Bounded Context je hranice konzistentního modelu a jazyka, ne technologie. [3][16]

Má se každý Bounded Context stát micro-frontendem?

Ne. Doménová hranice nevyžaduje samostatný deployment. Micro-frontend architektura je další rozhodnutí. [3][15]

Potřebuji složku domain?

Ne. DDD nepředepisuje povinnou strukturu adresářů. Složka může pomoci, ale sama nevytvoří doménový model. [1][5]

Kam patří byznysová logika ve frontendu?

Mimo čistou prezentaci, do explicitního modelu nebo use-case vrstvy daného kontextu. Fowler doporučuje oddělení prezentace a doménové logiky. [5][6]

Může být API DTO doménovým modelem?

V triviálním případě ano, ale nemusí. Různé kontexty mohou stejný pojem modelovat odlišně, takže mapping bývá vhodný. [3]

Má Repository ve frontendu smysl?

Jen pokud řeší skutečný problém abstrakce přístupu k modelu. Pro jednoduché načtení dat může být další Repository zbytečné. [1][9]

Jsou Redux, NgRx, Zustand nebo Signals součástí DDD?

Ne. Jsou to mechanismy správy stavu. Mohou uchovávat doménový stav, ale nedefinují model, jazyk ani Bounded Context. [14]

Má být frontendový doménový model identický s backendem?

Ne. Musí zachovat správnou doménovou sémantiku, ale reprezentace se může přizpůsobit potřebám klienta. [3]

Jak v monorepu vynutit doménové hranice?

Nx může použít tagy a @nx/enforce-module-boundaries k automatickému blokování zakázaných závislostí. [11][13]

Kde začít v existující aplikaci?

U jedné složité byznysové oblasti: pochopit její jazyk, pravidla a hranici. DDD Crew doporučuje iterativní cestu od domény ke kontextům a kódu. [10]

Zdroje a reference

  1. Eric Evans, DDD Reference12345
  2. Martin Fowler, Domain Driven Design123
  3. Martin Fowler, Bounded Context12345678
  4. Martin Fowler, Ubiquitous Language12
  5. Martin Fowler, Presentation Domain Data Layering123456
  6. Martin Fowler, Presentation Domain Separation123
  7. Microsoft Azure Architecture Center, Use Domain Analysis to Model Microservices
  8. Microsoft Azure Architecture Center, Use Tactical DDD to Design Microservices12
  9. Microsoft .NET, Design a microservice domain model123
  10. DDD Crew, DDD Starter Modelling Process123
  11. Nx, Enforce Module Boundaries12
  12. Nx, Monorepo Folder Structure
  13. Nx, Tag in Multiple Dimensions12
  14. React, Managing State12
  15. ANGULARarchitects, DDD in Angular & Frontend Architecture1234
  16. Tomasz Ducin, Your Frontend itself is NOT a Bounded Context123

Bylo to užitečné?

Odebírejte nové články e-mailem

Jeden krátký e-mail na každý nový článek znalostní báze. Žádný spam, odhlášení jedním kliknutím.

Váš e-mail používáme pouze k zasílání nových článků. Žádné sdílení s třetími stranami.

Zpět do znalostní báze