Kdy DDD nepoužívat - upřímně

DDD není architektura pro každý projekt. Špatně zvolená aplikace DDD přidává vrstvy abstrakce, zpomaluje vývoj a frustruje tým - aniž by přinesla cokoliv hodnotného. Tato kapitola říká přímo, kdy DDD vynechat, a co místo toho použít.

Předchozí kapitola ukázala kde DDD v praxi bolí, i když je nasazeno správně. Tato kapitola se věnuje situacím, kde DDD nasazovat nemá smysl. Je to pohled, který DDD literatura – soustředěná přirozeně na to, kdy vzor použít – zpravidla nerozvádí dostatečně.

Rozhodovací strom: Mám použít DDD?

Než se ponoříte do jednotlivých situací, projděte si pět otázek. Pokud na kteroukoli odpovíte „ne", DDD pravděpodobně není ta správná volba - nebo ještě ne.

Rozhodovací strom: Mám použít DDD?Rozhodovací strom: Mám použít DDD?Nový projekt / architektonické rozhodnutíDDD nepotřebuješ-> EasyAdmin / Flat MVCneKomplexní doménová logika?(ne jen CRUD)anoDDD se nevyplatí-> Symfony Controller + DoctrineneProjekt bude žít > 1 rok?anoDDD bez expertů = hádání-> Vrstvená architekturanePřístup k doménovýmexpertům?anoPseudo-DDD je horšínež žádné DDD-> Architektura, kterou tým znáneTým zná DDDnebo má čas se učit?anoPočkej na stabilizaci-> Flat MVC, DDD pozdějineDoména je stabilní?(ne pivot každý sprint)anoDDD dává smysl-> Strategický i taktický design

Každá z těchto pěti bran odpovídá jedné nebo více sekcím níže, které jsou podrobně popsány v dalším textu.

1. CRUD admin a jednoduchý backoffice

Typickým příkladem je aplikace, kde uživatel vytvoří záznam, upraví ho a smaže. Formulář mapuje 1:1 na tabulku. Žádná doménová logika – jen persistence.

DDD zde přidá agregáty, repozitáře, doménové události a value objekty pro věci, které jsou přirozeně jenom řádky v databázi. Výsledek: 5× více kódu, žádná přidaná hodnota.

Eric Evans to v Domain-Driven Design říká explicitně: DDD má smysl pro komplexní doménovou logiku. CRUD operace komplexní doménovou logiku nemají - jsou to operace nad daty bez business pravidel.

Srovnání: DDD vs. jednoduchý přístup pro CRUD admin

<?php
// ❌ Over-engineered DDD přístup pro prostý CRUD
// -- 6 tříd pro jednu operaci --

final class ArticleTitle {                          // Value Object
    public function __construct(private string $value) {
        if (strlen($value) === 0) throw new \InvalidArgumentException('...');
    }
    public function value(): string { return $this->value; }
}

final class Article {                               // Aggregate Root
    private ArticleTitle $title;
    private array $domainEvents = [];

    public static function create(ArticleTitle $title): self { /* ... */ }
    public function rename(ArticleTitle $newTitle): void {
        $this->title = $newTitle;
        $this->domainEvents[] = new ArticleRenamed($this->id, $newTitle);
    }
}

interface ArticleRepository { /* ... */ }           // Repository interface
final class DoctrineArticleRepository { /* ... */ } // Repository implementation
final class RenameArticleCommand { /* ... */ }      // Command
final class RenameArticleHandler {                  // Command Handler
    public function __invoke(RenameArticleCommand $cmd): void { /* ... */ }
}
<?php
// ✅ Jednoduchý přístup - EasyAdmin CRUD controller
// -- 1 třída, hotovo --

namespace App\Controller\Admin;

use App\Entity\Article;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
use EasyCorp\Bundle\EasyAdminBundle\Field\IdField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;

class ArticleCrudController extends AbstractCrudController
{
    public static function getEntityFqcn(): string
    {
        return Article::class;
    }

    public function configureFields(string $pageName): iterable
    {
        return [
            IdField::new('id')->hideOnForm(),
            TextField::new('title', 'Název článku'),
        ];
    }
}
Doporučené alternativy:
  • EasyAdmin - pro backoffice a CMS adminy. Konfigurací, ne kódem.
  • Symfony Forms + Doctrine Entity přímo v controlleru - pro jednoduchý CRUD bez business logiky.
Doménový model zavádíte tehdy, když máte doménu. CRUD admin doménu nemá. Martin Fowler tento anti-pattern pojmenoval Anemic Domain Model - model, který vypadá jako DDD, ale neobsahuje žádné chování.

2. Startup - doména se mění každý sprint

Hledáte product-market fit. Co dnes je objednávka, zítra je subscription. Co dnes je zákazník, zítra je partner. Ubiquitous Language nelze vybudovat, pokud doménový model ještě neexistuje.

DDD předpokládá, že doméně rozumíte dost dobře na to, abyste ji modelovali. Ve fázi hledání to neplatí. Každý refaktoring agregátů a bounded contextů vás zpomaluje a vývojové iterace se soustředí na kódovou architekturu namísto na hodnotu pro zákazníka.

Důležitá nuance: Strategické DDD nástroje - zejména Event Storming a Context Mapping - mohou být ve fázi hledání naopak velmi užitečné. Pomáhají pojmenovat, co ještě nerozumíte. Co nedává smysl, je taktické DDD (agregáty, doménové události, repozitáře) pro model, který se příští týden změní od základů.

Startup realita: pivot za 2 týdny

<?php
// ❌ Taktické DDD pro nestabilní doménu - za 2 týdny přepíšete všechno
// Bounded Context "Orders" s agregáty, events, repositories...

final class Order {                                 // Aggregate Root
    private OrderId $id;
    private CustomerId $customerId;                 // ← za 2 týdny: PartnerId
    private OrderStatus $status;                    // ← za 2 týdny: SubscriptionStatus
    /** @var OrderLine[] */
    private array $lines;                           // ← za 2 týdny: neexistuje

    public function place(): void { /* domain events, invariants... */ }
}

// + OrderPlaced event, OrderRepository interface, PlaceOrderHandler...
// Celý tento kód bude za 2 týdny v koši.
<?php
// ✅ Flat MVC - pivot je levný
// Entity se změní, controller se upraví, hotovo.

#[ORM\Entity]
class Order {
    #[ORM\Id, ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\Column(length: 255)]
    private string $customerName;   // příští sprint: partnerName - 1 rename

    #[ORM\Column(length: 50)]
    private string $status = 'new'; // příští sprint: subscriptionStatus - 1 rename
}
Doporučené alternativy:
  • Flat MVC s Doctrine Entities - rychlé iterace, změny jsou levné.
  • Až doména stabilizuje (3–6 měsíců provozu), teprve pak zvažte zavedení DDD vzorů selektivně - viz Migrace z CRUD na DDD.
  • Strategické nástroje DDD (Event Storming, Context Mapping) je vhodné zavést od začátku - pomáhají rychleji porozumět doméně.

3. Malý tým bez doménových expertů

DDD stojí na spolupráci vývojářů s lidmi, kteří doméně rozumí - zákazníci, produktoví manažeři, analytici. Bez nich modelujete doménu sami, z hlavy, bez zpětné vazby.

Výsledkem je model, který odráží to, jak vývojář chápe doménu - ne jak funguje doména ve skutečnosti. To je přesně opak toho, k čemu DDD slouží. Vaughn Vernon v Implementing Domain-Driven Design zdůrazňuje, že bez spolupráce s doménovými experty se Ubiquitous Language stává jen technickým žargonem.

Zásadní rozdíl oproti bodu 7: Zde doménové experty nemáte v týmu (malý tým = vývojáři dělají všechno). V bodě 7 experti existují, ale doména samotná je nejasná - nikdo neví, co modelovat. Řešení je odlišné: zde potřebujete lidi, tam potřebujete znalosti.

Doporučené alternativy:
  • Vrstvená architektura (Controller → Service → Repository) - dobře strukturovaný kód bez přílišné abstrakce.
  • DDD zaveďte až ve chvíli, kdy máte přístup k doménovým expertům a čas na Event Storming.

4. Data pipeline, ETL a reportovací systémy

Systém načítá data z externích zdrojů, transformuje je a ukládá nebo reportuje. Žádné business rules, žádné invarianty, žádná doménová logika. Jde o přesun a transformaci dat – ne o modelování domény.

Agregáty chrání invarianty. Pokud žádné invarianty nemáte, agregáty nemáte k čemu potřebovat. Výsledkem je přidaná komplexita bez věcného důvodu. Jak píše Evans: agregát je cluster of associated objects that we treat as a unit for the purpose of data changes - klíčové slovo je „data changes" s business pravidly, ne „data transfer".

Doporučené alternativy:
  • Service layer s plain PHP objekty - jednoduché třídy pro transformaci, bez agregátů.
  • Symfony Messenger pro asynchronní zpracování pipeline kroků - bez DDD overhead. Viz kapitola o CQRS pro inspiraci, jak Messenger používat v praxi.

5. Projekt s životností kratší než rok

Interní nástroj, landing page, jednorázová migrace, prototyp pro demo zákazníkovi. Kód napíšete, použijete a zahodíte.

DDD investice se vrátí na projektech, které žijí roky a rostou. Na krátkodobých projektech tým zaplatí cenu DDD (čas, komplexita, learning curve) aniž by kdy sklidil výhody (udržovatelnost, evolvability).

Proč zrovna rok? Hranice „jeden rok" není absolutní - je to orientační bod založený na praxi. DDD vyžaduje počáteční investici: modelování domény, budování Ubiquitous Language, návrh agregátů a bounded contextů. Tato investice se typicky začíná vracet po 6–12 měsících, kdy projekt roste a tým profituje z čistých doménových hranic. U projektů kratších než rok tuto návratnost jednoduše nedosáhnete. Vernon v Domain-Driven Design Distilled doporučuje zvážit „strategickou hodnotu" projektu - pokud je nízká, DDD se nevyplatí.

Doporučené alternativy:
  • Prostý Symfony controller + Doctrine - nejkratší cesta od požadavku k funkčnímu kódu.
  • Pokud projekt nečekaně vyroste, refaktorovat z jednoduchého kódu na DDD je snazší než vysvětlovat, proč jednoduchý projekt má 40 tříd. Postup najdete v Migraci z CRUD.

6. Tým DDD nezná a čas na učení není

DDD vyžaduje, aby tým rozuměl konceptům - aggregates, bounded contexts, domain events, repositories. Špatně pochopené DDD je horší než žádné DDD: produkuje pseudo-DDD kód, který má přidanou komplexitu bez architektonických výhod.

„Naučíme se za pochodu" na produkčním projektu s deadlinem je recept na technický dluh, který bude bolet roky.

Pseudo-DDD: vypadá jako DDD, ale není

<?php
// ❌ Pseudo-DDD - tým „zavedl DDD" bez pochopení
// Výsledek: Doctrine entity přejmenovaná na „Aggregate", setter zůstal

final class OrderAggregate  // ← jen přejmenovaná Entity, ne skutečný agregát
{
    private int $id;
    private string $status;

    // Setter - agregát nemá chránit invarianty, jen přepisuje data
    public function setStatus(string $status): void
    {
        $this->status = $status;  // žádná validace, žádné business rules
    }

    // „Repository" je jen přejmenovaný EntityRepository
    // „Command" je jen přejmenovaný DTO bez handleru
    // „Domain Event" se dispatchuje, ale nikdo ho neposlouchá
}
<?php
// ✅ Správné DDD - agregát chrání invarianty

final class Order
{
    private OrderId $id;
    private OrderStatus $status;
    /** @var DomainEvent[] */
    private array $domainEvents = [];

    public function cancel(Clock $clock): void
    {
        if ($this->status->isShipped()) {
            throw new OrderAlreadyShipped($this->id);
        }
        if ($this->status->isCancelled()) {
            throw new OrderAlreadyCancelled($this->id);
        }

        $this->status = OrderStatus::CANCELLED;
        $this->domainEvents[] = new OrderCancelled($this->id, $clock->now());
    }
    // Žádné settery - stav se mění jen přes explicitní business operace
}
Doporučené alternativy:
  • Klasická architektura, kterou tým zná dobře - srozumitelný kód je vždy lepší než „správná" architektura, které nikdo nerozumí.
  • DDD zaveďte na vedlejším projektu nebo v části systému jako experiment, pak přenášejte zkušenosti postupně.
  • Jako odrazový můstek doporučujeme Vernon: Domain-Driven Design Distilled - nejrychlejší cesta k pochopení DDD konceptů.

7. Doména je nejasná, experti nejsou k dispozici

Zákazník neví, co chce. Požadavky jsou vágní. Doménový expert buď neexistuje, nebo nemá čas spolupracovat. Výsledkem je modelování bez pevného základu.

Zásadní rozdíl oproti bodu 3: V bodě 3 chybí lidé - máte malý tým bez přístupu k expertům, ale doména může být jasná (pojišťovnictví, e-commerce...). Zde je problém v tom, že nikdo doménu nechápe - ani potenciální experti. Požadavky se teprve formují, pojmy nejsou ustálené, business pravidla se mění s každou schůzkou.

DDD bez znalosti domény je jen přejmenování tříd. „Order", „Customer", „Product" - vypadá to jako DDD, ale model neodráží skutečnou doménu. Za rok, až doménu pochopíte, přepíšete stejně všechno.

Doporučené alternativy:
  • Event Storming napřed - než napíšete první řádek kódu, zmapujte doménu se stakeholdery. Bez toho neví DDD co modelovat. Více o Event Stormingu v základních konceptech.
  • Pokud Event Storming není možný, začněte s jednoduchým kódem a DDD zaveďte retrospektivně, až doménu pochopíte - viz Migrace z CRUD na DDD.

Kdy DDD naopak smysl má

DDD není špatná architektura. Je to architektura pro specifický kontext. Smysl má, když platí většina z těchto podmínek:

Podmínka Proč záleží Příklad z praxe
Komplexní doménová logika (ne jen CRUD) DDD chrání invarianty a modeluje pravidla - bez pravidel nemá co chránit Pojistné smlouvy s 50+ business pravidly pro schválení, pojistné události s workflow
Projekt bude žít a růst roky Investice do architektury se vrátí jen při dostatečném horizontu Core banking systém, ERP, zdravotnický informační systém
Přístup k doménovým expertům Ubiquitous Language a model se tvoří ve spolupráci - ne ze vzduchoprázdna Pojistný matematik, zkušený účetní, vedoucí skladu - lidé, kteří žijí doménou denně
Tým rozumí DDD nebo má čas se učit Špatně implementované DDD je horší než žádné DDD Tým prošel školením, má za sebou alespoň jeden DDD projekt, nebo má 2–3 měsíce na ramp-up
Více bounded contexts nebo mikroslužby DDD dává přirozené hranice pro dekompozici systému E-commerce s oddělenými kontexty: katalog, objednávky, platby, logistika

Pokud váš projekt splňuje tyto podmínky, DDD se vyplatí. Pokud ne - použijte jednodušší přístup a ušetřete si bolest.

Detailní implementaci DDD v Symfony najdete v implementační kapitole. Reálné problémy při zavádění DDD popisuje kapitola DDD v praxi - kde to bolí. Pokud jste se rozhodli DDD zavést postupně v existujícím projektu, začněte migrací z CRUD.

Zdroje a další čtení

Knihy:
  • Eric Evans: Domain-Driven Design - Tackling Complexity in the Heart of Software (Addison-Wesley, 2003, ISBN 978-0-321-12521-7). Základní kniha DDD. Kapitoly 1–3 definují, kdy DDD aplikovat a kdy ne.
  • Vaughn Vernon: Implementing Domain-Driven Design (Addison-Wesley, 2013, ISBN 978-0-321-83457-7). Praktická implementace DDD s důrazem na spolupráci s doménovými experty.
  • Vaughn Vernon: Domain-Driven Design Distilled (Addison-Wesley, 2016, ISBN 978-0-134-43442-1). Nejrychlejší úvod do DDD - ideální pro týmy, které zvažují, zda DDD vůbec zavést.
  • Scott Millett, Nick Tune: Patterns, Principles, and Practices of Domain-Driven Design (Wrox/Wiley, 2015, ISBN 978-1-118-71470-6). Podrobný průvodce s praktickými vzory, včetně kapitol o tom, kdy DDD nedává smysl.
Články: