Slovník pojmů

Domain-Driven Design

DDD pomáhá tam, kde je problém složitější než samotné uložení formuláře. Kód pak může mluvit o objednávkách, rezervacích a pravidlech stejným jazykem jako lidé, kteří jim rozumějí.

Stručná definice

Návrh kolem významu problému, ne kolem technické vrstvy.

Doména je část reality, kterou software řeší: v e-shopu například prodej, cena, sklad, doprava a platba. DDD vede vývojáře a doménové experty k tomu, aby pro ni vytvořili přesný model a používali jej v rozhovoru, požadavcích, testech i názvech v kódu.

Nejde o ORM, sadu složek ani povinnost zavést každý známý vzor. DDD je užitečné především tehdy, když nejasný význam slov, mnoho výjimek nebo měnící se pravidla začínají způsobovat chyby a drahé domluvy.

Jaký problém řeší

Nejasné pojmy a pravidla schovaná v technických detailech

Model založený jen na tabulkách často pojmenuje důležité rozhodnutí neurčitě jako status, flag nebo service. DDD hledá význam, hranici a vlastníka pravidla.

  • různý výklad téhož slova mezi obchodem, zákaznickou podporou a vývojem
  • pravidla objednávek, cen, rezervací nebo vratek rozesetá v controllerech a SQL
  • integrace marketplace, která používá stejné slovo v jiném významu než interní aplikace
  • změny business pravidel, jež se těžko dohledávají a testují
  • potřeba oddělit jádro důležité domény od obecné infrastruktury

Praktický příklad

Potvrzení marketplace objednávky a rezervace skladu

V kontextu Prodej může Order obsahovat OrderItem, Money a OrderStatus. Operace confirm() ověří, že objednávka má alespoň jednu položku, není zrušená a její cena odpovídá měně prodeje. Samotné volání skladu nepatří do objektu Order, protože vyžaduje externí systém; aplikační služba proto po ověření modelu požádá sklad o rezervaci a teprve pak změnu uloží v transakci.

Marketplace však může slovem „confirmed“ označit okamžik převzetí požadavku, zatímco interní Prodej jím označuje obchodně platnou objednávku. Překlad na hranici integrace zachová oba významy a zabrání tomu, aby externí status přímo přepsal interní pravidlo.

PHP

final class Order
{
    public function confirm(): void
    {
        if ($this->items === [] || $this->status !== OrderStatus::draft()) {
            throw new DomainException('Objednávku nelze potvrdit.');
        }

        $this->status = OrderStatus::confirmed();
    }
}

Zjednodušený diagram

Od doménové otázky k proveditelnému modelu

DDD není lineární proces; tento tok pouze ukazuje, jak se význam pravidla přenáší do kódu a zpět k lidem, kteří jej ověřují.

  1. Doména Lidé popíšou problém, například kdy smí e-shop potvrdit objednávku a rezervovat sklad.
  2. Ubiquitous language Tým zpřesní slova Order, reservation, payment authorization a jejich význam.
  3. Bounded context Význam platí uvnitř vymezené části, například Prodej; jiný systém může mít jiný model.
  4. Model a invarianty Entity, hodnoty a služby vyjadřují pravidla, která musí zůstat pravdivá.
  5. Aplikace a integrace Aplikační služba model použije, uloží změnu a přeloží ji pro databázi nebo cizí systém.

Hlavní části

Strategický pohled určuje hranice, taktický model pravidla uvnitř nich

Ne každá aplikace potřebuje všechny tyto stavební prvky. Důležitější je, aby zvolený model chránil skutečná rozhodnutí.

Doména a subdomény

Doména je celá oblast problému, kterou software řeší. Subdomény ji dělí podle odlišného účelu a složitosti, například na prodej, sklad a platby; největší pozornost obvykle potřebuje část s vlastním konkurenčním pravidlem, ne nutně každá podpůrná funkce.

Ubiquitous language

Sdílený jazyk je pracovní dohoda o významu slov. Pokud „objednávka“ znamená pro sklad něco jiného než pro platby, samotné stejné jméno chybu nevyřeší; je potřeba hranice.

Bounded context

Vymezuje, kde má model a jeho názvy platnost. Prodej může chápat zákazníka jako kupujícího, zatímco CRM jako kontakt s historií komunikace. Context není automaticky mikroservisa ani databáze.

Entity a value object

Entita má průběžnou identitu, například Order. Value object popisuje hodnotu a obvykle se porovnává obsahem, například Money nebo OrderStatus. Doctrine entita je technický způsob mapování, ne automatická DDD entita.

Aggregate a aggregate root

Aggregate je hranice konzistence pro malou skupinu objektů. Root je vstupní bod, přes který se mění stav a hlídají invarianty. Nevytváří se proto, že každá tabulka má dostat vlastní aggregate.

Domain service, event a repository

Domain service nese doménovou operaci, která přirozeně nepatří jednomu objektu. Domain event zaznamená významnou skutečnost. Repository v DDD poskytuje kolekci doménových objektů; není to Git repository ani nutně univerzální CRUD vrstva.

Jak funguje v aplikaci

Doménový model, aplikační postup a infrastruktura mají odlišnou úlohu

Taktický DDD model není náhradou všech vrstev aplikace. Pomáhá určit, kam patří rozhodnutí a kam jen převod dat nebo provedení příkazu.

Doménový model
Drží pojmy a invarianty, například že potvrzená objednávka musí mít položky, cenu v určené měně a úspěšně vytvořenou rezervaci.
Application service
Koordinuje use case: načte aggregate, zavolá doménovou operaci, zajistí transakci a předá výsledek dalšímu kroku. Nemá se změnit v druhé doméně plné pravidel.
Repository
Načítá a ukládá aggregate podle potřeb use case. Zda pod ním je Doctrine, SQL nebo externí zdroj, je implementační detail.
Anti-corruption layer
Překladová vrstva chrání vlastní model před cizím slovníkem a datovým formátem marketplace nebo účetního systému. Není nutně samostatný velký modul.

Výhody a omezení

Model má snižovat nedorozumění, ne přidávat ceremonie

Přínosy

  • pojmenovaná pravidla blízko modelu, který jim dává význam
  • lepší rozhovor s lidmi, kteří doménu znají
  • jasnější hranice mezi částmi systému s odlišným významem
  • testy mohou číst jako konkrétní obchodní scénáře místo technických kroků

Omezení a časté chyby

  • DDD není adresářová struktura ani povinnost přejmenovat CRUD na commandy
  • Value Object pro každou primitivní hodnotu může zhoršit čitelnost bez ochrany pravidla
  • přehnaně velké agregáty zvyšují konflikty a složitost transakcí
  • zavedení DDD bez kontaktu s doménovým expertem vytváří jen domnělý model

Pragmatičnost

Hloubku modelu vybírá složitost domény, ne ambice architektury.

Jednoduchý katalog, administrace obsahu nebo jednorázový import mohou být nejčitelnější s přímým formulářem, validací a několika tabulkami. Začít s malým názvoslovím a několika jasnými pravidly je často lepší než předem vytvořit entity, repository a eventy pro každé pole.

DDD pomáhá, když se pravidla opakují, mají výjimky a jejich porušení stojí peníze nebo důvěru. Struktura má odpovídat skutečné složitosti: model se může vyvíjet spolu s porozuměním týmu a nemusí v každém contextu vypadat stejně.

Na co myslet

Model ověřuje společný jazyk i případy na hraně

Dobré otázky ke změně odhalí více než mechanické použití vzoru.

  • pojmenovat pravidlo slovy, kterým rozumí doménový expert i vývojář
  • zapsat invarianty a příklady, při nichž musí operace selhat
  • oddělit stejné slovo s různým významem do vlastních contextů
  • nenutit databázovou strukturu, aby určovala API doménového modelu
  • testovat rozhodnutí modelu bez závislosti na HTTP nebo konkrétním ORM
  • průběžně revidovat, zda abstrakce stále chrání reálnou složitost

Časté otázky

DDD v praxi

Je DDD totéž co Clean Architecture?

Ne. DDD se soustředí na porozumění doméně, její jazyk a model. Clean Architecture řeší zejména směr závislostí a hranici technických detailů. Mohou se rozumně doplnit, ale každý přístup řeší jiný problém.

Musí být každá Doctrine entita DDD entitou?

Ne. Doctrine entita je objekt mapovaný na perzistenci. DDD entita je objekt s identitou a doménovým významem; někdy se kryjí, jindy je vhodné je oddělit.

Jsou agregáty nutné pro každou tabulku?

Ne. Aggregate je hranice konzistence pro konkrétní pravidla. Jeho velikost a existence se odvozují od invariantů a souběhu, ne od počtu tabulek.

Je bounded context samostatná mikroservisa?

Ne nutně. Je to především hranice modelu a jazyka. Může být modul v monolitu, samostatná služba nebo jen jasně oddělená část práce týmu.

Jak přistupuji k návrhu aplikací

Nejdřív potřebuji rozumět pravidlům, teprve potom volit technické hranice.

U složitějších procesů vyjasňuji význam pojmů, neobvyklé stavy a odpovědnost jednotlivých částí aplikace. Teprve podle nich volím míru modelu a automatizovaných kontrol.

Zavolejte mi

Zavolám vám následující pracovní den mezi 9:00 a 17:00.

Můžete mi také zavolat rovnou.

+420 605 181 728

Nechte mi telefonní číslo a pošlete žádost o zpětné zavolání.

Odesláním souhlasíte se zpracováním údajů pro vyřízení žádosti.