Использование DDD и Monorepos для создания устойчивых приложений

Монолит против микроархитектуры

Микрофронтендыявляются новой тенденцией, и вокруг нее много шума, потому что это крутая технология, которая имеет свои преимущества, такие как независимое развертывание. Часто недостатки не упоминаются, тогда как наиболее важным недостатком является повышенная сложность, так что эту архитектуру не следует рассматривать для многих приложений.

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

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

Есть много принципов проектирования, которые можно использовать для предотвращения этого, одним из которых является Modulith, объединяющий лучшее из обоих миров.

Дизайн, управляемый доменом

Moduliths основаны на фундаментальном принципе проектирования под названием Domain Driven Design, который заключается в разработке независимых полнофункциональных блоков функций — мы называем эти домены. Если мы посмотрим на Medium в качестве примера, мы можем предположить, что у нас есть как минимум следующие домены: создание блога, выставление счетов, статистика, пользовательский фид, уведомления/обмен сообщениями и т. д., …. Он пытается свести зависимости между отдельными доменами к минимуму, поэтому оптимальным сценарием было бы, если бы ни один домен не имел никаких зависимостей от другого. Обычно это не всегда так, но с помощью таких шаблонов, как общие ядра или отдельные ограничения API, мы можем свести зависимости к минимуму.

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

Модулиты

Модуль основан на DDD, так что он разбивает классический монолит на домены. Эти домены не будут реализованы непосредственно в самом приложении, вместо этого каждый домен станет библиотекой angular, которая затем будет использоваться приложением.

Как и в архитектуре микрофронтенда, у нас есть отдельные домены/библиотеки, которые проводят четкие границы, что делает программное обеспечение более стабильным. Но у нас нет сложности микрофронтенда, потому что вместо того, чтобы потреблять библиотеки в разных микрофронтендах, все библиотеки потребляются в одном приложении.

Вкратце, модули имеют четкие границы, как микрофронтенд-архитектура в DDD-стиле, но меньший уровень сложности монолита.

Nx

В качестве внешнего интерфейса используется Angular, но, честно говоря, настоящий герой в этом примере — Nx. Никогда раньше не слышали о Nx? По сути, Nx предоставляет дополнительные инструменты поверх Angular CLI для создания монорепозиториев и управления ими, в которых различные приложения и библиотеки хранятся в одном репозитории только с одним package.json. Это означает, что каждая библиотека и приложение зависят от пакетов одной и той же версии, поэтому несоответствие версий невозможно. Кроме того, вам не нужно публиковать свои библиотеки в реестре NPM и устанавливать их в приложении, вместо этого вы можете напрямую ссылаться на них с помощью Nx. Уже звучит хорошо? Будьте готовы к еще большему совершенству.

Пакет @angular-architects/ddd

Angular Architects предоставляет очень хороший пакет схем, который не только помогает нам следовать DDD, но также дает нам возможность принудительно применять его. Сначала делаем классическую нарезку домена и создаем папку в папке libs для каждого домена. Но мы не останавливаемся на этом, вместо этого мы также проводим четкие границы внутри доменов, углубляясь в Функции, UI, Домен и Утилиты. .

Умные компоненты будут считаться функциями, тогда как немые компоненты будут считаться пользовательским интерфейсом. Управление состоянием, сервисы, взаимодействие с серверной частью и логика в целом содержатся в домене. Utils будет содержать довольно классические независимые вспомогательные функции JavaScript, такие как createUuid(), parseSomeDate() и т. д.

Но это еще не все! Если мы используем схемы @angular-architects/ddd, то каждая функция, пользовательский интерфейс, домен и утилиты будут отдельной библиотекой. Почему так? Таким образом, в файлы project.json можно добавлять теги, которые мы можем использовать в конфигурации linting для создания горизонтальных и вертикальных ограничений. Это означает, что мы можем не только ограничить доступ между доменами A и B, но и сделать ограничения внутри самого домена, так как мы разделяем домен на подбиблиотеки.

  • Утилиты могут зависеть ни от чего
  • Домен может зависеть от Utils.
  • UI может зависеть от домена, Utils.
  • Функция может зависеть от UI, домена, Utils.

Правила линтинга

Внутри файла .eslintrc.json теперь мы можем использовать теги, указанные в библиотеках, для создания ограничений в виде правил линтинга. К счастью, пакет @angular-architects/ddd справляется со всем этим, когда мы используем его схемы для создания библиотек.

Внутри массива depConstraints зависимости указываются явно следующим образом:

...
{
   “sourceTag”: “domain:domainA”,
   “onlyDependOnLibsWithTags”: [
      “domain:domainA”,
      “domain:shared”
   ]
}, 
...
{
   "sourceTag": "type:feature",
   "onlyDependOnLibsWithTags": [
      "type:ui",
      "type:domain-logic",
      "type:util"
    ]
},
...

Реалистичный сценарий

В идеале все домены должны быть идеально изолированы друг от друга без каких-либо зависимостей, но это просто нереально. Часто домен A будет иметь крошечную зависимость от чего-то внутри домена B, и это совершенно нормально, если мы знаем, как с этим справиться. Мы можем создать либо отдельный Barrel только для демонстрации зависимостей для домена A, либо создать общее ядро, что также является хорошим подходом, когда мы беспокоимся о циклических зависимостях.

Но имейте в виду, что размещение всего в общем ядре превратит ваше приложение обратно в классический монолит, уничтожив все преимущества, которые мы получаем благодаря модульной конструкции. Итак, создайте несколько общих ядер, если это возможно, и не помещайте все глупые компоненты в общее ядро. Хотя немые компоненты не знают точного контекста данных, в котором они используются, они все же могут знать домен, в котором они используются.

Заключение

Moduliths очень хорошо подходят для многих архитектур. Если вы хотите четко структурировать свое приложение и обеспечить соблюдение границ с помощью правил Linting, но не заботитесь о независимых развертываниях, то вам подойдет модуль. Если вам не нравится DDD, вы все равно можете создать что-то вроде модуля, используя Nx, отдельные библиотеки и правила линтинга для защиты границ. В противном случае я рекомендую использовать пакет @angular-architects/ddd, чтобы следовать DDD в вашем приложении Angular.

Присоединяйтесь к Medium по моей реферальной ссылке:

Если вам понравился этот пост в блоге и вы хотите неограниченно читать на Medium, я был бы признателен, если бы вы воспользовались моей реферальной ссылкой для создания подписки на Medium:



Другие интересные чтения:









Подробнее о DDD с Angular:



Повышение уровня кодирования

Спасибо, что являетесь частью нашего сообщества! Больше контента в публикации Level Up Coding.
Подписывайтесь: Twitter, LinkedIn, Информационный бюллетень
Level Up трансформирует рекрутинг в сфере технологий 👉 Присоединяйтесь к нашему коллективу талантов