<? phpukraine СПІВБЕСІДИ
Пошук по платформі
АРХІТЕКТУРА · SENIOR

Коли DDD виправданий, а коли шкодить?

DDD має сенс там, де складність саме в домені: багато правил, які часто змінюються, і потрібна спільна мова з бізнесом; для CRUD-адмінки чи інтеграційного сервісу агрегати й репозиторії додають шарів без вигоди.

Як зрозуміти, що домен достатньо складний для DDD?
Що таке bounded context на прикладі магазину?
Чому папки Domain, Application, Infrastructure ще не DDD?
DDD bounded context компроміси

Domain-Driven Design виправданий тоді, коли складність продукту зосереджена в бізнес-правилах. Ознаки: правила мають винятки й змінюються разом із бізнесом, експерти з різних відділів вкладають різне значення в одні слова, помилка в логіці коштує грошей, продукт житиме роками. У такому середовищі модель, яка говорить мовою бізнесу, окупає себе: зміну вимоги можна знайти в коді по назві, а інваріанти живуть в одному місці.

Найкорисніша частина DDD стратегічна. Bounded context — це межа, всередині якої слово має одне значення. Product у каталозі, на складі й у замовленні означає різні речі, і спроба зробити одну модель на всіх дає гігантський клас, який ніхто не розуміє. Три невеликі моделі з явними інтеграціями через події простіші, навіть якщо тактичних патернів у них мінімум.

Шкодить DDD там, де складності немає. CRUD-адмінка, звіти, інтеграційний сервіс, який перекладає один JSON в інший, не потребують агрегатів і репозиторіїв: пʼять класів на одну форму лише сповільнюють команду. Так само шкодить підміна суті формою: папки Domain, Application, Infrastructure без моделі та мови це не DDD, а бюрократія.

Зріла відповідь містить обидва приклади: контекст, де модель окупилась, і контекст, де від DDD свідомо відмовились на користь транзакційного скрипта й Eloquent. DDD можна застосовувати до одного складного контексту всередині звичайного застосунку, і саме так він найчастіше працює.

// Складний контекст: правила живуть у моделі, мова та сама, що в бізнесу
final class Subscription
{
    private function __construct(
        public private(set) SubscriptionId $id,
        private Plan $plan,
        private Period $period,
        private SubscriptionStatus $status,
    ) {}

    public function renew(Clock $clock): void
    {
        if ($this->status === SubscriptionStatus::Cancelled) {
            throw new CannotRenewCancelledSubscription($this->id);
        }
        if ($this->period->endsAfter($clock->now()->modify('+14 days'))) {
            throw new RenewalTooEarly($this->id, $this->period);   // правило з договору, не з таблиці
        }
        $this->period = $this->period->extendBy($this->plan->billingCycle());
        $this->record(new SubscriptionRenewed($this->id, $this->period));
    }
}

// Простий контекст поруч: CRUD без агрегатів, і це свідомий вибір
final class TagController
{
    public function store(Request $request): RedirectResponse
    {
        Tag::create($request->validate(['name' => ['required', 'max:50']]));
        return back();
    }
}

// Межа контекстів: той самий «продукт», різні моделі, інтеграція через подію
// Catalog\Product   — опис, фото, SEO
// Warehouse\StockItem — sku, залишок, комірка
// Orders\OrderLine   — назва й ціна, зафіксовані на момент покупки
Що цінність DDD у моделі й ubiquitous language, а не в структурі каталогів або в наборі патернів Entity, Repository, Value Object.
Критерії доречності: правила, які змінюються з бізнесом, кілька команд або підсистем із різними значеннями одних слів, довгий горизонт життя продукту.
Що стратегічна частина, тобто bounded contexts і context map, дає найбільше навіть без тактичних патернів, і що межі контекстів визначаються мовою, а не таблицями.
Приклад, де DDD не застосували свідомо: адмінка, звіти, інтеграція, і чому анемічна модель з транзакційним скриптом там була правильним вибором.
Розуміння ціни: більше коду, повільніший старт, потреба в дисципліні команди, і що DDD можна застосовувати до одного контексту, а не до всього застосунку.
Ототожнювати DDD зі структурою папок або з гексагональною архітектурою.
Застосовувати агрегати й репозиторії до CRUD і отримувати пʼять класів на одну форму.
Робити один величезний домен без bounded contexts, де Product означає одне для складу й інше для каталогу.
Проєктувати агрегати від таблиць бази, а не від інваріантів, і отримувати гігантський Order з усіма звʼязками.
Вважати, що DDD вимагає CQRS, event sourcing і мікросервіси.
ПОРАДА

Найсильніша відповідь — приклад, де ви свідомо не застосували DDD і чому це було правильно. Другий за силою: приклад слова, яке в двох контекстах означало різне.

оновлено 3 вересня 2026 · ліцензія CC-BY-SA-4.0 Знайшли неточність? Напишіть →
ПЕРЕВІРТЕ СЕБЕ

Цінність DDD у моделі й мові, а не в структурі каталогів.