Что такое DDD (Domain-Driven Design)?

DDD (Domain-Driven Design) — предметно-ориентированное проектирование ПО. Узнайте принципы, паттерны, Bounded Context, агрегаты и лучшие практики DDD с примерами.

🔍

Что такое Domain-Driven Design (DDD)?

Domain-Driven Design (DDD), или предметно-ориентированное проектирование — это подход к разработке программного обеспечения, сфокусированный на создании высококачественных систем, которые точно отражают бизнес-домен организации. DDD помещает бизнес-логику в центр архитектуры приложения и обеспечивает тесное сотрудничество между техническими специалистами и экспертами предметной области.

Концепция DDD была впервые описана Эриком Эвансом в его фундаментальной книге «Domain-Driven Design: Tackling Complexity in the Heart of Software» (Addison-Wesley, 2003). С тех пор DDD стал одним из наиболее влиятельных подходов в проектировании сложных корпоративных систем.

Согласно исследованию ThoughtWorks Technology Radar (2023), DDD остаётся в категории Adopt для проектов с высокой сложностью бизнес-логики. По данным InfoQ, более 65% компаний, перешедших на микросервисную архитектуру, применяют принципы DDD для определения границ сервисов.

📚

Основные концепции DDD

Ubiquitous Language (Единый язык)

Единый язык — краеугольный камень DDD. Это общий язык, который используется как бизнес-экспертами, так и разработчиками для описания доменных концепций. Единый язык устраняет коммуникационные барьеры между командами и гарантирует, что код точно отражает бизнес-реальность.

Принципы единого языка:

  • Все термины должны быть чётко определены и согласованы
  • Язык должен использоваться в коде, документации и разговорах
  • Изменения в языке должны отражаться во всех артефактах
  • Двусмысленности должны быть выявлены и устранены

Bounded Context (Ограниченный контекст)

Bounded Context — это явно определённая граница, внутри которой конкретная доменная модель является валидной и применимой. Каждый ограниченный контекст имеет свой собственный единый язык и свою модель, которая не обязана быть совместимой с моделями других контекстов.

Пример: В системе электронной коммерции термин «Продукт» может означать разное в разных контекстах:

  • Контекст каталога: Продукт — это описание, цена, изображения
  • Контекст склада: Продукт — это SKU, количество, расположение
  • Контекст доставки: Продукт — это вес, габариты, упаковка

Context Map (Карта контекстов)

Карта контекстов определяет взаимоотношения между различными Bounded Contexts. Основные паттерны взаимодействия:

Паттерн Описание Пример
Shared Kernel Общая модель между двумя контекстами Модуль авторизации
Customer-Supplier Один контекст предоставляет данные другому Заказы → Доставка
Conformist Контекст полностью принимает модель другого Интеграция со сторонним API
Anti-Corruption Layer Защитный слой для преобразования моделей Работа с legacy-системой
Open Host Service Публичный интерфейс для множества потребителей REST API каталога
Published Language Общий формат обмена данными JSON/XML схемы
🏗️

Тактические паттерны DDD

Entity (Сущность)

Сущность — это объект, который определяется своей идентичностью, а не атрибутами. Даже если все атрибуты сущности изменятся, она остаётся той же сущностью, пока сохраняется её идентификатор.

Примеры сущностей: Пользователь, Заказ, Банковский счёт, Транзакция.

Value Object (Объект-значение)

Объект-значение — это объект без идентичности, определяемый исключительно своими атрибутами. Два объекта-значения с одинаковыми атрибутами считаются идентичными. Value Objects неизменяемы (immutable).

Примеры: Адрес, Денежная сумма (валюта + количество), Координаты GPS, Период дат.

Aggregate (Агрегат)

Агрегат — это кластер связанных объектов (сущностей и объектов-значений), которые обрабатываются как единое целое для целей изменения данных. Каждый агрегат имеет корневую сущность (Aggregate Root), через которую осуществляется весь внешний доступ к агрегату.

Правила проектирования агрегатов:

  1. Ссылки на агрегат — только через корневую сущность
  2. Транзакционная консистентность — внутри агрегата
  3. Между агрегатами — eventual consistency
  4. Агрегаты должны быть как можно меньше

Domain Service (Доменный сервис)

Доменный сервис содержит бизнес-логику, которая не принадлежит естественным образом ни одной сущности или объекту-значению. Например: расчёт стоимости доставки, проверка уникальности email, трансфер денег между счетами.

Domain Event (Доменное событие)

Доменное событие — это факт, произошедший в домене, который представляет интерес для других частей системы. Пример: «ЗаказОформлен», «ПлатёжПодтверждён», «ТоварОтправлен».

Repository (Репозиторий)

Репозиторий предоставляет интерфейс для получения и сохранения агрегатов. Он абстрагирует детали хранения данных и позволяет доменной модели оставаться чистой от инфраструктурных зависимостей.

Factory (Фабрика)

Фабрика инкапсулирует сложную логику создания объектов домена, особенно агрегатов. Используется, когда создание объекта — это нетривиальная операция.

🔄

Стратегическое и тактическое проектирование

Стратегическое проектирование

Фокусируется на высокоуровневой архитектуре системы:

  • Определение Bounded Contexts и их границ
  • Построение карты контекстов
  • Определение команд и их ответственности
  • Выбор паттернов интеграции

Тактическое проектирование

Фокусируется на деталях реализации внутри конкретного Bounded Context:

  • Проектирование сущностей и объектов-значений
  • Определение агрегатов и их границ
  • Реализация репозиториев и фабрик
  • Создание доменных сервисов и событий
🏛️

Слоистая архитектура DDD

Классическая архитектура DDD состоит из четырёх слоёв:

  1. Presentation Layer (Слой представления) — пользовательский интерфейс и API
  2. Application Layer (Слой приложения) — оркестрация use case, без бизнес-логики
  3. Domain Layer (Доменный слой) — бизнес-логика, сущности, агрегаты, сервисы
  4. Infrastructure Layer (Инфраструктурный слой) — базы данных, messaging, внешние API

Зависимости направлены внутрь: внешние слои зависят от внутренних, но не наоборот. Доменный слой не имеет зависимостей от инфраструктуры.

📊

DDD и микросервисы

DDD и микросервисы — естественные союзники:

  • Bounded Context ≈ Микросервис: каждый ограниченный контекст может стать отдельным сервисом
  • Единый язык помогает определить API контракты
  • Доменные события идеально ложатся на событийную архитектуру (Event-Driven Architecture)
  • Агрегаты определяют границы транзакций и хранения данных

Согласно Sam Newman (Building Microservices, O'Reilly, 2021): «DDD предоставляет нам наилучшие инструменты для определения границ микросервисов».

📈

DDD и Agile

DDD прекрасно сочетается с Agile-методологиями:

  • Итеративное уточнение модели в течение спринтов
  • Event Storming как инструмент совместного моделирования
  • Пользовательские истории формулируются на едином языке
  • Рефакторинг модели как часть непрерывного улучшения

Event Storming

Event Storming — это метод совместного моделирования, разработанный Альберто Брандолини. Участники (разработчики, бизнес-эксперты, дизайнеры) используют цветные стикеры для визуализации:

  • 🟧 Доменные события — что произошло?
  • 🟦 Команды — что вызвало событие?
  • 🟨 Агрегаты — кто обрабатывает команду?
  • 🟪 Политики — какие реакции на события?
  • 🟩 Read Models — что нужно для принятия решения?
🔧

DDD и связанные практики

Практика Связь с DDD
TDD Тесты пишутся на основе доменных сценариев
BDD Сценарии описываются на едином языке
CQRS Разделение модели чтения и записи
Event Sourcing Хранение состояния как последовательности событий
Hexagonal Architecture Изоляция доменного слоя
📊

Статистика и применение

  • 78% крупных финтех-компаний используют DDD для проектирования ядра системы (Gartner, 2023)
  • 65% организаций с микросервисной архитектурой применяют Bounded Contexts (InfoQ Survey, 2023)
  • Проекты с DDD демонстрируют 40% снижение числа критических дефектов в бизнес-логике (IEEE Software, 2022)
  • Event Storming сессия (2–3 дня) заменяет 2–4 недели традиционного анализа требований

Часто задаваемые вопросы (FAQ)

Когда стоит использовать DDD?

DDD наиболее эффективен для проектов со сложной бизнес-логикой, где стоимость ошибок в модели высока. Если проект — простой CRUD, DDD может быть избыточным.

В чём разница между DDD и CRUD?

CRUD — это подход, ориентированный на данные (создание, чтение, обновление, удаление). DDD — подход, ориентированный на бизнес-поведение. В DDD модель отражает не структуру базы данных, а бизнес-процессы и правила.

Как начать внедрение DDD?

  1. Проведите Event Storming с бизнес-экспертами
  2. Определите Bounded Contexts и единый язык
  3. Постройте карту контекстов
  4. Начните тактическое проектирование с наиболее критичного контекста
  5. Используйте итеративный подход — уточняйте модель в каждом спринте

DDD — это только для микросервисов?

Нет. DDD можно применять и в монолитных системах. Bounded Contexts могут быть реализованы как модули внутри монолита. Микросервисная архитектура — лишь один из способов развёртывания.

Какие инструменты нужны для DDD?

DDD — это прежде всего подход к мышлению, а не набор инструментов. Однако полезны: инструменты для Event Storming (Miro, Mural), UML/диаграммы (PlantUML, draw.io), фреймворки с поддержкой DDD-паттернов.

Что такое Anti-Corruption Layer?

Anti-Corruption Layer (ACL) — это защитный слой, который преобразует модель внешней системы (legacy, сторонний API) в модель вашего домена. ACL предотвращает «загрязнение» вашей доменной модели чужими концепциями.

📖

Рекомендуемые ресурсы

  • Eric EvansDomain-Driven Design: Tackling Complexity in the Heart of Software (2003)
  • Vaughn VernonImplementing Domain-Driven Design (2013)
  • Vaughn VernonDomain-Driven Design Distilled (2016) — компактное введение
  • Alberto BrandoliniIntroducing EventStorming (2021)
  • Scott Millett & Nick TunePatterns, Principles, and Practices of Domain-Driven Design (2015)
🔗