Рекомендации
Рекомендация — одно конкретное actionable наблюдение: конкретный модуль на разбивку, конкретный импорт на конвертацию, конкретный цикл на разрыв. У каждой есть данные, её породившие (чтобы можно было проверить), объяснение и — где это осмысленно — counterfactual («removes 7 of 12 cycles in this group»).
Каталог намеренно небольшой. Лучше пропустить пограничный случай, чем выдать вам 200 шумных карточек «consider reviewing X».
Как рекомендации скорятся
У каждой рекомендации есть severity (info / low / medium / high), вычисленный из лежащего в основе сигнала. Десктоп сортирует по severity, потом по импакту (циклов разорвано, модулей затронуто). CLI отдаёт те же данные в поле recommendations[] JSON-конверта.
--fail-on recommendations:N в check срабатывает, когда суммарных рекомендаций > N — полезен как «любой новый совет вообще» гейт; в большинстве проектов вы предпочтёте более конкретные cycles:0 или layer-violations:0.
Каталог
split-god-module
Модуль попадает в топ-5% проекта по fan-in, имеет fan-in ≥ 8 и длину ≥ 300 строк.
Все три порога важны. Один fan-in — over-flag для маленьких heavily-used утилит. Одни строки — over-flag для длинных, но изолированных файлов. Вместе они ловят паттерн «этот файл делает слишком много, и от него все зависят».
Типичный фикс: найти когезивные группы экспортов, вынести их в соседние файлы, подкрутить импорты. Часто один файл превращается в 3–4 файла половинного размера.
unused-utility
Файл, классифицированный как util (путь матчит utils|lib|helpers), с fan-in 0. Fan-in считает статические импорты, динамические импорты (включая template-literal import() и import.meta.glob), entry-точки и интеграционные файлы (loaders, plugins, registries) — последние из «unused» исключаются.
Типичный фикс: удалить файл. Одна из немногих рекомендаций, где действие однозначно.
cycle-break-candidate
Для каждого цикла — самое высокоскоренное внутреннее ребро по feedback-arc-set эвристике. Идёт с counterfactual removes N of M cycles in this group.
Типичный фикс: разрезать ребро — удалением, инверсией или переносом типа.
cycle-break-cluster
Группирует параллельные циклы, проходящие через одни и те же back-рёбра, в одну рекомендацию. Полезно, когда SCC содержит несколько циклов, делящих одно-два «закрывающих» импорта.
Для каждого back-ребра в кластере — точный (для маленьких) или оценочный (для больших) счётчик отдельных циклов, проходящих через него. Берите с самым высоким счётчиком первым.
type-only-candidate
Файл импортирует имя из другого файла, но все использования этого имени — типовые позиции (x: SomeType, extends SomeInterface, as SomeType). Замена import на import type безопасна и стирает импорт при сборке — а любой цикл, в котором он участвовал, исчезает с ним.
Одно value-использование (SomeType(), typeof SomeType) дисквалифицирует. Мы никогда не флагаем кандидата, если хотя бы одно использование — runtime-значение.
Типичный фикс: добавить модификатор type к существующему импорту. Однострочное изменение.
Это единственный вид рекомендации с встроенным auto-fix в десктоп-приложении. Иконка-палочка рядом с ? открывает side-by-side diff и предлагает Применить / Применить и пересканировать / Скопировать патч. Патч генерируется из AST (ts.createSourceFile): import { A, B } from 'x' становится import type { A, B } from 'x'; если только часть bindings — type-only, импорт разделяется (import { runtime } from 'x'; import type { Foo } from 'x';), чтобы value-сторона продолжала работать. Backup'ы пишутся в .archora/backups/. См. Работа с графом.
misplaced-by-layer
Модуль сидит в слое X, но ≥ 70% его dependents — в одном другом слое Y, при минимум 5 dependents всего.
Типичный фикс: перенести файл в слой Y. Убирает большинство cross-layer переходов разом.
top-violator
Один модуль — источник нескольких нарушений слоёв. Рекомендация суммирует количество и целевые слои.
Типичный фикс: ревью импортов этого одного модуля. Часто причина — смешанные ответственности; разбиение (или перенос) убирает несколько нарушений за один PR.
isolated-cluster
Связная компонента неориентированного графа импортов (без type-only рёбер) с ≥ 5 модулями, у которой:
- нет entry-точек внутри,
- нет инфраструктурных файлов,
- размер не превышает половины кодбейза (чтобы не флагать основную компоненту как «изолированную»).
Типичный фикс: разобраться. Скорее всего dead code, удалённая фича, не до конца почистившаяся, или vendored-копия, которая не подключилась. Подтвердив — удалить или подключить.
Достижимый runtime-код (MFE-loader-ы, import.meta.glob, кастомные dynamic-loader-ы из archora.config) подцепляется до запуска этого правила, чтобы не было ложных срабатываний на лениво загружаемых маршрутах.
Почему нет других рекомендаций?
Мы намеренно не выводим:
- «Функция X слишком длинная.» Файлы — да, function-level метрики — нет: пришлось бы лезть глубже в парсер, и сигнал слишком шумный.
- «У модуля X слишком много импортов.» Один высокий fan-out не повод для карточки; если это важно — оно вылезет как hot zone или god-module.
- «Модуль X часто меняется.» Git-churn — реальный сигнал, но он вне модели архитектуры; пусть его покрывают другие тулы — анализатор остаётся pure-of-graph.
См. также
- Feedback Arc Set — алгоритм за cycle-break рекомендациями.
- Hot zones — как
split-god-moduleвырастает из hot-zone сигнала. - Слои архитектуры —
misplaced-by-layerиtop-violator.