Derived Modular Arch
Концепции

Эволюция кода

Как архитектура растёт без переписывания: второе использование, promotion, сигналы doctor.

DMA не масштабируется заменой архитектуры на другую. Проект уплотняется на месте: папки появляются, когда предикаты начинают нести информацию.

Вы не создаёте пустой services/ «на вырост». Вы не выносите в shared/ «вдруг пригодится». Рост — ответ на факт второго потребителя или на сигнал инструментов.

Три фазы проекта

1. Старт

src/
├── app/          # или pages/, routes/
├── features/
└── shared/       # почти пустой

Нет services/. Все модули — изолированные фичи.

2. Первая promotion

Модуль стал нужен другому модулю → создаёте services/, переносите модуль, пересматриваете public API. С этого момента полезны проверки циклов внутри services.

Пример: catalog вызывает addToCart, checkout тоже — cart переезжает из feature в services/cart/.

3. Домены (когда services разросся)

Плотный подграф services или несколько команд → горизонтальный split (domains/billing/, отдельные пакеты). Новые вертикальные слои не добавляются.

Правило второго использования

Что произошлоДействие
Feature нужен другому модулюPromotion в services/
Переносимый хелпер/UI нужен 2+ модулямLift в shared/ (нужная группа)
Тип из public/ нужен 2+ модулямПеренос в shared/domain

import type — тоже ребро графа. Обход через типы не сработает.

Монтирование из корня композиции не считается входящие рёбра и promotion не вызывает.

Promotion — момент дизайна

Когда feature получает входящих рёбер от другого модуля, API, выросшее для одного потребителя, становится контрактом для многих. Это осознанный шаг:

  1. Перенести в services/<name>/
  2. Пересмотреть public/ — что действительно нужно снаружи
  3. Убедиться, что dma check зелёный (feature-has-inbound больше не ругается)

Триггеры роста модуля

СигналДействиеTooling
Соседние файлы с общим basename-префиксом у стадия-0 (checkout.tsx + checkout.store.ts)Стадия 1: папка + public/stage-growth
~8+ внутренних файловСтадия 2: сегменты ui/model/apistage-growth
Раздутый public/Стадия 3: split модуляРевью (doctor пока нет)
Feature нужен модулюPromotion → services/feature-has-inbound
Цикл между модулямиПорт + связка в app, или extract в sharedno-cycle
Плотный services подграфГоризонтальный splitdense-services

Пороги — дефолты CLI. В v1 нет user config для их изменения.

Сигналы dma doctor

Мягкие подсказки. Код выхода 0 — CI не ломают.

shared-candidate

Файл модуля импортируют 2+ других модуля. Часто это здоровая поверхность services/*/public/*. Перед перенос в shared/ спросите: это продукт или переносимый хелпер?

stage-growth

Структура модуля отстаёт от размера: file-модуль оброс соседний файл-файлами с тем же basename-префиксом, или в папке много файлов без сегментов ui/ / model/ / api/.

dense-services

Подграф services/ выглядит плотным — пора делить по доменам.

orphan-public

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

Подробнее о команде — dma doctor.

При внедрении в существующий проект promotion и doctor-сигналы идут в связке с поэтапным планом — Миграция.

Что дальше

On this page