指南
迁移到 DMA
如何在现有项目中采用 DMA,而无需一次性大改。
迁移到 DMA 不是「一个冲刺重写一切」。这是渐进式收紧:先划定边界并接入检查,再根据图信号进行提升(promotion)和 shared 调整。
阶段 0:明确目标
你希望:
- 在代码评审中不再为导入争论;
- 在 CI 中捕获循环和 feature-to-feature 边;
- 通过就近放置(colocation)成长,而非过早引入
shared/。
如果 Confluence 上的风格指南已足够——DMA 可能过重。
阶段 1:目录树与工具(第 1 天)
- 将
src/整理为基线布局:
src/
├── app/ # or pages/, routes/
├── features/
└── shared/ # can be nearly empty- 安装 CLI:
npm install -D @derived-modular/cli- 接入 CI:
npx @derived-modular/cli check . --format json首次运行 dma check 会呈现真实图景——长列表不必惊慌。
阶段 2:组合根(第 1 周)
目标: 路由和 layout 只导入 */public/*。
| 之前 | 之后 |
|---|---|
import { X } from '@/features/foo/internal' | import { X } from '@/features/foo/public/foo-page' |
page.tsx 中的逻辑 | 精简外壳 + 从 feature 挂载 |
在修复入口点之前,不要动模块内部。
阶段 3:移除 feature → feature(第 2–3 周)
典型的 DMA 前模式:
features/catalog → features/checkout/internal修复选项:
- 提升(promotion)——产品代码放入
services/ - 上移到 shared——无产品逻辑的可移植 helper
- 在 app 中接线——props、事件、providers(跨模块接线)
每次重构后执行 npx @derived-modular/cli check .。
阶段 4:公共 API 与 barrel 文件(第 3–4 周)
- 移除模块内 barrel
index.ts的再导出 - 将公共符号移至
public/,使用直接路径 - 若模块为单文件,保留 stage-0 文件(
features/profile.tsx)
阶段 5:提升(promotion)与 shared(按信号)
不要提前创建 services/。等待:
check中出现feature-has-inbound——该提升了doctor中出现shared-candidate——考虑上移
规划时每个 sprint 运行一次 npx @derived-modular/cli doctor .。
大型代码库策略
按 feature 绞杀(Strangler)
选一个垂直域(如 checkout),按 DMA 布局,并通过独立 package/文件夹暂时将其余部分排除在 dma check 之外——不要全局禁用规则。
Monorepo
dma check 每个根对应一张图;从 monorepo 根目录可使用 multi-root discover:
npx @derived-modular/cli check .
npx @derived-modular/cli check apps/web
npx @derived-modular/cli check --roots apps/web,apps/admin详见 Monorepo。
遗留的 utils/ 与 components/
不要一次性全部重命名。新代码遵循 DMA。旧代码在第二次使用或编辑该文件时再动。
就绪清单
- 每个 PR 的 CI 中运行
dma check - 组合根只导入
public/ - 无 feature → feature
- 模块内无 barrel 文件
- 编辑器中的 linter 用于快速反馈
- 团队了解代码演进和文件放哪里