Stop Circular Dependencies With SDP

Циклические зависимости — это тихие убийцы. Они не вызывают ошибок сборки. Они не вызывают исключений при импорте во время выполнения. Вместо этого они приводят к появлению едва заметных значений undefined, которые всплывают в продакшене спустя недели.

Цикл возникает, когда модуль A импортирует что-то из B, а B импортирует что-то обратно из A.

JavaScript разрешает такие импорты незаметно. Если модуль A всё еще загружается в тот момент, когда модуль B запрашивает его, JavaScript возвращает пустой объект. Ваш код ломается позже, а стек вызовов указывает не на то место.

Это можно исправить с помощью dependency-cruiser. Этот инструмент сканирует ваши файлы и строит граф зависимостей. Он работает с TypeScript и монорепозиториями.

How to set it up:

  • Добавьте его в dev dependencies: yarn add -D dependency-cruiser
  • Добавьте скрипт в package.json: "depcruise": "depcruise packages --config .dependency-cruiser.js"
  • Создайте файл .dependency-cruiser.js, чтобы отлавливать циклы.

Но найти цикл — это только половина дела. Вы должны не дать им возникнуть.

Используйте принцип стабильных зависимостей (Stable Dependencies Principle, SDP). Это правило гласит: вы должны зависеть в направлении стабильности.

Стабильность — это структурное свойство. Модуль является стабильным, когда от него зависят многие другие модули. Если вы измените стабильный модуль, это затронет многих людей. Эта цена делает его стабильным.

Используйте формулу нестабильности: I = Fan-Out / (Fan-In + Fan-Out)

• I = 0 означает, что модуль максимально стабилен. Все зависят от него, а он не зависит ни от чего. • I = 1 означает, что модуль максимально нестабилен. Он зависит от многих вещей, а от него никто не зависит.

The rule: Показатель нестабильности модуля должен быть выше показателя каждого модуля, который он импортирует. Ваши стрелки должны указывать в сторону меньшей нестабильности.

Ваши низкоуровневые утилиты (I ≈ 0) никогда не должны импортировать что-либо из высокоуровневых страниц (I ≈ 1).

Вы можете превратить этот принцип в автоматизированное правило с помощью dependency-cruiser. Вместо того чтобы просто искать циклы, проверяйте направление:

  • Запретите утилитам импортировать что-либо из фич (features).
  • Запретите фичам импортировать что-либо из страниц (pages).

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

Source: https://dev.to/wojciech_kot_b82f5d7cbfc6/stop-circular-dependencies-before-they-stop-you-dependency-cruiser-the-stable-dependencies-34ho