Появление каждой технологии и архитектуры имеет свою историческую подоплеку и эволюцию; аналогичным образом каждая технология и архитектура также имеет свои преимущества и недостатки и адаптируемые бизнес-сценарии. Поэтому в этой статье кратко анализируются предпосылки появления и процесс эволюции DDD с двух точек зрения: «модель анемии и перегрузки» и «эволюция многоуровневой архитектуры». «Я понимаю, что вы сказали, покажите мне свою модель, покажите мне свой код». Что касается того, как спроектировать и разработать DDD, в этой статье также будет использоваться собственный бизнес-пример для обсуждения с вами.
Модель домена перегрузки VS Модель анемии
Anemic model and bulky services
Модель анемии относится к модели, предметной областью которой является анемия. В анемичной модели объекты предметной области используются только как носители данных, без поведенческой и бизнес-логики, которая обычно размещается в сервисах, утилитах, хелперах и т. д. Эта конструкция (три слоя, показанные в левой части рисунка) является наиболее актуальной моделью разработки.
Когда мы реализуем определенную функциональность, мы сначала обсуждаем классы, которые будут сохраняться, которые мы называем сущностями. Они представлены буквой E в таблице выше. Эти сущности на самом деле являются объектно-ориентированными представлениями таблиц базы данных. Мы не реализуем в них никакой бизнес-логики. Их единственная роль заключается в том, чтобы быть сопоставленными с их эквивалентами базы данных с помощью некоторого ORM.
Когда наши сопоставленные сущности готовы, следующим шагом будет создание классов для их чтения и записи. Это DAO (объект доступа к данным). Как правило, каждая из наших сущностей представляет собой отдельный вариант использования в бизнесе, поэтому количество классов DAO соответствует количеству сущностей. Они не содержат никакой бизнес-логики. Классы DAO — это не что иное, как инструменты для извлечения и сохранения сущностей. Мы можем создавать их, используя существующие фреймворки, такие как Hibernate.
Последний слой поверх DAO — это суть нашей реализации — Service. Сервисы используют DAO для реализации бизнес-логики для определенных функций. Независимо от количества функций типичный сервис всегда делает следующее: загружает объекты с помощью DAO, изменяет их состояние по мере необходимости и сохраняет их. Мартин Фаулер описывает эту архитектуру как набор сценариев транзакций. Чем сложнее функция, тем выше количество операций между загрузкой и сохранением. Часто одни службы используют другие службы, что приводит к увеличению размера и сложности кода.
Rich model and thin services
Domain Driven Design предлагает совершенно другой подход к многоуровневому кодированию. Общая архитектура модели проектирования, управляемой предметной областью, показана справа на рисунке.
Обратите внимание на слой службы в DDD, который намного тоньше, чем слой службы в анемичной модели. Причина в том, что большая часть бизнес-логики содержится в агрегатах, сущностях и объектах-значениях.
Слой домена имеет больше типов объектов. Существуют Объекты-стоимости, Сущности и Объекты, составляющие Совокупность. Aggragate может подключаться только по идентификатору. Никакие другие данные не могут быть переданы между ними.
Последний слой также тоньше предыдущего. Количество репозиториев соответствует количеству агрегатов в DDD, поэтому приложение, использующее анемичную модель, имеет больше репозиториев, чем приложение, использующее богатую модель.
Easier changes and less bugs?
Применение архитектуры проектирования, ориентированной на предметную область, дает разработчикам ряд важных преимуществ.
Модель анемии на самом деле является своего рода процедурным программированием, хотя она относительно проста, нам трудно понять процесс изменения объекта (почему изменяться, каковы условия, как измениться и кем стать). Поскольку бизнес-логика находится в Сервисе, а Сервис не имеет состояния (не хранит состояние объекта), нам сложно понять процесс изменения состояния объекта, а при взаимных обращениях между Сервисами даже сложнее понять состояние объекта, процесс изменения. В то же время логика обработки состояния, содержащая большое количество объектов в Сервисе, также будет содержать много повторяющегося кода.
Благодаря разделению объектов на объекты-сущности и объекты-значения мы можем более точно управлять вновь создаваемыми объектами в нашем приложении. Агрегаты существуют для того, чтобы сделать наш API проще, а изменения внутри агрегатов легче реализовать (нам не нужно анализировать влияние наших изменений на другие части предметной области).
В то же время меньшее количество связей между элементами Dmoain может снизить риск ошибок при разработке и изменении кода. Например, чтобы избежать проблем с согласованностью и так далее.
Ссылаться на:Domain-Driven Design vs. anemic model. How do they differ?
Архитектура, управляемая доменом
Наиболее классическим и в то же время наиболее часто используемым является трехслойный режим. Трехуровневая модель разделена на уровень пользовательского интерфейса, уровень обслуживания и уровень Dao. В этой архитектуре бизнес-логика определяется в объекте службы уровня бизнес-логики, а объекты домена, отражающие концепцию домена, определяются как Java Bean-компоненты.Эти Java-бины не содержат никакой доменной логики, поэтому они размещаются в уровень доступа к данным. Схема архитектуры трехуровневой модели выглядит следующим образом:
Как упоминалось выше, эта традиционная модель 30% приведет к модели анемии. Чтобы избежать модели анемии, необходимо разумно присвоить поведение операционных данных Модели предметной области, то есть Объекту Сущности и Ценности в тактическом дизайне, вместо того, чтобы помещать его в Сервис в трехуровневой модели, затем архитектура должна быть:
В приведенной выше модели бизнес-поведение разумно назначается объекту модели предметной области (Domain Model), что позволяет избежать анемии, и в то же время не приведет к слишком раздутому слою бизнес-логики.
После того, как система разработана, она не может быть статичной, она будет постоянно обновляться и итеративно, поэтому требования будут постоянно обновляться и изменяться. Однако, если мы присмотримся, мы обнаружим, что всегда есть следы изменений. Во-первых, изменения в пользовательском опыте и рабочих привычках часто приводят к изменениям в отображении системного интерфейса; во-вторых, изменения в платформах развертывания и переключении компонентов часто приводят к изменениям в базовом хранилище системы. Но в целом, независимо от того, как изменится внешний вид системы и базовое хранилище, логика основного домена системы в основном не изменится сильно.
В приведенной выше архитектуре уровень домена зависит от уровня инфраструктуры, и эта связь сделает уровень домена хрупким, поэтому нам нужно найти способ сделать уровень домена более чистым и стабильным. Метод очень прост, то есть полагаться на абстракцию, а не на конкретику. Поэтому уровень системы может быть переработан, и новый дизайн выглядит следующим образом:
В этом многоуровневом режиме объекты домена постоянно хранятся через интерфейсы, абстрагированные уровнем инфраструктуры. Но уместно ли добавлять новую «абстракцию уровня инфраструктуры»?
С точки зрения бизнеса необходимо управлять жизненным циклом объектов, но не обязательно обращаться к внешним ресурсам. Только потому, что ресурсов компьютера недостаточно для такой стабильности, приходится вводить внешние ресурсы. Другими словами, доступ к этим объектам предметной области является элементом бизнеса, а способ доступа к этим объектам предметной области (например, через внешние ресурсы) является техническим элементом конкретной реализации.
С точки зрения кодирования экземпляр объекта предметной области — это просто структура данных, единственная разница в том, где она хранится. Дизайн, управляемый предметной областью, абстрагирует структуры данных, которые управляют этими объектами, в репозиторий. Доступ к объектам домена через этот абстрактный репозиторий естественно следует рассматривать как поведение домена. Если репозиторий реализован как база данных, а управление жизненным циклом объектов предметной области реализовано через механизм сохраняемости базы данных, поведение сохраняемости является техническим фактором.
Следовательно, репозитории должны быть перемещены на уровень поля, фигура уровня поля больше не зависит от каких-либо других уровней компонентов или классов, чтобы стать чистой моделью предметной области, новая структура выглядит следующим образом:
Приведенная выше архитектура является окончательным видом четырехуровневой архитектуры DDD. Обвинения на каждом уровне резюмируются следующим образом:
уровень представления
Он отвечает за отображение информации для пользователей и интерпретацию пользовательских команд для завершения логики внешнего интерфейса. Пользователь здесь не обязательно человек, использующий пользовательский интерфейс, это может быть другая компьютерная система.
прикладной уровеньЭто тонкий слой, который отвечает за координацию между уровнем представления и уровнем предметной области, а также является необходимым каналом для взаимодействия с другими уровнями системных приложений. Он в основном отвечает за состав, расположение и пересылку сервисов, а также за обработку порядка выполнения бизнес-прецедентов и сборку результатов.После сборки доменных сервисов сервисы общего назначения публикуются в приложении переднего плана через шлюз API. Таким образом, скрывается сложность доменного слоя и его внутренних механизмов реализации. В дополнение к определению сервисов приложений прикладной уровень также может выполнять аутентификацию безопасности, проверку разрешений, постоянный контроль транзакций или отправлять уведомления о событиях другим системам.
Код этого уровня в основном формирует сервисы общего назначения, вызывая сервисы уровня предметной области, завершает композицию и компоновку сервисов, а также предоставляет сервисы API для переднего плана. Этот уровень кода может выполнять проверку данных бизнес-логики, аутентификацию полномочий, компоновку и оркестровку сервисов, а также управление распределенными транзакциями.
Слой доменаЭто ядро программного обеспечения для бизнеса. Оно включает в себя объекты предметной области (сущности, объекты-значения), службы предметной области и их отношения, участвующие в бизнесе. Оно отвечает за выражение бизнес-концепций, информацию о бизнес-статусе и бизнес-правила. Конкретной формой является модель предметной области. . . . Дизайн, управляемый предметной областью, поддерживает богатую модель предметной области, то есть пытается приписать бизнес-логику объектам предметной области и определить часть, которая не может быть атрибутирована в форме служб предметной области.
Этот уровень кода в основном реализует основную логику бизнес-домена.Необходимо разделить код домена на слои и логически изолировать код между агрегатами.
слой инфраструктурыОснова системы ограничена не только доступом к базе данных, но и доступом, например, к сети, файлу, очереди сообщений или другим аппаратным средствам, поэтому очень разумно изменить название этого уровня на «уровень инфраструктуры». Он предоставляет общие технические возможности другим уровням, доставляет сообщения (API-шлюз и т. д.) для прикладного уровня и предоставляет механизмы сохранения (такие как ресурсы базы данных) для доменного уровня.
В соответствии с принципом инверсии зависимостей инкапсулировать базовые службы ресурсов, реализовать инверсию зависимости вызовов между уровнем ресурсов и прикладным уровнем и уровнем домена, предоставить базовые службы ресурсов (такие как базы данных, кэши и другие базовые ресурсы) для прикладного уровня. и уровень предметной области, а также реализовать решение каждого уровня. Связывание снижает влияние изменений во внешних ресурсах на основную бизнес-логику.
Этот уровень в основном включает в себя два типа кодов адаптации: активную адаптацию и пассивную адаптацию. Активный код адаптации в основном предоставляет услуги шлюза API для интерфейсных приложений и выполняет простую интерфейсную проверку данных, преобразование и адаптацию протоколов и форматов. Пассивная адаптация в основном предназначена для внутренних базовых ресурсов (таких как базы данных, кэши и т. д.) и обеспечивает сохранение данных и поддержку доступа к данным для прикладного уровня и уровня предметной области посредством инверсии зависимостей, а также реализует отделение уровня ресурсов.
Шестиугольная архитектура
В четырехуровневой архитектуре DDD принят принцип инверсии зависимостей, а уровень предметной области реализует развязку, полагаясь на абстрактные интерфейсы. Точно так же, если мы примем принцип ведущей зависимости на прикладном уровне, мы действительно сможем добиться разделения. На самом деле можно обнаружить, что когда принцип инверсии зависимостей применяется ко всем уровням в многоуровневой архитектуре, на самом деле нет понятия многоуровневости.И верхний, и нижний уровни относятся к опоре на абстракцию, которая кажется чтобы сгладить всю многоуровневую архитектуру, которая превратилась в шестиугольную архитектуру DDD:
Шестиугольная архитектура делит систему на внутренние и внешние двухуровневые шестиугольники.Внутренние шестиугольники представляют основную бизнес-логику приложения, а внешние шестиугольники представляют внешние приложения, драйверы и основные ресурсы. Внутренне взаимодействует с внешним миром через порты и адаптеры, предоставляет услуги в виде активной адаптации API и представляет ресурсы в виде ресурсов пассивной адаптации посредством инверсии зависимостей. Порт может соответствовать нескольким внешним системам, разные внешние системы используют разные адаптеры, и адаптер отвечает за преобразование протокола. Это позволяет приложениям согласованно управлять пользователями, программами, автоматическими тестами, пакетными сценариями.
Концепции, управляемые предметной областью
Дизайн DDD включает две части: стратегический дизайн и тактический дизайн. Моделирование предметной области и карта услуг в основном завершаются на этапе стратегического проектирования. На этапе тактического проектирования построение и реализация микросервисов завершаются с помощью агрегатов, сущностей, объектов-значений и сервисов на разных уровнях. С помощью DDD можно гарантировать согласованность бизнес-модели, модели системы, модели архитектуры и модели кода.
1. Что такое доменная служба?
Когда в домене операция или процесс преобразования не является ошибкой сущности или объекта значения, мы должны поместить операцию в отдельный интерфейс, службу домена. Услуги домена, как и другие модели домена, в основном сосредоточены на бизнесе конкретного домена.
В чем разница между службой домена и службой приложений?
Ответ: С точки зрения обвинения служба приложений не обрабатывает бизнес-логику, а служба домена содержит бизнес-логику; с точки зрения относительных ролей служба приложений является клиентской стороной службы домена.
Работают ли доменные службы с несколькими объектами домена, включая несколько агрегатов?
Ответ. Служба домена может обрабатывать несколько объектов домена в рамках одной атомарной операции.
2. Какова роль репозитория? А отношения с DAO?
DAO в основном смотрит на проблему с точки зрения таблицы базы данных, объектом операции является класс DO и предоставляет операции CRUD, которые представляют собой стиль, ориентированный на обработку данных (сценарий транзакции);
Репозиторий соответствует абстракции чтения и хранения объектов Entity, которая унифицирована на уровне интерфейса и не обращает внимания на лежащую в основе реализацию. Например, сохраните объект Entity через save, но не важно, вставка это или обновление. Конкретный класс реализации Repository реализует различные операции, вызывая DAO, и реализует преобразование между AccountDO и Account через объекты Builder/Factory.
3, что такое превентивный слой, какова роль?
Технические эксперты Alibaba объясняют второй пункт серии DDD — архитектуру приложенийОпределение Anti-Corruption Layer (ACL) в этой статье очень хорошее:
Много раз наша система будет зависеть от других систем, а зависимая система может содержать необоснованные структуры данных, API, протоколы или технические реализации.Если существует сильная зависимость от внешних систем, наша система будет «разъедена». В это время, добавляя антикоррозийный слой между системами, можно эффективно изолировать внешние зависимости и внутреннюю логику, независимо от того, как меняется внешний код, внутренний код может максимально оставаться неизменным.
ACL — это не только дополнительный уровень вызовов, но и в реальной разработке ACL может предоставлять более мощные функции:
- адаптер: во многих случаях внешне зависимые данные, интерфейсы и протоколы не соответствуют внутренним спецификациям.Благодаря режиму адаптера логика преобразования данных может быть инкапсулирована в ACL, чтобы уменьшить вмешательство бизнес-кода. В данном случае, инкапсулируя объекты ExchangeRate и Currency, мы преобразовали входные и выходные параметры друг друга, сделав входные и выходные параметры более соответствующими нашим стандартам.
- тайник: Для внешних зависимостей с частыми вызовами и нечастыми изменениями данных за счет внедрения логики кэширования в ACL можно эффективно уменьшить давление запросов для внешних зависимостей. В то же время логика кеша часто прописывается в бизнес-коде, и, встраивая логику кеша в ACL, можно уменьшить сложность бизнес-кода.
- раскрыть все подробности: если стабильность внешних зависимостей плохая, стратегия, которая может эффективно улучшить стабильность нашей системы, состоит в том, чтобы использовать ACL, чтобы играть восходящую роль.Например, когда есть проблема с внешними зависимостями, вернуть последний успешный кэш или восходящие бизнес-данные. Такая итоговая логика, как правило, более сложна, и если она разбросана по основному бизнес-коду, ее будет сложно поддерживать. Концентрируя ее в ACL, ее легче тестировать и модифицировать.
- легко проверить: Подобно предыдущему репозиторию, класс интерфейса ACL может легко реализовать Mock или Stub для модульного тестирования.
- переключатель функций: Иногда мы хотим открыть или закрыть функцию интерфейса в определенных сценариях или разрешить интерфейсу возвращать определенное значение. Мы можем настроить переключатель функций в ACL, чтобы добиться этого, не затрагивая реальный бизнес-код. В то же время использование функциональных переключателей также позволяет нам легко реализовывать тесты Monkey, фактически не закрывая внешние зависимости физически.
Рефакторинг традиционной модели разработки
Технические эксперты Alibaba объясняют второй пункт серии DDD — архитектуру приложений,В этой статье раздаточная коробка используется для объяснения возможных проблем традиционной модели развития и плана реконструкции.Если вам интересно, вы можете пойти и посмотреть ее.Я кратко объясню ее основные идеи и содержание здесь.
Потенциальная проблема
Для сложного бизнеса проблемы, которые могут существовать при традиционной трехуровневой разработке, следующие:
Плохая ремонтопригодность
- Нестабильность структур данных: класс DO — это чистая структура данных, которая отображает таблицу в базе данных. Проблема здесь в том, что структура таблиц и дизайн базы данных являются внешними зависимостями приложения и могут измениться в долгосрочной перспективе, например, базу данных необходимо сегментировать, или изменить дизайн таблицы, или изменить имя поля.
- Неопределенность в отношении использования сторонних услуг: Изменения сторонних сервисов: В свете изменений в сигнатурах API, в серьезных случаях сервисы недоступны и необходимо найти другие альтернативные сервисы. Затраты на модернизацию и миграцию в этих случаях огромны. В то же время необходимо соответствующим образом изменить такие решения, как восходящее, ограничение тока и объединение внешних зависимостей.
- Замена промежуточного ПО: Сегодня мы используем Kafka для отправки сообщений, а что, если завтра мы захотим использовать RocketMQ в облаке Alibaba? Что, если послезавтра метод сериализации сообщения изменится со String на Binary? Как изменить, если требуется фрагментация сообщения?
Плохая масштабируемость
Масштабируемость = сколько кода необходимо добавить/изменить при внесении новых требований или логических изменений.
- Бизнес-логика не может быть использована повторно: проблема несовместимых форматов данных приведет к невозможности повторного использования основной бизнес-логики. Следствием того, что каждый вариант использования является специальной логикой, является то, что в конечном итоге это приведет к большому количеству операторов if-else, и эта логика со многими ответвлениями сильно усложнит анализ кода, и легко пропустить пограничные случаи и вызывать ошибки.
- Взаимозависимость логики и хранения данных: когда бизнес-логика увеличивается и становится более сложной, вновь добавленная логика, вероятно, потребует изменений в схеме базы данных или формате сообщения. После изменения формата данных другую исходную логику необходимо перенести вместе. В самом крайнем случае добавление новой функции приведет к реконструкции всех исходных функций, что очень дорого.
Плохая тестируемость
Тестируемость = время, затрачиваемое на выполнение каждого тестового примера * количество дополнительных тестовых случаев, необходимых для каждого требования.
- Трудно построить объекты: Когда код сильно зависит от внешних зависимостей, таких как базы данных, сторонние сервисы, промежуточное ПО и т. д., если вы хотите полностью запустить тестовый пример, вам необходимо убедиться, что все зависимости могут работать, что чрезвычайно сложно на ранних этапах. стадия проекта. На более позднем этапе проекта тест провалится из-за нестабильности различных систем.
- Долго бежит: Большинство внешних вызовов зависимостей требуют интенсивного ввода-вывода, например межсетевые вызовы, дисковые вызовы и т. д., и такие вызовы ввода-вывода требуют много времени для тестирования. Еще одна частая зависимость — от тяжелых фреймворков, таких как Spring, запуск контейнера Spring часто занимает много времени. Когда выполнение тестового примера занимает более 10 секунд, большинство разработчиков не проводят тестирование слишком часто.
- высокое сцепление: Если сценарий имеет три подшага A, B и C, и каждый шаг имеет N возможных состояний, когда несколько подшагов сильно связаны, чтобы полностью охватить все варианты использования, требуется не более N N N тестовых случаев. При объединении большего количества подэтапов количество необходимых тестовых примеров растет экспоненциально.
принцип рефакторинга
Разработка программного обеспечения обычно следует следующим принципам:
- Принцип единой ответственности: Принцип сингулярности требует, чтобы у объекта/класса была только одна причина для изменения. Но в этом случае код может измениться из-за любой внешней зависимости или изменения вычислительной логики.
- Принцип инверсии зависимости: Принцип инверсии зависимостей требует, чтобы код зависел от абстракций, а не от конкретных реализаций. В этом случае все внешние зависимости являются конкретными реализациями.Например, хотя YahooForexService является интерфейсным классом, он соответствует конкретным службам, предоставляемым Yahoo, поэтому его можно рассматривать как зависящий от реализации. Одни и те же DAO-реализации KafkaTemplate и MyBatis являются конкретными реализациями.
- Открытый закрытый принцип: Принцип открытого-закрытого означает, что расширения открыты, а модификации закрыты. Расчет суммы в данном случае относится к коду, который может быть изменен, в это время логика должна быть упакована в немодифицируемый класс расчета, а новая функция реализована через расширение класса расчета.
Схема рефакторинга
Шаг 1: Абстрагируйте уровень хранения данных.
Уровень доступа к данным абстрагирован, чтобы уменьшить прямую зависимость системы от базы данных. Общий метод заключается в следующем: 1) Новый объект-сущность: Сущность (Entity) — это объект домена с идентификатором в дополнение к данным. Сущность не имеет ничего общего с форматом хранения базы данных и основана на вездесущем языке в этой области. 2) Новый класс интерфейса хранилища объектов AccountRepository: Repository отвечает только за хранение и чтение объектов Entity, а класс реализации Repository дополняет детали хранения базы данных. Добавляя интерфейс репозитория, базовое соединение с базой данных можно заменить другим классом реализации.
Шаг 2: Абстрагирование сторонних сервисов
Подобно абстракции базы данных, все сторонние службы также должны решить проблему неконтролируемых сторонних служб и сильной связи входных и выходных параметров посредством абстракции. Этот шаг обычно означает создание ACL антикоррозионного слоя.
Шаг 3. Инкапсулируйте бизнес-логику
Измените бизнес-логику с разбросанной по каждой службе на инкапсулированную в объекте домена и службе домена.
Реализация на основе домена
В этой статье для иллюстрации выбран относительно простой бизнес-сценарий, потому что бизнес слишком сложен, и его сложно четко объяснить, а также сложно понять каждому. Сценарий спроса: создать службу потока данных, объединяющую управление продавцами и управление спросом, чтобы помочь нам управлять производством и отслеживать его. Конкретные элементы:
1) Под каждым продавцом можно создать несколько требований; 2) После подтверждения запроса будет создано несколько заказов; 3) Каждый заказ будет доставлен несколько раз; 4) Каждая поставка должна быть принята или нет. 5) Требования, сдача-приемка, при необходимости можно предоставить вложения для пояснений (нет модификации в информационном поле вложения, если модифицируете, загрузите новое);
Декомпозиция процесса + моделирование объектов
Декомпозиция процесса заключается в разделении требований на отдельные этапы, а объектное моделирование — в извлечении объектов и операций для моделирования разделенных требований.
Декомпозиция процесса, как правило, идет сверху вниз, начиная с большого спроса, и постепенно разделяется; в то время как объектное моделирование обычно идет снизу вверх, моделирование и анализ объекта для каждого маленького шага. Таким образом, весь процесс представляет собой комбинацию верхнего и нижнего и дополняют друг друга.Вышеприведенный анализ может помочь нам лучше прояснить отношения между моделями, а следующее выражение модели может улучшить возможности повторного использования кода и бизнес-семантического выражения.
Ссылаться на:Эта статья научит вас писать сложный бизнес-код
Как идентифицировать объекты предметной области, агрегаты, сущности и объекты-значения
Следует ли использовать несколько объектов в качестве агрегата, критерии оценки:
- релевантность имени
- жизненный цикл
- Сильная последовательная корреляция
- Накладные расходы памяти и сложность
Как правило, агрегация определяется вышеуказанными критериями. Во-первых, требования разделяются, и, наконец, они делятся на несколько операций.Если несколько операций имеют зависимости имени, то есть все они связаны с объектом предметной области, то этот объект предметной области может быть кандидатом на агрегацию. Это очень полезно для сложной бизнес-логики, но для простой бизнес-логики этот шаг не требуется, потому что легко узнать объекты предметной области.
Что касается того, какие сущности входят в одну из агрегаций, и должны ли сущности в ней выходить отдельно в качестве критериев для новой агрегации, то прежде всего нужно обратить внимание на жизненный цикл вовлеченных объектов, два жизненных цикла тесно связаны (покинув зависимый объект, он потеряет смысл существования), в таком случае рекомендуется сводить их вместе, а не судить по другим эталонам.
Для агрегации есть очень хорошая фича, то есть агрегация представляет собой единое целое, а операции основаны на одной агрегации, так что внутри агрегации может быть гарантирована сильная согласованность.Поэтому, если вам нужно обеспечить сильную согласованность домена объектов, то рекомендуется как совокупность, в противном случае обращаться к другим критериям для суждения.
Агрегация представляет собой единое целое и может гарантировать строгую согласованность, так хорошо ли иметь большую агрегацию? Нет, для большой агрегации накладные расходы памяти велики, в то же время она должна обеспечить конечную согласованность, поэтому возможности параллелизма уменьшаются, и это влияет на производительность.
Говоря о накладных расходах памяти, на самом деле накладные расходы памяти в основном вызваны сущностью, потому что сущность может быть изменена, поэтому каждый раз, когда мы загружаем агрегацию, нам нужно загружать сущность.Если сущностей много, накладные расходы памяти должны быть очень большим. ; но объект значения отличается, объект значения не будет изменен, поэтому при загрузке мы не должны загружать объект значения полностью. Поэтому рекомендуется отдавать предпочтение объектам-значениям.
Итак, давайте также обсудим в совокупности, какие из противоположностей в совокупности должны стать сущностями, а какие должны быть объектами-значениями? Я думаю, что наиболее важным является то, является ли объект изменчивым.Если он изменчив, он должен быть сущностью.Если он неизменен, то он должен быть спроектирован как объект-значение.
Основываясь на вышеуказанных критериях, окончательный дизайн моего управления требованиями выглядит следующим образом:
разработка кода
Архитектура DDD, принятая системой, представляет собой четырехуровневую архитектуру, упомянутую выше:
Структура каталогов кода:
Как разрабатывать EventSourcing на языке GO, и об этом будет рассказано в следующей статье!
постскриптум
Эта статья основана на некоторых выводах из моей реальной разработки DDD.В то же время я сделал резюме после прочтения множества статей в Интернете.Я надеюсь, что это будет полезно для всех!