DDD vo frontende: kedy Domain-Driven Design dáva zmysel | POLPROG Prejsť na obsah

DDD vo frontende: kedy Domain-Driven Design dáva zmysel

Domain-Driven Design nie je konvencia priečinkov ani prístup vyhradený backendu. Jeho cieľom je zvládať zložité biznisové domény pomocou spoločného jazyka, explicitných modelov a jasných hraníc kontextov. Vo frontende môže byť DDD veľmi prínosné vo veľkých produktových aplikáciách, ale rovnako ľahko sa môže zmeniť na nákladnú nadmernú architektúru. Kľúčové je rozpoznať, kde klient skutočne obsahuje doménovú zložitosť a kde je najmä prezentačnou vrstvou.

Publikované Autor Čas čítania 20 min čítania

Domain-Driven Design nie je konvencia priečinkov ani prístup vyhradený backendu. Jeho cieľom je zvládať zložité biznisové domény pomocou spoločného jazyka, explicitných modelov a jasných hraníc kontextov. Vo frontende môže byť DDD veľmi prínosné vo veľkých produktových aplikáciách, ale rovnako ľahko sa môže zmeniť na nákladnú nadmernú architektúru. Kľúčové je rozpoznať, kde klient skutočne obsahuje doménovú zložitosť a kde je najmä prezentačnou vrstvou.

Na tejto stránke
  1. 1DDD nezačína priečinkom `domain`
  2. 2Strategické DDD a taktické DDD pracujú na rôznych úrovniach
  3. 3Bounded Context nie je technická vrstva
  4. 4Kedy DDD vo frontende dáva zmysel
  5. 5Kedy sa DDD stáva zbytočne zložitým
  6. 6Ubiquitous Language má byť viditeľný aj v UI kóde
  7. 7Veľký frontend organizujte podľa domén, nie iba podľa typov súborov
  8. 8Oddeľte prezentačné správanie od doménového správania
  9. 9Praktické vrstvy v jednom frontendovom kontexte
  10. 10API model a doménový model frontendu nemusia byť rovnaké
  11. 11Entities, Value Objects a Aggregates používajte selektívne
  12. 12UI stav nie je to isté ako doménový stav
  13. 13Hranice treba vynucovať, nie iba dokumentovať
  14. 14Frontend a backend môžu zdieľať doménu bez identického modelu
  15. 15Testovateľnosť je silný dôvod na izoláciu doménovej logiky
  16. 16Ako zaviesť DDD do existujúceho frontendu bez veľkého rewrite

DDD nezačína priečinkom `domain`

Eric Evans predstavuje DDD ako súbor vzorov a definícií pre prácu s doménovými modelmi, zatiaľ čo Martin Fowler zdôrazňuje modelovanie zložitých domén a rozvoj spoločného jazyka medzi vývojármi a doménovými expertmi. [1][2][4]

Štruktúra `domain/application/infrastructure` teda sama osebe neznamená DDD. Kód môže mať dokonale pomenované priečinky a pritom obsahovať iba DTO a procedurálnu logiku. Strategické DDD možno používať aj bez kanonickej vrstvenej štruktúry.

Strategické DDD a taktické DDD pracujú na rôznych úrovniach

Strategické DDD rieši rozdelenie väčšej domény na subdomény a Bounded Contexts a ich vzťahy. Microsoft opisuje doménovú analýzu ako identifikáciu subdomén a obmedzených kontextov, zatiaľ čo Fowler označuje Bounded Context za centrálny strategický vzor. [3][7]

Taktické DDD pracuje vnútri konkrétneho kontextu a zahŕňa napríklad Entities, Value Objects, Aggregates a Domain Services. Microsoft výslovne oddeľuje strategickú analýzu od taktického modelovania. [8]

Vo frontende je často lepšie začať strategickým návrhom a až potom rozhodnúť, ktoré kontexty skutočne potrebujú bohatý taktický model.

Bounded Context nie je technická vrstva

Fowler opisuje Bounded Context ako hranicu, vnútri ktorej zostáva model konzistentný a pojmy majú jednoznačný význam. Rovnaký pojem, napríklad `Customer` alebo `Product`, môže mať v rôznych kontextoch odlišný význam. [3]

Preto `frontend`, `backend`, `React app`, `route` ani `micro-frontend` nie sú automaticky Bounded Contexts. Hranice vychádzajú z doménového modelu a jazyka, nie z technológie. Praktické zdroje o frontendovom DDD upozorňujú na rovnakú zámenu. [15][16]

Kedy DDD vo frontende dáva zmysel

SignálSmerPrečo
Veľa meniacich sa biznisových pravidielDDDDoménový model bráni rozptýleniu pravidiel
Rovnaké pojmy znamenajú v rôznych častiach produktu niečo inéDDDBounded Contexts umožňujú viac konzistentných modelov
Spolupracuje viac tímov a doménových expertovDDDUbiquitous Language znižuje nejednoznačnosť
Jednoduché CRUD a formuláreJednoduchšia modularitaNáklady taktického DDD môžu prevýšiť prínos
Frontend prevažne zrkadlí APIJednoduchšia modularitaJe málo vlastnej klientovej doménovej logiky
Malá aplikácia s jednou konzistentnou doménouJednoduchšia modularitaĎalšie hranice a vrstvy môžu priniesť malú hodnotu

Najsilnejším signálom sú zložité a často sa meniace biznisové pravidlá na klientovi: konfigurátory, viacstupňové procesy, pricing, oprávnenia, prechody stavov, workflow alebo rozdielne modely rovnakého pojmu v rôznych častiach produktu.

DDD je užitočné aj vtedy, keď na veľkom produkte pracuje viac tímov a rovnaké slová majú v rôznych oblastiach iný význam. Bounded Contexts sú určené práve na správu viacerých konzistentných modelov. [3]

DDD Crew odporúča najprv pochopiť doménu, identifikovať strategicky dôležité subdomény, potom definovať zodpovednosti Bounded Contexts a až následne model kódovať. [10]

Kedy sa DDD stáva zbytočne zložitým

Ak frontend hlavne načítava dáta, zobrazuje ich, upravuje formuláre a odosiela jednoduché CRUD príkazy bez významnej biznisovej logiky na klientovi, kompletná sada taktických vzorov DDD zvyčajne nerieši skutočný problém.

Microsoft výslovne uvádza, že pre jednoduchý CRUD kontext môže stačiť anemický dátový model a zložitejšie vzory DDD nemusia stáť za náklady. Bohatší model je vhodnejší tam, kde existuje veľa meniacich sa biznisových pravidiel. [9]

Rovnaké kritérium platí aj vo frontende: zložitosť architektúry má zodpovedať zložitosti domény, nie technickým ambíciám tímu.

Ubiquitous Language má byť viditeľný aj v UI kóde

Ubiquitous Language je spoločný a presný jazyk vytváraný vývojármi a doménovými expertmi okolo modelu. Fowler zdôrazňuje, že sa má vyvíjať spolu s porozumením doméne. [4]

Vo frontende by názvy use case, akcií, typov, modulov, obrazoviek a stavov mali používať biznisový slovník vždy, keď vyjadrujú doménové správanie.

Ak biznis hovorí `approveApplication`, ale kód používa `setFlag2` alebo `handleData`, kód prestáva byť zrozumiteľným vyjadrením doménového jazyka.

Veľký frontend organizujte podľa domén, nie iba podľa typov súborov

Fowler uvádza, že štruktúra najvyššej úrovne `view/model/data` môže stačiť pri menších systémoch, ale s rastom je často lepšie mať top-level moduly podľa domén, ktoré si vo vnútri zachovávajú vlastné vrstvy. [5]

Aktuálna dokumentácia Nx ukazuje podobný smer: priečinky môžu tvoriť hranice ownershipu domén a knižnice v doméne možno klasifikovať ako `feature`, `ui`, `data-access` a `util`. [12]

Praktická štruktúra teda môže vyzerať ako `libs/orders/...`, `libs/billing/...`, `libs/identity/...` namiesto jedného globálneho stromu `components/`, `services/`, `models/`.

Oddeľte prezentačné správanie od doménového správania

Fowler opisuje oddelenie prezentácie, doménovej logiky a prístupu k dátam ako účinnú modularizáciu. UI kód sa tiež zvyčajne testuje ťažšie, preto má doménová logika mimo prezentácie výhodu. [5][6]

Frontendový komponent by mal primárne renderovať, obsluhovať UI udalosti a delegovať operácie. Pravidlá ako či možno objednávku zrušiť, ako vypočítať zľavu alebo aký prechod stavu je povolený, majú mať explicitné miesto mimo JSX, šablón alebo komponentových tried.

To neznamená zákaz prezentačnej logiky. Validácia pohľadu, viditeľnosť, lokálny focus alebo animácia sú iný druh logiky než biznisové pravidlá.

Praktické vrstvy v jednom frontendovom kontexte

VrstvaZodpovednosťPríklady
presentation / uiRenderovanie a správanie rozhraniacomponents, routes, view state
applicationKoordinácia use casecommands, use cases, orchestration
domainDoménové pravidlá, pojmy a invariantyentities, value objects, policies
infrastructure / data-accessTechnické integrácieHTTP, storage, SDKs, mappers

DDD nepredpisuje povinnú štruktúru priečinkov. Oddelenie `presentation`, `application`, `domain` a `infrastructure` je praktická interpretácia separácie zodpovedností, nie formálna požiadavka Evansa. [1][5]

Vrstva domain môže obsahovať pravidlá, pojmy a správanie nezávislé od frameworku; application koordinuje use case; infrastructure adaptuje HTTP, storage a externé SDK; presentation obsahuje komponenty, routing a čisto UI stav.

API model a doménový model frontendu nemusia byť rovnaké

Bounded Context môže mať vlastný model určitého pojmu a rôzne kontexty môžu mapovať medzi rozdielnymi reprezentáciami. Fowler používa `Customer` a `Product` ako typické príklady pojmov s odlišným významom podľa kontextu. [3]

Backendové DTO preto nemusí prúdiť priamo do každého komponentu. Mapper alebo adapter môže transportný kontrakt previesť do modelu konkrétneho frontendového kontextu.

Takáto hranica je najcennejšia, keď API používa viac klientov, je legacy, kombinuje viac domén alebo sa vyvíja nezávisle. Pri jednoduchom CRUD endpointe môže byť ďalšia mapping vrstva zbytočná.

Entities, Value Objects a Aggregates používajte selektívne

DDD rozlišuje napríklad Entities, Value Objects, Services a Aggregates. Fowler ich uvádza ako súčasť Evansovho slovníka a Microsoft opisuje agregáty ako taktický vzor pre udržiavanie konzistencie modelu. [2][8]

Frontend by nemal kopírovať backendový model 1:1 iba kvôli rovnakým triedam. Value Object je užitočný pre `Money`, `DateRange` alebo `Email`, ak chráni skutočné invarianty. Aggregate dáva zmysel, ak klient reálne potrebuje strážiť pravidlá konzistencie.

Ak typ slúži len ako dáta pre tabuľku, jednoduchý TypeScript typ môže byť lepší než Entity, Factory, Repository a Service.

UI stav nie je to isté ako doménový stav

React považuje organizáciu stavu za návrhový problém a odporúča vyhýbať sa redundantnému alebo duplicitnému stavu. Je to dobrý technický základ, ale reducery, stores alebo signals samy osebe nevytvárajú doménový model. [14]

Stav ako `isModalOpen`, aktívna záložka alebo pozícia scrollu patrí prezentácii. Životný cyklus objednávky, povolené prechody procesu alebo pravidlá konfigurátora môžu patriť do doménového modelu.

Oddelenie týchto kategórií obmedzuje globálne stores, ktoré miešajú serverové dáta, biznisové správanie a UI detaily.

Hranice treba vynucovať, nie iba dokumentovať

Nx umožňuje definovať projektové tagy a deklaratívne obmedzenia závislostí, napríklad blokovať importy medzi scope alebo typmi knižníc. `@nx/enforce-module-boundaries` môže importy kontrolovať počas lintovania. [11]

Nx podporuje aj viac dimenzií tagov, takže možno samostatne modelovať `scope`, typ knižnice, stabilitu alebo client/server aspekty. [13]

Rozhodnutia DDD sa tak môžu stať pravidlami CI: `billing` neimportuje interné časti `identity`, `ui` nezávisí od `data-access` a `domain` zostáva nezávislý od frameworku.

Frontend a backend môžu zdieľať doménu bez identického modelu

Bounded Context je hranicou modelu a jazyka, preto by sa nemal automaticky kresliť pozdĺž sieťovej hranice medzi prehliadačom a serverom. Praktické materiály o frontendovom DDD zdôrazňujú, že kontexty môžu prechádzať technickými vrstvami a byť realizované spoločne frontendom aj backendom. [15][16]

Klientská reprezentácia sa napriek tomu môže líšiť od serverovej kvôli odlišným potrebám interakcie, lokálneho stavu a prezentácie. Dôležitá je správna sémantika a explicitné mapovanie, nie kopírovanie tried.

Micro-frontend tiež nemá vzniknúť iba preto, že existuje Bounded Context. Doménová hranica a hranica deployovateľného artefaktu sú dve odlišné rozhodnutia.

Testovateľnosť je silný dôvod na izoláciu doménovej logiky

Fowler uvádza testovateľnosť ako výhodu oddelenia prezentácie od domény. Logiku mimo UI možno testovať bez renderovania komponentov a bez závislosti od detailov rozhrania. [5][6]

Vo frontende to umožňuje rýchle testy pravidiel, Value Objects, use case a prechodov stavov ako bežného TypeScriptu alebo JavaScriptu. Komponentové testy zostávajú potrebné, ale nemusia byť jediným miestom overovania biznisových pravidiel.

Varovným signálom je stav, keď každá zmena biznisového pravidla vyžaduje mount celej komponenty a mock routera, store, HTTP a browser API.

Ako zaviesť DDD do existujúceho frontendu bez veľkého rewrite

DDD Crew odporúča iteratívny proces: pochopiť doménu, určiť dôležité subdomény, definovať zodpovednosti Bounded Contexts a až potom kódovať model. [10]

V existujúcom frontende je bezpečnejšie vybrať jednu problémovú oblasť, pomenovať jej jazyk, stanoviť hranicu, oddeliť prezentáciu od pravidiel, definovať verejné API modulu a až potom migrovať ďalšie funkcie.

Celú aplikáciu netreba prerábať. DDD možno použiť tam, kde biznisová zložitosť vráti náklady na modelovanie, a jednoduché oblasti ponechať ako ľahšie feature moduly.

  • Začnite biznisovým problémom, nie priečinkami.
  • Identifikujte pojmy, pravidlá a nejednoznačné termíny.
  • Definujte jeden Bounded Context a jeho verejný kontrakt.
  • Oddeľte doménové pravidlá od komponentov a transportných DTO.
  • Pridávajte iba taktické vzory, ktoré riešia konkrétnu zložitosť.
  • Zapíšte hranice ako lint alebo CI pravidlá.
  • Merajte závislosti, cykly, regresie a náklady priečnych zmien.
  • Nemigrujte jednoduché CRUD oblasti iba kvôli architektonickej symetrii.

DDD vo frontende dáva zmysel, keď je klient súčasťou zložitého produktu a nie iba rendererom dát. Najväčšiu hodnotu zvyčajne prináša strategické DDD: spoločný jazyk, hranice kontextov a reálne vynucované modulárne hranice. Taktické vzory je vhodné pridávať iba tam, kde pravidlá, invarianty a správanie odôvodňujú bohatší model. Ak je aplikácia prevažne CRUD, formuláre a priame zobrazovanie API, dobrá modularita a oddelenie prezentácie od dát bývajú lepšie než plné DDD.

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

Často kladené otázky

Dáva DDD vo frontende zmysel?

Áno, ak frontend pracuje so zložitou doménou a ťaží z explicitných hraníc, spoločného jazyka alebo klientských biznisových pravidiel. DDD nie je iba pre backend. [1][2][15]

Mal by každý frontend používať DDD?

Nie. Pre jednoduché CRUD aplikácie môže byť plné taktické DDD zbytočné. Microsoft výslovne uvádza, že jednoduché CRUD kontexty nie vždy potrebujú bohatý model. [9]

Je frontend samostatný Bounded Context?

Nie automaticky. Bounded Context je hranica konzistentného modelu a jazyka, nie technológie. [3][16]

Má sa každý Bounded Context stať micro-frontendom?

Nie. Doménová hranica nevyžaduje samostatný deployment. Micro-frontend architektúra je ďalšie rozhodnutie. [3][15]

Potrebujem priečinok domain?

Nie. DDD nepredpisuje povinnú štruktúru adresárov. Priečinok môže pomôcť, ale sám nevytvorí doménový model. [1][5]

Kam patrí biznisová logika vo frontende?

Mimo čistej prezentácie, do explicitného modelu alebo use-case vrstvy daného kontextu. Fowler odporúča oddelenie prezentácie a doménovej logiky. [5][6]

Môže byť API DTO doménovým modelom?

V triviálnom prípade áno, ale nemusí. Rôzne kontexty môžu rovnaký pojem modelovať odlišne, takže mapovanie býva vhodné. [3]

Má Repository vo frontende zmysel?

Iba ak rieši skutočný problém abstrakcie prístupu k modelu. Pre jednoduché načítanie dát môže byť ďalšie Repository zbytočné. [1][9]

Sú Redux, NgRx, Zustand alebo Signals súčasťou DDD?

Nie. Sú to mechanizmy správy stavu. Môžu uchovávať doménový stav, ale nedefinujú model, jazyk ani Bounded Context. [14]

Má byť frontendový doménový model identický s backendom?

Nie. Musí zachovať správnu doménovú sémantiku, ale reprezentácia sa môže prispôsobiť potrebám klienta. [3]

Ako v monorepe vynútiť doménové hranice?

Nx môže použiť tagy a @nx/enforce-module-boundaries na automatické blokovanie zakázaných závislostí. [11][13]

Kde začať v existujúcej aplikácii?

Pri jednej zložitej biznisovej oblasti: pochopiť jej jazyk, pravidlá a hranicu. DDD Crew odporúča iteratívnu cestu od domény ku kontextom a kódu. [10]

Zdroje a referencie

  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

Bolo to užitočné?

Získavajte nové články e-mailom

Jeden krátky e-mail na každý nový článok Vzdelávania. Žiadny spam, odhlásenie jedným kliknutím.

Váš e-mail používame len na zasielanie nových článkov. Žiadne zdieľanie s tretími stranami.

Späť na Vzdelávanie