Files
slm-design/docs/reference/validation.md
2026-08-10 12:37:32 +03:00

121 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Проверка архитектуры
Проверка SLM подтверждает две разные стороны решения:
- смысловая проверка устанавливает ответственность, владельца и корректность границ;
- структурная проверка подтверждает, что решение правильно выражено путями, публичными фасетами и зависимостями.
Успешная сборка или корректно отображаемый интерфейс не доказывают архитектурную корректность.
## Карточка решения
Перед изменением структуры нужно ответить:
| Вопрос | Что зафиксировать |
|---|---|
| Ответственность | Какой результат или поведение изменяется как единое целое |
| Владелец | Какой модуль определяет контракт и внутреннюю реализацию |
| Слой | Какой архитектурной роли соответствует ответственность |
| Потребители | Кому действительно нужен публичный API |
| Зависимости | Какие другие владельцы и возможности необходимы |
| Состояние | Кто определяет смысл и допустимые изменения данных |
| Жизненный цикл | Кто создаёт ресурсы, какова их область жизни и очистка |
| Физическая форма | Какими путями и фасетами представлено принятое решение |
Если ответственность или владелец не определены, проверка путей откладывается: одинаковая файловая структура может представлять разные архитектурные решения.
## Архитектурное ревью
На ревью проверяется смысл кода, который нельзя надёжно вывести из файловой системы:
- одна ли связная ответственность находится внутри модульной границы;
- есть ли у каждой самостоятельной ответственности ровно один ближайший владелец;
- соответствует ли ответственность роли выбранного слоя;
- владеет ли вложенный модуль отдельно сформулированной подответственностью;
- не стали ли группа или сегмент скрытыми владельцами;
- реализует ли внутренний код ответственность ближайшего модуля;
- не принимаются ли props, Context, локальное состояние или lifecycle-код за достаточное основание для новой модульной границы;
- является ли главный файл в корне однозначной реализацией или сборкой ответственности;
- не лежат ли прочие файлы реализации в корне вместо подходящих сегментов;
- нужен ли каждый экспорт реальному внешнему потребителю;
- не раскрывает ли публичный API изменяемые внутренние механизмы;
- определены ли владелец, область жизни, число экземпляров и очистка каждого ресурса.
Окончательные смысловые требования имеют класс `R` в [реестре правил](../rules/registry.md).
## Автоматическая проверка
Проект сопоставляет физические пути с SLM root, слоями, группами, модулями, вложенными модулями, сегментами, фасетами, точками входа `app` и ресурсами `shared`. Сопоставление задаётся локальной конфигурацией и не меняет смысл сущностей.
Наличие `index.ts` само по себе не объявляет модуль. Проверка отличает объявленные корни модулей и их публичные фасеты от локальных точек входа и других внутренних единиц.
Автоматически проверяются:
- допустимое направление импортов по матрице слоёв;
- отдельная папка каждого модуля;
- доступ к чужому модулю только через объявленные фасеты;
- отсутствие циклов в свёрнутом модульном графе;
- отсутствие прямого внешнего доступа к вложенным модулям;
- допустимый транзитивный граф исполняемых импортов каждого фасета среды выполнения;
- динамическое подключение `browser`-фасета с отключённым SSR.
Каждое правило класса `A` должно полностью блокировать проверку при нарушении. SLM не требует конкретного lint-инструмента.
## Проверка зависимостей
Для каждого внешнего импорта определяется:
1. Ближайший модуль-владелец исходного файла.
2. Ближайший модуль-владелец целевого файла.
3. Слои исходного и целевого владельцев.
4. Публичный фасет, через который выполнен импорт.
5. Отсутствие цикла после добавления межмодульного ребра.
Импорты типов (`import type`) и реэкспорты проверяются как архитектурные связи. Импорты файлов одного модуля сворачиваются и не создают межмодульного ребра. Вложенный модуль считается отдельным узлом.
File-level проверка не заменяет модульную: два модуля могут зависеть друг от друга через разные файлы без замкнутого пути между конкретными файлами. Полный алгоритм описан в разделе [Зависимости](../architecture/dependencies.md#запрет-циклов).
## Проверка внутренней структуры
Ревью или дополнительный project lint подтверждают:
- помимо опционального главного framework-файла, остальные компонентные единицы размещены на одном внутреннем уровне модуля;
- их локальные каталоги не содержат другие компонентные единицы или вложенные модули;
- runtime-дерево компонентов не используется как файловая иерархия;
- рекурсивная структурная вложенность проходит только через вложенные модули;
- в корне модуля находятся только фасеты и опциональный главный implementation- или assembly-файл;
- остальная реализация организована сегментами.
## Проверка фасетов
Совместимость фасета определяется всем достижимым исполняемым кодом, а не только его собственным файлом.
Проверка подтверждает:
- `index` не достигает `client`, `browser` или `server`;
- `client` не достигает `browser` или `server`;
- `browser` и `server` не достигают друг друга;
- `browser` экспортирует только browser-only или предназначенный для динамического подключения клиентский код;
- `browser` доступен только через поддерживаемую динамическую границу без SSR;
- специализированный фасет существует ради реального потребителя;
- один исполняемый экспорт не дублируется между фасетами.
Импорт типа остаётся архитектурной зависимостью, но не добавляет исполняемый код в среду фасета.
## Критерий завершения
Изменение соответствует SLM, когда одновременно выполнены условия:
- ответственность и единственный ближайший владелец определены;
- роль слоя соответствует ответственности;
- публичный API минимален и используется всеми внешними потребителями;
- зависимости разрешены и не образуют модульных циклов;
- группа и сегменты не подменяют модульную границу;
- вложенные модули владеют отдельными подответственностями;
- внутренний код реализует ответственность ближайшего модуля;
- framework-компоненты имеют одноуровневую файловую организацию с единственным допустимым исключением для главного файла в корне;
- корень и сегменты соответствуют своим назначениям;
- состояние и ресурсы имеют владельца и корректную область жизни;
- физическая структура однозначно выражает принятое решение;
- применимые автоматические проверки и архитектурное ревью пройдены.