Derived Modular Arch
Инструменты

dma doctor

Мягкие сигналы эволюции для локальной работы — без падения CI.

dma doctor смотрит на тот же граф, что и check, но ищет сигналы роста, а не жёсткие нарушения. По умолчанию код выхода 0 — команду можно гонять хоть каждый коммит, CI не сломается.

Думайте о doctor как о «архитектурном линтере наперёд»: подсказывает, что пора вынести, промоутить или разделить — до того, как check начнёт ругаться.

Запуск

npx @derived-modular/cli doctor .
npx @derived-modular/cli doctor . --format json
npx @derived-modular/cli doctor . --format sarif
npx @derived-modular/cli doctor . --suggest   # план удаления orphan-public
npx @derived-modular/cli doctor . --fix      # удалить orphan public файлы

Те же форматы вывода, что у check: human, json, SARIF.

doctor vs check

dma checkdma doctor
НазначениеЖёсткие правилаСигналы эволюции
Блокирует CIДа (код выхода 1)Нет (код выхода 0)
Повторяет rule ID из checkНет
Когда запускатьCI, pre-pushЛокально, раз в спринт

Doctor не дублирует ошибки check. Если check красный — сначала чините check.

Сигналы

shared-candidate

Файл модуля импортируют 2+ других модуля.

В help — следующий шаг алгоритма размещения по текущему слою файла:

  • в features/ → promote в services/<name>/public/ (Placement #2)
  • в services/ → оставить, если product flow, иначе вынести в shared/{ui,lib,…} (Placement #2–3)
  • в shared/ → уже shared; следите, чтобы хелпер оставался переносимым (Placement #3)

Не поднимайте в shared автоматически — сначала поймите смысл кода.

stage-growth

Структура модуля отстаёт от размера. help привязывает фикс к colocation из placement:

  • file-модуль (стадия 0) оброс соседними файлами с тем же basename-префиксом (например checkout.tsx + checkout.store.ts) → папка и public/ (Placement #4–5)
  • много файлов без сегментов → добавьте ui/, model/, api/ (Placement #4)

Порог по умолчанию — около 8 файлов (stage1FileCount).

Пример: stage-growth на checkout

До — стадия 0, один UI-файл, но рядом появился store с тем же префиксом:

features/
├── checkout.tsx
└── checkout.store.ts

dma doctorstage-growth: file-модуль checkout оброс соседний файл с префиксом checkout.

После — стадия 1:

features/checkout/
├── public/
│   └── checkout-page.tsx
├── checkout.store.ts
└── checkout.shipping.ts
  1. Создайте папку features/checkout/
  2. Перенесите UI в public/checkout-page.tsx
  3. Store и хелперы остаются internal; public/ импортирует их relative
  4. Обновите импорты в корень композиции на @/features/checkout/public/checkout-page
  5. npx @derived-modular/cli check . — зелёный; npx @derived-modular/cli doctor .stage-growth для checkout исчез

Если файлов станет ~8+ без сегментов — добавьте ui/, model/, api/ (стадия 2). См. Модули и public API.

dense-services

Подграф services/ выглядит плотным или глубоким. Пора делить горизонтально — домены, пакеты — а не добавлять новые вертикальные слои.

orphan-public

Файл в public/ никто не импортирует. Мёртвый контракт — удалите или сделайте внутренним.

--suggest / --fix могут удалить такие файлы только если в графе нет никаких импортеров (включая внутри модуля). Только single project root.

Типичный workflow

# утром
npx @derived-modular/cli check .          # блокировка

# перед рефакторингом
npx @derived-modular/cli doctor .         # что пора перестроить

# после крупного PR
npx @derived-modular/cli doctor . --format json > doctor.json

Не ждите doctor в CI как блокировка

Сигналы субъективны: shared-candidate на здоровом services/*/public/* — норма. Используйте doctor для разговора в команде, не для блокировки слияния.

В CI doctor имеет смысл только как информационная задача (артефакт json для дашборда).

Связанные темы

Что дальше

On this page