DDD Практический бой, часть 2: Посмотрите, как выглядит структура кода

DDD Практический бой, часть 2: Посмотрите, как выглядит структура кода

Прежде чем вы действительно начнете свое путешествие по DDD, я хочу, чтобы вы увидели, как выглядит код после проектирования DDD. Я думаю, что это концепция, которая волнует всех программистов, которые следуют концепции «говорить легко, покажи мне свой код».

По этой причине я специально показываю старую и новую структуры кода серверного кода системы электронной коммерции свежих продуктов Qunmaicai, чтобы вы могли видеть, как выглядит исходный старый код - то есть код «скрипта транзакции» ( должно быть так, как большинство Java-программистов пишут код в настоящее время), позволит вам увидеть, как выглядит новый код после преобразования и проектирования DDD. Затем посредством анализа мы сможем объяснить, почему традиционный код «скрипта транзакции» не является «изоморфным отображением» реального мира и где находится «изоморфное отображение» кода DDD.

Я должен напомнить вам: начиная с сегодняшней темы, вам, возможно, придется потратить больше времени, внимательно прочитать код и каждое предложение написанного мною текста и неоднократно сравнивать его или даже перечитывать несколько раз вперед и назад, чтобы по-настоящему понять это, понять эти слова.

Давайте сначала посмотрим на скриншот структуры каталогов старого кода. Обратите внимание на отмеченные позиции 1, 2, 3 и 4 ниже (пояснение: я использую среду разработки Spring-Boot, среду сохранения данных MyBatisPlus и базу данных MySql5.6):

изображение.png

изображение.png

изображение.png

Вы заметили отмеченные здесь позиции кода 1, 2, 3 и 4? Похожа ли структура кода на структуру кода большинства платформ приложений с пружинной загрузкой? Чтобы вы не могли не понять эту структуру кода, я кратко ее объясню.

Позиция метки 1: здесь размещается код уровня контроллера, то есть здесь реализованы все интерфейсы внешнего доступа. В соответствии с принципом многоуровневого управления MVC, вообще говоря, сюда будет включен только некоторый анализ входных параметров клиента и вызовы бизнес-методов на уровень сервиса (см. ниже). Вообще говоря, код здесь выглядит так:

изображение.png

Позиция метки 2: здесь размещается код слоя объекта (компонента данных).Фактически, это весь код POJO, и все классы сопоставляются с таблицей базы данных один за другим. Вообще говоря, код здесь выглядит так:

изображение.png

Позиция номер 3: уровень картографа. Для структуры уровня персистентности mybatis картограф и объект совместно реализуют ORM (сопоставление объектной модели с реляционной моделью). Вообще говоря, код здесь выглядит следующим образом (класс CustomerMapper здесь определяет только отношения отображения сущностного класса Customer, а также пользовательские методы работы с данными):

изображение.png

И вот так (в MP этот файл CustomerMapper.xml нужен только для реализации пользовательских методов операций SQL):

изображение.png

Позиция номер 4: Сервисный уровень, это основной код, в котором реализована вся бизнес-логика, и почти вся бизнес-логика реализована здесь. Вообще говоря, будет реализация комбинации интерфейс+реализация. Например: OrderService и OrderServiceImpl соответственно выглядят так:

Класс интерфейса OrderService

изображение.png

Класс реализации OrderServiceImpl

изображение.pngизображение.png

изображение.png

Из приведенного выше кода мы ясно видим следующие моменты:

  • Контроллер/сущность/сопоставитель — это, по сути, очень мало кодов, реализованных с использованием аннотаций фреймворка и кода общедоступных инструментов (например, синтаксического анализа json и т. д.);

  • Очевидно, что большая часть бизнес-логики реализована в классе реализации уровня Сервиса;

  • Логика кода класса реализации уровня обслуживания очень длинная и совершенно «плоская и понятная». Метод создания OrderServeImple, который я показываю здесь — для создания заказа написал 135 строк. Из комментариев на скриншоте моего кода видно, что я задумался над тем, как поэтапно выполнить CRUD в базе данных: сначала я заполнил комментарии, а затем написал код. Такой код, если говорить прямо, представляет собой код, сочетающий в себе «CRUD + логику вычислений»;

  • Фактически, такой «плоский и простой» код легко понять программе и легко написать. По сути, для него не нужно «убивать» слишком много клеток мозга, поэтому команде легко приступить к реализации проекта. ., просто найдите кого-нибудь с базовым опытом программирования на Java (обычно опыта более одного года достаточно) и можно приступать к разработке бизнес-кода;

  • Этот тип кода называется кодом «скрипта транзакции» или кодом «модели анемии».

  • Причина, по которой его называют «скриптом транзакции», заключается в моем личном понимании: по сути, это то же самое, что и написание кода хранимой процедуры базы данных 20 лет назад (просто он написан на другом языке, и место, где запускается код, упомянутый от сервера базы данных к серверу приложений);

  • Причина, по которой его называют кодом «анемичной модели», заключается в том, что объекты POJO на уровне сущности, такие как Order и т. д., не имеют какой-либо инкапсуляции бизнес-поведения (например: класс Order должен генерировать собственный номер заказа, номер доставки и т. д.), только атрибуты и нет. Поведенческий объект — это объект «анемии», а код бизнес-логики, реализованный на основе объекта «анемии», называется кодом «модели анемии».

Основываясь на анализе кода здесь, можем ли мы найти ключевую проблему: на самом деле здесь нет сопоставления между контроллером/объектом/сопоставителем/сервисом и бизнесом в реальном мире - то есть: «миром кода» » и «реальный мир» неоднороден. В частности, мы можем рассмотреть следующие моменты.

Прежде всего, благодаря самой «грубой» детализации разделения бизнес-модулей, мы можем просто и интуитивно разделить модули. Вместо того, чтобы помещать все бизнес-модули в один проект, мы можем разделить их по бизнес-модулям (например, магазинам), управлению, управление заказами, управление продуктами и т. д.) для разделения каталога проекта, то есть группируется команда проекта.

Фактически, большинство компаний-разработчиков программного обеспечения, присутствующих в настоящее время на рынке, просто и грубо делят проект на несколько команд разработки, основываясь на бизнес-опыте или интуиции. Но хотя этот метод разделения может быть более или менее точным, нам нужно осознавать, что такое простое и грубое деление, основанное на опыте и интуиции, отличается от проектного разделения, выполненного по методологии DDD (разделенного на степень детализации ограниченного контекста). Проект (называемый в DDD «стратегическим проектом») имеет как минимум три недостатка:

  • Как разделить программный код — это строго «инженерная проблема», а все инженерные проблемы часто заключаются в том, что «незначительная разница может привести к тысяче миль»! Такое разделение опыта и интуиции, вероятно, упускает из виду некоторые очень важные определения «ограниченного контекста». И именно из-за отсутствия этих важных «ограниченных контекстов» возникают некоторые нечеткие области, и обнаруживается либо ненужная связь между модулями, либо ненужное дублирование.
  • Идентификация «ограниченного контекста» DDD должна не только различать, на сколько модулей его необходимо разделить (на самом деле «модуль» — очень расплывчатое слово, его можно использовать для разделения микросервисов, а также для разделения структуру каталогов кода, в зависимости от необходимости)), также необходимо выявить связи взаимодействия и границы между этими «ограниченными контекстами». Эти отношения сотрудничества действительно определяют «четко и точно на уровне строки кода», какой код принадлежит модулю A, а какой код принадлежит модулю B - то есть границу, и взаимодействуют ли эти модули через отношения RPC или локальных вызовов, или асинхронные сообщения.События взаимодействуют или даже не взаимодействуют напрямую.
  • Вообще говоря, «ограниченный контекст» DDD должен соответствовать бизнес-поддомену, и важность бизнес-поддомена будет определять важность ограниченного контекста. Для конкретной программной системы подполе бизнеса может определить с точки зрения бизнеса, что должно быть создано в качестве основной конкурентоспособности программного обеспечения, а что может быть реализовано в виде вторичных модулей или даже посредством аутсорсинга. Эти различные определения «важности» модулей «ограниченного контекста» побудят руководство проекта принять различные технологические стеки с точки зрения эффективности. Например: разные программисты, присутствующие в настоящее время на рынке, имеют разные уровни заработной платы и трудности с набором персонала; разные технологические стеки имеют разные уровни зрелости и применимые функции программирования (например: Java является относительно зрелым и подходит для разработки приложений корпоративного уровня, а Python подходит для обработки данных). разработка обработки, node.js подходит для подключения к сторонним интернет-системам и т. д.).

Во-вторых, внутри модуля разделена иерархическая структура его кода: если следовать идее MVC, то со временем он вернется к методу деления типа контроллер/сущность/маппер/сервис. И какова изоморфная связь между этим методом деления и «реальным миром»? Можно сказать, нет!

Следовательно, в конце концов мы можем заключить, что эта традиционная архитектура кода не учитывает «изоморфное отображение» реального мира. Это отсутствие «изоморфного отображения» является основной причиной, почему у нас возникают такие сомнения, как «реальный бизнес не сильно изменился, но почему определенное требование вызывает потрясающие изменения в программном коде?» — используется методология DDD. Для решения этой проблемы!

Давайте посмотрим, как выглядит новая структура кода после использования дизайна DDD. Ниже приведен скриншот структуры нового кода (также обратите внимание на цифры 1–8 ниже):

изображение.png

Я объясню приведенные выше положения меток кода одну за другой следующим образом (следует отметить, что сортировка каталогов здесь автоматически сортируется в алфавитном порядке инструментом разработки IDEA, а не в порядке проектирования кода):

Позиция метки 1: Здесь размещается код краевого слоя (края). Поскольку внешний интерфейс апплета «Qunmaicai» был разработан, а это проект разделения внешнего и внутреннего интерфейса, я не собираюсь изменять код внешнего интерфейса, поэтому существует дополнительная «адаптация интерфейса». "код работает здесь. Вообще говоря, такой код называется «граничным слоем». Код, размещенный на пограничном уровне, аналогичен этому коду для адаптации внешнего интерфейса и адаптации интерфейса сторонней системы. Этот вид кода также можно назвать «Бэкенд для фронтенда» (BFF). Теоретически этот код слоя BFF может быть разработан командой фронтенда.Я могу выбрать стек технологий Node.js и использовать язык js или ts для разработки.

Положение этикетки 2: Здесь показан «базовый слой» (фундамент). В системной архитектуре DDD ограниченный контекст (конкретное понятие будет введено позже, здесь нужно только понимать, что это похоже на разделение подсистем или бизнес-модулей) можно разделить на «бизнес-поддомены» в соответствии с «бизнес-поддоменами». «а не основной уровень. Базовый уровень» и «Уровень бизнес-ценности». Вообще говоря, «уровень бизнес-ценности» соответствует основному бизнес-модулю и является основной конкурентоспособностью программной системы. Он требует тактического проектирования в строгом соответствии с концепцией DDD, принимает модель разработки через тестирование и инвестирует в лучшее знание бизнеса. Программисты идут на работу, а «базовый уровень» - это, как правило, непрофильные бизнес-модули, такие как: базовые классы, связанные с бизнесом, классы инструментов, стыковка сопутствующих систем и т. д. - Следует отметить, что «Базовый уровень» не является «базовым уровнем ресурсов», базовый уровень относится к бизнес-модулям, находящимся в неосновном положении, а базовые ресурсы относятся к техническим компонентам, таким как базы данных и промежуточное программное обеспечение.

Позиция метки 3: здесь отображается несколько ограниченных контекстов, все они названы в честь каталогов, таких как xxxcontext. И на «базовом уровне», и на «уровне бизнес-ценности» появится несколько «ограниченных контекстов». Каждый ограниченный контекст может быть разделен на разные проектные группы, за которые они будут отвечать, или даже на разные центры микросервисов. Опять же, сейчас вам не нужно слишком глубоко понимать «ограниченный контекст», а пока вам просто нужно понять, что это своего рода разделение модулей (подробно будет объяснено позже).

Позиция метки 4: Здесь отображается код «уровня бизнес-ценности», то есть тех модулей, которые должны быть основной конкурентоспособностью программной системы. Ниже также будет несколько «ограниченных контекстов».

Позиция номер 5: Под многоуровневой «ромбовидной архитектурой» программного обеспечения тактического проектирования DDD здесь размещается код «доменного» уровня, который также является основным кодом бизнес-логики - весь код модели «перегрузки». Отсюда мы объясним структуру кода в «ограниченном контексте». О деталях проектирования этих кодов мы поговорим позже, а пока вам нужно только знать, что здесь находится «основная бизнес-логика».

Позиция номер 6, 8: в многоуровневой «ромбовидной архитектуре» программного обеспечения тактического проектирования DDD, чтобы позволить «ограниченному контексту» соответствовать различным требованиям внешних вызовов, а также когда ему необходимо звонить или взаимодействовать с другими «ограниченными контекстами». Что касается «турбулентности» логики кода в этом модуле, вызванной изменениями различных внешних факторов, не связанных с бизнес-логикой этого модуля, были введены понятия «северный шлюз» и «южный шлюз». Соответствующие описания следующие:

Метка 6 содержит код «Северного шлюза», который разделен на два типичных каталога: локальный и удаленный. Функция «северного шлюза» заключается в том, чтобы позволить ограниченному контексту выводить различные сервисы приложений. Ниже локального каталога находится «служба приложений», предоставляемая этим ограниченным контекстом, который представляет собой полную бизнес-логику, инкапсулирующую различные коды «модели перегрузки» в домене; а в удаленном каталоге находится служба приложений для локального каталога. Инкапсуляция кода для удовлетворения «удаленных вызовов», таких как вызовы RPC, подписка на события межсерверных сообщений и т. д., не имеет какой-либо бизнес-логики.

Метка 8 содержит код «южного шлюза», который разделен на два типичных каталога: «port» и «adaper». Функция «южного шлюза» заключается в том, чтобы позволить этому ограниченному контексту запрашивать через него внешние ресурсы. Типичные три типа запросов внешних ресурсов включают: доступ к уровню хранения данных (реляционная или нереляционная база данных), вызов других служб ограниченного контекста (в архитектуре микросервисов — часто удаленные вызовы RPC) и публикацию сообщений в других ограниченных контекстах. Мы все знаем, что эти запросы на внешние ресурсы могут быть реализованы по-разному из-за разных технических технологий, лежащих в основе внешних ресурсов. Чтобы изолировать зависимость «уровня домена» от базовой технологии, уровень порта и уровень адаптера разделены. В реализации языка Java уровень порта — это интерфейс без какого-либо кода реализации, только определения методов; а уровень адаптера — это реализация, которая реализуется на разных уровнях персистентности (например, в различных реляционных базах данных oracle/mysql и т. д.). различные базы данных nosql redis/mongodb и т. д.). Затем, в соответствии с принципом IoC (инверсия зависимостей), в Java используется «внедрение зависимостей» для соединения конкретной реализации в каталоге адаптера с кодом на уровне домена.

Позиция метки 7: это слой «опубликованного языка» (published Language, pl). Грубо говоря, «язык публикации» означает, что когда «северный шлюз» выводит службы, он может иметь «унифицированный язык» с вызывающими службами, например: структурное определение входных и выходных параметров, определение формата сообщений о событиях, и т. д. . Поскольку нам не нужно «утекать» внутреннюю объектную структуру слоя «домен» внутри ограниченного контекста наружу, у нас должен быть этот уровень «выпуска языка».

Хорошо, после объяснения конструкции структуры кода в соответствии с DDD нам все еще нужно ответить на вопрос: где находится логика кода после того, как DDD выполняет «изоморфное отображение» в реальный мир?

Ответ: внутри слоя «Домен»! Функции так называемых уровней «Северный шлюз», «Язык выпуска» и «Южный шлюз» предназначены только для предотвращения «нарушения» внешними запросами и базовой технологией запрошенных ресурсов «изоморфизма» нашей «бизнес-логики». «.изация» картографирования!

Это эквивалентно утверждению: уровень предметной области является ядром отображения «бизнес-логики» в DDD, а все остальное — просто иерархической «упаковкой» этой «основной бизнес-логики»!

Итак, очевидно, что с технической точки зрения понимание того, как проектировать доменный уровень, является наиболее важным навыком на уровне тактического проектирования DDD! Поскольку разработка кода трех уровней «Северный шлюз», «Язык выпуска» и «Южный шлюз» представляет собой обычные процедуры с небольшим содержанием «бизнес-знаний» и может даже быть реализована с помощью роботов (то есть автоматического производства через инструмент кода).

Наконец, давайте объясним разницу между стратегическим дизайном DDD и тактическим дизайном, о которой неоднократно упоминалось:

Вообще говоря, стратегический проект DDD заключается в том, чтобы определить, какие существуют ограниченные контексты, и четко определить отношения и границы ограниченных контекстов. С какими сторонними внешними системами взаимодействовать и т.п., но это уже нельзя назвать "проектированием", поскольку не требует особого размышления);

Сутью тактического проектирования DDD является завершение разработки «агрегации» и «доменных служб» на уровне «домена», то есть разработка «основной бизнес-логики». Позже я подробно продемонстрирую, как в нее играть.

Эта статья опубликована OpenWrite, блогом, в котором публикуется множество статей !

OpenAI бесплатно открывает ChatGPT для всех пользователей. Голосовые программисты подделали балансы ETC и присвоили более 2,6 млн юаней в год. Официально выпущена Spring Boot 3.2.0. Сотрудники Google раскритиковали большого босса после ухода из компании. Он принимал активное участие в проект Flutter и сформулировал стандарты, связанные с HTML. Microsoft Copilot Web AI будет официально запущен 1 декабря и будет поддерживать китайскую веб-инфраструктуру Terminal Chat Rust от Microsoft с открытым исходным кодом. Rocket-версии v0.5: поддерживает асинхронный режим, SSE, WebSockets и т. д . Отец Redis реализует фреймворк Telegram Bot с использованием чистого кода языка C. Если вы являетесь сопровождающим проекта с открытым исходным кодом, столкнитесь с вопросом: «Как далеко вы сможете вынести такой ответ?» PHP 8.3 общедоступная версия
{{o.name}}
{{m.name}}

Supongo que te gusta

Origin my.oschina.net/u/5587102/blog/10143202
Recomendado
Clasificación