Введение

NestJs стал одним из самых популярных и прогрессивных фреймворков nodejs. Nodejs и другие библиотеки существуют уже много лет, но ни одна из них не смогла решить проблемы, связанные с архитектурой. NestJS предоставляет готовую архитектурную среду, которая может быть знакома тем, кто имеет опыт работы с концепциями Angular или немного Java (Spring). Если вы знакомы с архитектурными принципами, вы, скорее всего, найдете архитектуру NestJS вполне узнаваемой.

В NestJS есть концепция, известная как «провайдеры». Эти поставщики могут быть внедрены в структуру как зависимости, а NestJS динамически обрабатывает процесс подключения во время выполнения.

Проблема циклической зависимости

Круговая зависимость возникает, если классу А требуется класс Б, и в то же время классу Б требуется класс А.

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

NestJs выдает ошибку циклической зависимости при загрузке приложения.

Выявление циклической зависимости

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

В этой ситуации на помощь приходит инструмент CLI под названием madge.

Madge — это инструмент командной строки, который определяет зависимости между файлами. Его также можно использовать в командной строке, а также он может генерировать визуальный график, показывающий все зависимости модулей.

Для отображения визуальных зависимостей мы можем использовать graphviz

Монтаж

npm install -D madge
npm install -D graphviz

Создать график зависимостей

madge --image graph.png --extensions ts src

--image graph.png: Создать изображение зависимого графика в виде файла .png.

--extensions ts: ищет зависимости только в файлах машинописного текста (.ts).

src: поиск в папке ./src. Мы можем передать несколько папок, разделенных пробелами.

Приведенная выше команда напрямую генерирует изображение графа зависимостей.

Если вы хотите видеть только циклические зависимости, передайте --circular в качестве параметра.

madge --image graph.png --extensions ts --circular src 

Синим цветом показаны файлы, имеющие зависимости, узлы зеленого цвета не имеют никаких зависимостей, а узлы красного цвета имеют круговые зависимости.

* Использование Graphviz (для больших приложений со слишком большим количеством файлов)

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

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

* Генерация файла .gv с помощью madge.

madge --dot --extensions ts src > graph.gv

Это создаст файлgraph.gv в текущей папке.

Теперь мы можем либо скопировать и вставить содержимое этого файла в онлайн-визуализатор Graviz, либо вы можете установить Расширение VSCode, которое показывает предварительный просмотр ваших файлов .gv в реальном времени. (Чтобы открыть, нажмите Ctrl+Shift+p -> введите > graphviz preview)

Рефакторинг и решение

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

  • Мы можем использовать внедрение зависимостей NestJs (ForwardRef) для решения проблемы.
  • Мы можем реорганизовать наши модули, чтобы разделить задачи.
  • Создавайте общие модули для общих функций, чтобы избежать межмодульных зависимостей.

Заключение

Циклическая зависимость обычно возникает, когда код тесно связан. Из прошлого опыта я видел, что когда мы стараемся не дублировать код (DRY), мы попадаем в такую ​​ситуацию.

Нам часто приходится разрабатывать независимые основные службы, которые принимают базовые входные данные и возвращают некоторые DTO. Затем нам следует организовать их в других службах/контроллерах, даже если нам придется вызвать две или более служб, чтобы получить окончательный результат. Их объединение и создание другого сервиса часто приводит к проблемам.

Если возникает циклическая зависимость, нам следует подумать о разделении кода, перемещении нашего кода в другой модуль features и создании основного модуля со службами. Если в обоих модулях используется один метод, посмотрим, сможем ли мы переместить его в служебный модуль. Как правило, я не предпочитаю создавать общий служебный класс, такой как utils.js (создавайте конкретные служебные классы, такие как StringHelper.js, LeadDuplateHelper.js).

Приятного кодирования!! Приветствую 👋