Files
slm-design/docs/architecture/dependencies.md

103 lines
6.8 KiB
Markdown
Raw Normal View History

2026-08-10 12:37:32 +03:00
# Зависимости
Зависимость связывает архитектурных владельцев. Исходный файл создаёт ребро от своего ближайшего модуля к ближайшему модулю импортируемого файла.
## Модульный граф
Узлами архитектурного графа являются модули, включая вложенные. Группы, сегменты, framework-компоненты, hooks, stores и другие файлы реализации отдельных узлов не создают.
Для каждой связи определяются:
1. Ближайший модуль-владелец исходного файла.
2. Ближайший модуль-владелец целевого файла.
3. Слои исходного и целевого владельцев.
4. Публичный фасет, через который пересечена граница.
Обычный импорт, `import type` и реэкспорт одинаково создают архитектурное ребро. Связь файлов внутри одного модуля остаётся внутренней реализацией и не создаёт межмодульную зависимость.
Вложенный модуль начинает новый узел. Импорт из родительского модуля во вложенный или обратно проверяется как обычная межмодульная связь.
## Публичная граница
При пересечении модульной границы используется только объявленный публичный фасет целевого модуля:
```ts
// Допустимо
import { Button } from '@/ui/button'
// Недопустимый глубокий импорт
import { Button } from '@/ui/button/button'
```
Разрешённое направление слоя или отсутствие цикла не делает глубокий импорт допустимым.
## Направление между слоями
Матрица определяет, от каких слоёв может зависеть исходный слой:
| Исходный слой | Допустимые целевые слои |
|---|---|
| `app` | `app`, `compositions`, `domains`, `infra`, `ui`, `shared` |
| `compositions` | `compositions`, `domains`, `infra`, `ui`, `shared` |
| `domains` | `domains`, `infra`, `ui`, `shared` |
| `infra` | `infra`, `ui`, `shared` |
| `ui` | `ui`, `shared` |
| `shared` | `shared` |
Разрешённая зависимость может пропускать промежуточные слои. Например, `compositions` может напрямую использовать модуль `ui`, не создавая посредника в `domains` или `infra`.
Разрешённое направление не переносит владение. Если модуль `domains` использует `infra`, предметный сценарий остаётся ответственностью доменного модуля, а техническая возможность — ответственностью инфраструктурного.
## Зависимости внутри слоя
Модули одного слоя могут зависеть друг от друга в любом направлении при одновременном выполнении двух условий:
1. Целевой модуль используется только через публичный API.
2. Общий модульный граф остаётся ацикличным.
Принадлежность модулей одной или разным [группам](./groups.md) не влияет на разрешение связи. Группа не имеет API и не является промежуточным узлом импорта.
SLM не задаёт отдельные same-layer матрицы для `pages`, `layouts`, `widgets`, доменов, инфраструктуры, UI или shared. Если проекту нужна более строгая локальная политика, она является дополнительным проектным ограничением, а не общим правилом SLM.
## Запрет циклов
Общий граф модулей внутри одного SLM root остаётся ацикличным. Запрет действует для модулей одного слоя, разных разрешённых слоёв и вложенных модулей.
Проверки только файлового графа недостаточно. Например:
```text
module-a/file-1.ts → module-b/file-1.ts
module-b/file-2.ts → module-a/file-2.ts
```
Между конкретными файлами может не существовать замкнутого пути, но после сопоставления файлов владельцам возникает архитектурный цикл:
```text
module-a ↔ module-b
```
Lint-проверка модульных циклов должна:
1. Сопоставить каждый файл ближайшему модулю-владельцу.
2. Свернуть внутренние импорты файлов одного модуля.
3. Добавить межмодульные рёбра для импортов типов, исполняемого кода и реэкспортов.
4. Считать каждый вложенный модуль отдельным узлом.
5. Блокировать любое сильносвязное множество из нескольких модулей.
Стандартная file-level проверка циклов может использоваться дополнительно, но не заменяет проверку модульного графа.
## Проверка связи
Для каждого нового или изменённого импорта проверяются три условия:
1. Направление разрешено матрицей слоёв.
2. Целевая модульная граница пересечена через публичный фасет.
3. После добавления ребра модульный граф остаётся ацикличным.
## Связанные правила
- [`SLM-LAYER-A002`](../rules/registry.md#slm-layer-a002)
- [`SLM-MODULE-A004`](../rules/registry.md#slm-module-a004)
- [`SLM-DEPENDENCY-A005`](../rules/registry.md#slm-dependency-a005)
- [`SLM-NESTED_MODULE-A010`](../rules/registry.md#slm-nested_module-a010)