mirror of
https://github.com/gromlab-ru/slm-design.git
synced 2026-08-22 07:30:16 +03:00
chore: sync
This commit is contained in:
102
docs/architecture/dependencies.md
Normal file
102
docs/architecture/dependencies.md
Normal file
@@ -0,0 +1,102 @@
|
||||
# Зависимости
|
||||
|
||||
Зависимость связывает архитектурных владельцев. Исходный файл создаёт ребро от своего ближайшего модуля к ближайшему модулю импортируемого файла.
|
||||
|
||||
## Модульный граф
|
||||
|
||||
Узлами архитектурного графа являются модули, включая вложенные. Группы, сегменты, 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)
|
||||
Reference in New Issue
Block a user