Содержание
Domain-Driven Design (DDD, предметно-ориентированное проектирование) — это подход, при котором структура кода повторяет устройство бизнеса: разработчики и эксперты говорят на одном языке, система делится на части по предметным областям, а самые важные правила живут в коде явно, а не размазаны по контроллерам. DDD окупается в продуктах со сложной бизнес-логикой и избыточен для простых сайтов и CRUD-приложений.
Разберём ключевые идеи DDD без сложных терминов, когда подход оправдан и как начать применять его постепенно.
Что такое DDD?
DDD — это набор практик для проектов, где главная сложность не в технологиях, а в самой предметной области: тарифах, правилах начисления, логистике, финансовых операциях. Идея простая — сначала глубоко понять бизнес вместе с его экспертами, а потом выразить это понимание в коде так, чтобы оно было видно.
Основные идеи:
- единый язык — одни и те же термины в разговорах, документации и коде;
- ограниченные контексты — система делится на части с собственной моделью и словарём;
- агрегаты — группы объектов, которые меняются вместе и охраняют свои правила;
- доменные события — значимые факты бизнеса: «заказ оплачен», «договор подписан».
Зачем нужен единый язык?
Единый язык нужен, чтобы бизнес и разработчики понимали друг друга без перевода. Если менеджер говорит «бронь», аналитик — «резерв», а в коде — Hold, то каждая задача обрастает недопониманием, а ошибки появляются на стыке формулировок.
Как создают единый язык:
- Проводят сессии с экспертами и выписывают ключевые термины процесса.
- Для каждого термина фиксируют точное определение и границы.
- Используют эти слова в задачах, документации, названиях классов и таблиц.
- Когда смысл термина меняется, меняют и код.
Хорошее место для такой работы — этап исследования перед разработкой, подробнее в статье discovery-фаза, а также в техническом задании.
Фото: Unsplash
Что такое ограниченный контекст?
Ограниченный контекст — это часть системы, внутри которой у каждого термина одно значение. Слово «клиент» в продажах означает потенциального покупателя со сделкой, в бухгалтерии — плательщика с реквизитами, в поддержке — человека с обращениями. Попытка описать всё это одной моделью порождает огромный класс, который никто не может безопасно менять.
| Контекст | Что значит «клиент» | Что важно |
|---|---|---|
| Продажи | Лид или компания в воронке | Этап сделки, менеджер, источник |
| Биллинг | Плательщик | Реквизиты, тариф, задолженность |
| Поддержка | Автор обращений | История тикетов, приоритет |
| Доставка | Получатель | Адрес, окно доставки, телефон |
Контексты общаются через явные интерфейсы и события, а не через общие таблицы. Именно они часто становятся естественными границами модулей или сервисов — об этом статья монолит или микросервисы.
Что такое агрегаты и доменные события?
Агрегат — это группа объектов, которые меняются только вместе и через один вход, чтобы бизнес-правила нельзя было обойти. Заказ с позициями — агрегат: нельзя добавить позицию в оплаченный заказ, и это правило проверяется в одном месте, а не в каждом контроллере.
final class Order
{
public function addItem(Product $product, int $quantity): void
{
if ($this->status !== OrderStatus::Draft) {
throw new OrderAlreadyPlaced($this->id);
}
$this->items[] = new OrderItem($product->id, $product->price, $quantity);
}
public function markPaid(Payment $payment): void
{
$this->status = OrderStatus::Paid;
$this->recordEvent(new OrderPaid($this->id, $payment->amount));
}
}
Доменное событие OrderPaid сообщает другим контекстам — складу, биллингу, уведомлениям — о факте оплаты. Им не нужно знать, как устроен заказ внутри, а события удобно обрабатывать асинхронно — подробнее в статьях очереди задач и Kafka или RabbitMQ.
Когда DDD оправдан, а когда избыточен?
DDD оправдан, когда бизнес-правил много, они сложные и часто меняются, а ошибки дорого стоят. Для лендинга, блога или админки, которая просто создаёт и редактирует записи, это лишняя сложность — там хватает обычной архитектуры фреймворка.
DDD помогает, если:
- в продукте сложные расчёты: тарифы, скидки, начисления, лимиты;
- над системой работает несколько команд с разными зонами ответственности;
- эксперты и разработчики регулярно понимают требования по-разному;
- изменения в одной части неожиданно ломают другие.
DDD избыточен, если:
- приложение — в основном формы и списки без сложных правил;
- проект короткий и не будет развиваться;
- в команде один-два разработчика и простая предметная область.
Как начать применять DDD постепенно?
Начать можно без переписывания: составить словарь терминов, выделить контексты на схеме и при следующих доработках переносить бизнес-правила из контроллеров в доменные классы самой сложной части системы. Остальные части можно оставить как есть.
- проведите одну-две сессии с экспертами и зафиксируйте единый язык;
- нарисуйте карту контекстов и связей между ними;
- выберите самую сложную и изменчивую область и начните с неё;
- выносите правила в агрегаты и покрывайте их модульными тестами — подробнее в статье какие автотесты нужны продукту.
Коротко
- DDD строит код вокруг устройства бизнеса, а не вокруг технологий.
- Единый язык убирает недопонимание между бизнесом и разработкой.
- Ограниченные контексты делят систему на части с собственными моделями.
- Агрегаты охраняют бизнес-правила, доменные события связывают контексты.
- Подход окупается при сложной логике и избыточен для простых CRUD-проектов.
Частые вопросы
Нужен ли DDD для микросервисов?
Не обязательно, но ограниченные контексты из DDD — хороший способ найти границы сервисов. Сервисы, нарезанные по техническим слоям, а не по предметной области, обычно получаются сильно связанными.
Можно ли применять DDD в Laravel?
Да. Laravel не мешает выделять модули по предметным областям, писать доменную логику в отдельных классах и использовать события. Важно не превращать Eloquent-модели в свалку всей бизнес-логики.
Сколько времени нужно, чтобы внедрить DDD?
Отдельного внедрения не требуется: начинают с общего словаря и выделения контекстов на одной-двух сессиях с бизнесом, а остальные практики применяют постепенно к самым сложным частям системы.



