DDD
Domain-driven design (Предметно-ориентированное проектирование, реже проблемно-ориентированное) — это набор принципов и схем, направленных на создание оптимальных систем объектов. Сводится к созданию программных абстракций, которые называются моделями предметных областей. В эти модели входит бизнес-логика, устанавливающая связь между реальными условиями области применения продукта и кодом.
Предметно-ориентированное проектирование не является какой-либо конкретной технологией или методологией. DDD — это набор правил, которые позволяют принимать правильные проектные решения. Данный подход позволяет значительно ускорить процесс проектирования программного обеспечения в незнакомой предметной области.
Стратегическое проектирование
Проектирование на высоком уровне абстракции, без технических нюансов, осуществляемое всей командой - как менеджерами/заказчиками, так и техническими специалистами.
Основной целью применения DDD является получение высококачественной модели программного обеспечения, которая будет максимально точно отражать поставленные бизнес-цели. Для реализации этого требуется объединение усилий как разработчиков, так и экспертов в предметной области. Создание дружной и сплоченной команды позволяет получить большое количество преимуществ для бизнеса. Обмен знаниями между членами команды снижает шансы появления «тайного знания» о модели, достигается консенсус между экспертами предметной области в отношении различных понятий и терминологии, разрабатывается более точное определение и описание самого бизнеса.
Ubiquitous Language (Единый язык)
Для того чтобы уравнять разработчиков и экспертов предметной области, чтобы было гораздо проще обмениваться полезными знаниями о предметной области, подход DDD предлагает применять общий набор терминов, понятий и фраз, который будет использоваться в общении между членами команды, и который позже отразится в исходном коде результирующей программы.
Этот коллективный язык терминов называется - единый язык. (Ubiquitous Language). Это один из основных и самых важных шаблонов предметного-ориентированного проектирования. Это не бизнес жаргон, навязанный разработчикам, а настоящий язык, созданный целостной командой – экспертами в предметной области, разработчиками, бизнес-аналитиками и всеми, кто вовлечен в создание системы. Роль в команде не столь существенна, поскольку каждый член команды использует для описания проекта единый язык.
Bounded Context (Ограниченный контекст)
Очень важно понимать, что в рамках предметной области смысл определенного термина или фразы может сильно отличаться. Существует некая граница, в пределах которой понятия единого языка имеют вполне конкретное контекстное значение - ограниченный контекст (Bounded context). Это второе по значимости свойство DDD после единого языка. Оба эти понятия взаимосвязаны и не могут существовать друг без друга.
Итак, ограниченный контекст – это явная граница, внутри которой существует модель предметной области, которая отображает единый язык в модель программного обеспечения.
- В каждом ограниченном контексте существует только один
единый язык
. - Ограниченные контексты являются относительно небольшими, меньше чем может показаться на первый взгляд.
ограниченный контекст
достаточно велик только для единого языка изолированной предметной области, но не больше. - Единый значит «вездесущий» или «повсеместный», т. е. язык, на котором говорят члены команды и на котором выражается отдельная модель предметной области, которую разрабатывает команда.
- Язык является единым только в рамках команды, работающей над проектом в едином ограниченном контексте.
- Попытка применить
единый язык
в рамках всего предприятия или что хуже, среди нескольких предприятий, закончится провалом.
Предметная область (Domain)
Это то, что делает организация, и среда, в которой она это делает. Разработчик программного обеспечения для организации обязательно работает в ее предметной области
. Следует понимать, что при разработке модели предметной области необходимо сосредоточиться в определенной подобласти
, так как практически невозможно создать единственную, всеобъемлющую модель бизнеса даже умеренно сложной организации. Очень важно разделять модели на логические разделенные предметные подобласти
(Subdomain) всей предметной области
, согласно их фактической функциональности. Подобласти
позволяют быстрее определить разные части предметной области
, необходимые для решения конкретной задачи
Смысловое ядро (Core domain)
Очень важный аспект подхода DDD. Смысловое ядро
– это подобласть
, имеющая первостепенное значение для организации. Со стратегической точки зрения бизнес должен выделяться своим смысловым ядром
. Большинство DDD проектов сосредоточены именно на смысловом ядре
. Лучшие разработчики и эксперты должны быть задействованы именно в этой подобласти
. Большинство инвестиций должны быть направлены именно сюда для достижения преимущества для бизнеса и получения наибольшей прибыли.
Пространство задач и пространство решений
Предметные области
из пространства задач и пространства решений. Пространство задач позволяет думать о стратегической бизнес проблеме, которая должна быть решена, а пространство решений, сосредоточится на том, как реализуется программное обеспечение, чтобы решить бизнес проблему.
- Пространство задач – части
предметной области
, которые необходимы, чтобы создатьсмысловое ядро
. Это комбинациясмыслового ядра
иподобластей
, которое это ядро должно использовать. - Пространство решений – один или несколько
ограниченных контекстов
, набор конкретных моделей программного обеспечения. Разработанныйограниченный контекст
– это конкретное решение, представление реализации.
Идеальным вариантом является обеспечение однозначного соответствия между подобластями и ограниченными контекстами. Таким образом, объединяются пространство задач и пространство решений, выделяются модели предметной области в четко определенные области в зависимости от поставленных целей. Если система не разрабатывается с нуля, она часто представляет собой большой комок грязи, где подобласти пересекаются с ограниченными контекстами.
Тактическое проектирование
Использование технических, структурных паттернов в вашем коде, для отражения результатов стратегического проектирования непосредственно в коде приложения.
Entity
Если какое-то понятие предметной области является уникальным и отличным от всех других объектов в системе, то для его моделирования используется сущность
. Такие объекты-сущности
могут сильно отличаться своей формой за весь цикл существования, тем не менее их всегда можно однозначно идентифицировать и найти по запросу. Для этого используются уникальные идентификаторы, создание которых необходимо продумать в первую очередь при проектировании сущности
.
Value Object
A small simple object, like money or a date range, whose equality isn't based on identity
Если для объекта не важна индивидуальность, если он полностью определяется своими атрибутами, его следует считать объектом-значением
. Чтобы выяснить, является ли какое-то понятие значением
, необходимо выяснить, обладает ли оно большинством из следующих характеристик:
- Оно измеряет, оценивает или описывает объект предметной области;
- Должен быть неизменяем (immutable): при попытке обновления значения свойств мы должны создать и вернуть новый экземпляр VO
- Оно моделирует нечто концептуально целостное, объединяя связанные атрибуты в одно целое;
- При изменении способа измерения или описания его можно полностью заменить;
- Его можно сравнивать с другими объектами с помощью отношения равенства
значений
. Два VO считаются одинаковыми тогда и только тогда, когда все поля VO равны - Оно предоставляет связанным с ним объектам
функцию без побочных эффектов
. - Состоит только из других VO и примитивов(не может содержать сущность или сервис)
- Должен содержать в себе логику самовалидации: нельзя невалидный VO, исключение должно выкидываться прямо из метода VO(конструктор или клон).
Domain Service
Используя единый язык, существительные этого языка отражаются в объекты, а глаголы отражаются в поведения этих объектов. Очень часто существуют глаголы или какие-то действия, которые нельзя отнести к какой-то сущности или к какому-то объекту-значению. Если существует такого рода операция в предметной области, ее объявляют как Domain Service (она отличается от прикладной службы, которая является клиентом). Есть три характеристики служб:
-
Операция, выполняемая службой, относится к концепции предметной области, которая не принадлежит ни одной из существующих сущностей;
-
Операция выполняется над различными объектами модели предметной области;
-
Операция не имеет состояния.
Domain Event
Событие — это то, что произошло в прошлом. Логически, событие предметной области — это то, что произошло в конкретной предметной области, и то, о чем должны быть в курсе и на что должны реагировать другие части той же предметной области. Должны быть иммутабельными(так как нельзя менять прошлое). Название должно описывать случившиеся в прошлом событие.
Module(Модуль)
Модули
внутри модели являются именованными контейнерами для некоторой группы объектов предметной области, тесно связанных друг с другом. Их цель – ослабление связей между классами, которые находятся в различных модулях
. Так как модули
в подходе DDD – это неформальные или обобщенные разделы, их следует правильно называть. Выбор их имен является функцией единого языка
.
Factory
Некоторые агрегаты
или сущности
могут быть достаточно сложными. Сложный объект не может создавать сам себя посредством конструктора. (В книге Эрика Эванса был приведен пример: двигатель автомобиля, который собирается либо механиком, либо роботом, но он никак не должен собираться сам по себе.) Еще хуже, когда передают создание сложного объекта на клиент. Так, клиент должен знать о внутренней структуре и взаимосвязях внутри объекта. Это нарушает инкапсуляцию и привязывает клиента к определенной реализации (таким образом, при изменении объекта придется менять и реализацию клиента).
Лучше выполнять создание сложных агрегатов
или других объектов отдельно. Для этого используются фабрики
. Фабрики
– элементы программы, обязанности которого создавать другие объекты.
Aggregate
Агрегатом
называется кластер из объектов сущностей
или значений
. То есть эти объекты рассматриваются как единое целое с точки зрения изменения данных. У каждого агрегата
есть корень Aggregate Root
и граница, внутри которой всегда должны быть удовлетворены инварианты.
Все обращения к агрегату
должны осуществляться через его корень
, который представляет собой сущность
с глобально уникальным идентификатором. Все внутренние объекты агрегата
имеют только локальную идентичность, они могут ссылаться друг на друга как угодно. Внешние объекты могут хранить только ссылку на корень
, а не на внутренние объекты.
Repository(Репозиторий)
Репозиторий - область памяти, которая предназначена для безопасного хранения помещенных в нее элементов. Именно этим является Репозиторий в DDD. Репозиторий используется для агрегатов
. Помещая агрегат
в соответствующий Репозиторий, а затем извлекая его оттуда, вы получаете целостный объект. Если агрегат
будет изменен, то изменения будут сохранены. Если агрегат
будет удален, то его уже нельзя будет извлечь.
Каждый агрегат
, предполагающий постоянное хранение, имеет свой Репозиторий. Зачастую в Репозитории реализуются методы для выборки полностью сгенерированных агрегатов по каким-то критериям.
Есть два типа Repository:
- Ориентированные на имитацию коллекций;
- Ориентированные на механизм постоянного хранения.
Application Layer
Дополнительно: