Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Дизайн на основе домена (DDD) отклоняет единую единую модель для всей системы. Вместо этого рекомендуется разделить систему на ограниченные контексты, в которых каждая из них имеет собственную модель. В статье по анализу домена рассматривается стратегический этап DDD. Эта статья продолжает эти шаги и применяет тактические шаблоны DDD для определения моделей предметных областей более точно в пределах ограниченных контекстов.
В архитектуре микросервисов, где каждый замкнутый контекст является кандидатом микросервиса, сущностные и агрегатные паттерны имеют значение. Применение этих шаблонов помогает определить естественные границы для служб в приложении. Дополнительные сведения см. в разделе "Определение границ микрослужбы". В качестве общего принципа проектируйте микрослужбу, чтобы она была не меньше агрегата и не больше граничного контекста.
В этой статье рассматриваются тактические шаблоны, которые затем применяются к ограниченному контексту перевозки в приложении доставки дронами.
Общие сведения о тактических шаблонах
В этом разделе описаны тактические шаблоны DDD. Если вы знакомы с DDD, перейдите к следующему разделу. Эти шаблоны появляются в книге Эрика Эванса Domain-Driven Design, которая ввела этот термин. Еще одна практическая, современная ссылка — Learning Domain-Driven Design Влад Хононов.
Entities
Сущность — это объект, имеющий уникальную идентичность, сохраняющуюся во времени. Например, в банковском приложении клиенты и счета являются сущностями.
Сущность имеет следующие характеристики:
Сущность имеет уникальный идентификатор в системе, который можно использовать для поиска или извлечения сущности.
Два экземпляра сущности, которые делят одну и ту же идентичность, представляют одну и ту же концепцию домена, даже если их атрибуты отличаются в определенный момент времени. Например, имя или адрес человека может измениться, но они остаются одинаковыми. И наоборот, два экземпляра с одинаковыми атрибутами, но разными идентичностями — это отдельные сущности.
Идентификатор не всегда предоставляется пользователям напрямую. Это может быть глобальный уникальный идентификатор (GUID) или первичный ключ в базе данных.
Выберите стратегию идентификации намеренно. Естественные ключи, такие как номер заказа или идентификатор, выданный правительством, передают бизнес-смысл и распознаются в разных системах. Суррогатные ключи, такие как GUID, не имеют бизнес-смысла, но избегайте связывания с внешними системами. В архитектуре микрослужб другие службы ссылаются на сущности по их идентификаторам, поэтому идентификатор должен оставаться стабильным и значимым за пределами границ службы. Идентичность может охватывать несколько ограниченных контекстов и может сохраняться за рамками жизненного цикла приложения.
Сущности должны инкапсулировать поведение, а не только содержать данные. Если бизнес-логика находится за пределами сущности в классах служб, создается анемичная модель домена. Это противопаттерн подрывает преимущество DDD, которое заключается в выражении бизнес-правил внутри модели домена. Поместите проверку, переходы состояния и бизнес-правила внутри сущности. Например,
Deliveryсущность должна содержать логику, чтобы определить, можно ли ее отменить, вместо того чтобы делегировать это решение внешней системе.
Объекты-значения
Объект значений не имеет идентичности. Он определяется только значениями его атрибутов. Два объекта значения с одинаковыми значениями атрибутов являются взаимозаменяемыми. Распространенные примеры включают цвета, даты и время, суммы валют и измерения.
Объекты значений неизменяемы. Чтобы обновить объект value, создайте новый экземпляр для замены старого экземпляра. Вы можете разделять неизменяемые объекты между потоками, кэшировать их без дублирования и проще понимать их в распределенных системах.
Объекты значений могут включать методы, которые инкапсулируют логику домена, но эти методы не должны создавать побочные эффекты. Вместо этого они возвращают новые объекты значений.
Предпочитайте использовать объекты-значения в качестве стандартного выбора для моделирования. Продвигайте концепцию до уровня сущности только при необходимости отслеживания ее идентичности с течением времени. Например, Address обычно является объектом значения, так как два адреса с одной и той же улицей, городом и почтовым кодом взаимозаменяемы. Но если ваш домен должен отслеживать определенную запись адреса с течением времени, например для целей аудита, она становится сущностью.
Агрегаты
Агрегат определяет границу консистентности одной или нескольких сущностей. В агрегате именно одна сущность является корневой. Поиск выполняется с помощью идентификатора корневой сущности. Любые другие сущности в совокупности являются дочерними элементами корня и ссылаются, следуя по указателям от корня.
Используйте агрегаты для моделирования инвариантных транзакций. Реальные домены содержат сложные связи. Клиенты создают заказы, в которых содержатся продукты, а у продуктов есть поставщики. Когда приложение изменяет несколько связанных объектов, оно должно обеспечить согласованность и поддерживать необходимые инварианты.
Традиционные приложения обычно обеспечивают согласованность с помощью транзакций базы данных. В распределенном приложении такой подход не работает по границам. Одна бизнес-транзакция может охватывать несколько хранилищ данных, выполняться в течение длительного времени или включать службы, отличные от Майкрософт. Приложение должно применять инварианты, которые требуется домену, а не уровню данных. Агрегирует модель ответственности.
Замечание
Агрегат может состоять из одной сущности без дочерних сущностей. Что делает его агрегатом, так это транзакционная граница.
При разработке агрегатов следуйте этим правилам:
Проектирование небольших агрегатов. Включите только данные, которые должны оставаться согласованными в рамках одной транзакции. В примере доставки дронов,
Delivery,Package,DroneиAccountобразуют отдельные агрегаты, так как они имеют независимые жизненные циклы. При их объединении вы заставляете несвязанные обновления конкурировать за одни и те же замки.Ссылка на другие агрегаты только по идентификатору. Агрегат
DeliveryхранитDroneIdиPackageId, а не прямые ссылки на эти объекты. Это разделение напрямую соответствует границам микросервисов.Используйте итоговую согласованность между агрегатами. Если бизнес-процесс охватывает несколько агрегатов, используйте события домена, а не одну транзакцию. После завершения
Deliveryдоставки агрегат вызываетDeliveryCompletedсобытие, на которое другие службы реагируют асинхронно.
Доменные и службы приложений
В терминологии DDD служба — это объект без отслеживания состояния, реализующий логику, которая естественно не относится к объекту сущности или значения.
Подсказка
Термин служба имеет несколько значений в разработке программного обеспечения. Определение в этой статье напрямую не связано с микрослужбами.
DDD определяет следующие два типа служб:
Доменные службы инкапсулируют бизнес-правила, охватывающие несколько сущностей или агрегатов. В пределах контекста доставки
Schedulerфункционирует как доменная служба, так как логика планирования включает бизнес-правила о доступности дронов, временных окнах доставки и оптимизации маршрутов, которые не связаны с отдельной сущностью.Службы приложений оркестрируют варианты использования. Они координирует вызовы доменных служб и репозиториев, управляют транзакциями и обрабатывают такие проблемы, как проверка подлинности пользователя или SMS-уведомления. Они сами не содержат бизнес-логику. Конечная точка API, получающая запрос на доставку, вызывает
Schedulerи возвращает результат — это служба приложений.
События домена
События в доменной области представляют собой значительные изменения. Например, запись была вставлена в таблицу не квалифицируется как доменное событие, а доставка была отменена — да. Агрегаты вызывают события домена после изменения состояния, и эти события работают в качестве основного способа координации работы между агрегированными границами.
В архитектуре микрослужб события домена иногда должны пересекать границы микрослужб. Внутренние события домена остаются в ограниченном контексте. Система публикует события интеграции асинхронно через брокер сообщений после фиксации транзакции, инициировавшей их. Например, когда контекст доставки завершает доставку, он публикует DeliveryCompleted событие интеграции, которое потребляется контекстом учетных записей для инициирования выставления счетов. Дополнительные сведения об асинхронных сообщениях см. в разделе "Взаимодействие между службами".
Другие шаблоны
Другие шаблоны DDDD, не описанные в этой статье, включают фабрики, репозитории и модули. Эти шаблоны имеют значение при реализации микрослужбы, но в этой статье рассматриваются шаблоны, которые помогают определить границы микрослужб.
Доставка дронов: применение шаблонов
Контекст ограниченной доставки должен обрабатывать следующие сценарии:
Клиент запрашивает беспилотный летательный аппарат, чтобы забрать товары из бизнеса, зарегистрированного в службе доставки дронов.
Отправитель создает тег со штрихкодом или СИД, чтобы поместить его в пакет.
Дрон берет и доставляет пакет из исходного расположения в место назначения.
Когда клиент планирует доставку, система выдает предполагаемое время прибытия на основе информации о маршруте, погодных условиях и исторических данных.
Когда беспилотный летательный аппарат находится в полете, пользователь отслеживает текущее расположение и последнюю версию ETA.
Клиент может отменить доставку до тех пор, пока беспилотный летательный аппарат не выберет пакет.
Система уведомляет клиента о завершении доставки.
Отправитель может запросить подтверждение доставки от клиента в виде подписи или отпечатка пальца.
Пользователи могут просмотреть историю завершенной доставки.
В этих сценариях группа разработчиков определяет следующие сущности:
DeliveryPackageDroneAccountConfirmationNotificationTag
Агрегаты, такие как Delivery, PackageDroneи Account каждый определяет свои собственные границы согласованности транзакций. Каждый агрегат имеет свой собственный независимый жизненный цикл, а другая часть системы управляет ею. Например, можно создать, обновить и завершить доставку без транзакции, которая блокирует дрон или учетную запись.
Confirmation и Notification сущности функционируют как дочерние сущности сущностей Delivery, так как они не существуют независимо.
Tag сущности выполняют функцию дочерних сущностей для Package сущностей по той же причине.
Объекты значений в этом конструкторе включают Location, ETAPackageWeightи PackageSize. Эти объекты не имеют удостоверения и не отслеживаются с течением времени.
На следующей схеме унифицированного языка моделирования (UML) показан Delivery агрегат. Он ссылается на другие агрегаты, такие как Account, Package, и Drone только по идентификатору.
Дизайн включает в себя два события доменной области:
Когда беспилотный летательный аппарат находится в полете, сущность
Droneотправляет событияDroneStatus, описывающие местоположение и статус дрона, например, в полете или приземленный.Сущность
DeliveryотправляетDeliveryTrackingсобытия при изменении этапа доставки. Включаемые события:DeliveryTracking,DeliveryCreated,DeliveryRescheduled,DeliveryHeadedToDropoffиDeliveryCompleted.
Эти события описывают значимые события в области, которые имеют значение в модели домена. Они представляют вхождения доменного уровня и не зависят от какой-либо конкретной конструкции языка программирования.
Команда разработчиков определяет одну область функциональных возможностей, которые пока не соответствуют описанным сущностям. Компонент должен координировать все шаги по планированию или обновлению доставки. Команда добавляет в проект следующие две доменные службы:
A
Scheduler, который координирует шагиОбъект
Supervisor, который отслеживает состояние каждого шага для выявления сбоев или тайм-аутов.
Этот подход представляет собой вариацию паттерна координатора агентов планировщика.
Следующий шаг
Следующий шаг — определить границы для каждой микрослужбы.