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

88 lines
5.2 KiB
Markdown
Raw Normal View History

2026-08-10 09:12:22 +03:00
# Зависимости SLM
> Пояснение нормативной модели зависимостей SLM.
Матрица слоёв задаёт допустимые зависимости между модулями.
## Что считается зависимостью
- Обычный импорт, импорт типа и реэкспорт одинаково создают архитектурную зависимость.
- Импорт между файлами одного модуля не пересекает модульную границу.
- Импорт любого внутреннего файла, сегмента или компонента считается зависимостью ближайшего модуля-владельца.
- Вложенный модуль имеет собственную границу зависимостей.
- Группы, сегменты и компоненты не имеют самостоятельных границ зависимостей.
Точка входа фреймворка не является модулем. Её импорты участвуют в проверке направления слоёв.
Ресурс `shared` также не является модулем. Его прямой импорт участвует в проверке направления слоёв, но не нарушает требование о публичном API модуля.
## Допустимые связи
- Модуль может импортировать модули своего слоя и слоёв, разрешённых нормативной матрицей.
- Модули одного слоя могут импортировать друг друга.
- Промежуточный слой не является обязательным посредником.
- `infra` может импортировать `ui` для визуального представления технической возможности; `ui` не импортирует `infra`.
Модуль слоя `domains` может импортировать публичный API другого разрешённого модуля. Runtime- и type-only импорты одинаково создают архитектурную зависимость, а циклические зависимости запрещены.
```ts
// domains/orders
import type { Product } from '@/domains/catalog'
```
SLM не требует отдельного механизма инъекции между модулями слоя `domains`.
Матрица слоёв определена в [Слоях](./layers.md).
## Связанные правила
- [`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)
- [`SLM-ENVIRONMENT-R016`](../rules/registry.md#slm-environment-r016)
- [`SLM-ENVIRONMENT-R017`](../rules/registry.md#slm-environment-r017)
- [`SLM-ENVIRONMENT-R018`](../rules/registry.md#slm-environment-r018)
- [`SLM-ENVIRONMENT-R019`](../rules/registry.md#slm-environment-r019)
## Публичный API
```ts
// Допустимо
import { Button } from '@/ui/button'
// Недопустимо
import { Button } from '@/ui/button/button'
```
Если модуль объявляет специализированный фасет, его путь также является публичным:
```ts
import type { Session } from '@/domains/auth'
import { AuthProvider } from '@/domains/auth/client'
import { getServerSession } from '@/domains/auth/server'
```
## Фасеты сред выполнения
Ограничения фасета распространяются на все его runtime-импорты и реэкспорты, включая транзитивные. Type-only import остаётся архитектурной зависимостью, но не добавляет исполняемый код в среду фасета.
`index` не импортирует и не реэкспортирует `client`, `browser` или `server`. `client` может использовать универсальную внутреннюю реализацию модуля, но не импортирует `browser` или `server`. `browser` и `server` могут использовать универсальную внутреннюю реализацию, но не импортируют друг друга.
```ts
// Browser-only фасет подключается только за границей без SSR.
const BrowserEditor = dynamic(
() => import('@/domains/editor/browser').then(({ BrowserEditor }) => BrowserEditor),
{ ssr: false },
)
```
Обычный статический импорт `@/domains/editor/browser` запрещён даже внутри Client Component. Tree shaking, проверка `typeof window` и обещание не вызывать экспорт при SSR не заменяют динамическую границу с отключённым SSR.
## Циклы
```text
ui/modal → ui/button → ui/icon
ui/icon -/→ ui/modal
```