关于 evolutionary-modular-architecture
用于设计可随产品和团队需求演进的模块化单体架构技能,帮助架构师和开发者划分领域边界、组织模块、规划通信与弹性,并制定拆分部署的演进路径。
主要功能
- 01DDD 限界上下文与上下文映射
- 02按聚合组织扁平模块
- 03端口、适配器与事务发件箱
- 04外部调用的弹性策略
- 05用于边界校验的 Node 脚本
- 06自包含的 HTML 架构文档
适用场景
- 01设计新平台或后端
- 02梳理领域上下文和数据所有权
- 03通过适配器集成外部供应商
- 04评估单体与微服务的边界
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ tech-leads-club/ agent-skills --skill evolutionary-modular-architecture安装后在 Claude Code 中输入/evolutionary-modular-architecture确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
assets/architecture-template.htmlreferences/acl-and-communication.mdarchitecture-doc.mdddd.mdflat-by-aggregate.mdprinciples.mdresilience.mdstack-2026.mdscripts/validate-boundaries.mjsvalidate-structure.mjs详细介绍
演进式模块化架构
将平台设计和构建为演进式模块化单体:从第一天起就设立明确的逻辑边界(DDD 限界上下文、按聚合扁平组织模块、围绕每个外部系统设置防腐层、事件驱动通信、默认具备韧性),同时将物理边界(独立部署、独立数据库)留作后续可选步骤。先从简单开始,只有在产品和团队确有需要时才调整粒度——绝不为了追赶潮流而反向设计微服务。
何时使用此技能
- 从头设计新的平台、后端或服务。
- 为某个领域定义限界上下文和上下文映射。
- 决定如何组织模块的文件夹和文件。
- 在单体、模块化单体和微服务之间做出选择。
- 集成外部供应商(或与其解耦):ERP、工单系统、存储、支付、AI、身份系统、持久化工作流引擎。
- 提高外部调用或模块间调用的韧性。
- 添加实时的服务端到客户端更新。
- 选择现代化(2026)的全栈 TypeScript 技术栈。
何时不使用
- 只有少量端点的简单 CRUD——使用框架默认设置即可。
- 深入探讨 NestJS 特定的实现细节——优先使用
nestjs-modular-monolith。 - 审查或重构单个贫血领域模型——优先使用
tactical-ddd。
统领一切的一条规则
始终严格区分逻辑边界与物理边界;前者固定,后者演进。 从第一天起,模块、契约、状态所有权和防腐层都不可妥协。模块是否独立部署、是否使用独立数据库,是之后再做的运维决策,绝不是结构上的前提。这样,系统就能从一次部署起步,并不断发展,而无需重写。
可以这样想象:房子里的房间划分明确(模块)。每个房间里的物品都摆在明处,并按用途归类(按聚合扁平组织),而不是埋在层层嵌套的抽屉里(按技术层划分的文件夹)。最重要的是平面布局(边界)。
核心模型(深入时加载相应的参考资料)
| 主题 | 涵盖内容 | 参考资料 |
|---|---|---|
| 原则 | 10 条模块化原则(P1–P10)+ 9 条结构原则(P11–P19)+ 冲突层级 | references/principles.md |
| DDD | 战略设计(子域、上下文映射、集成模式)+ 战术设计(富领域模型聚合、按子域调整建模强度) | references/ddd.md |
| 模块内部结构 | 按聚合扁平组织、后缀、深度、扁平结构与子域判定、脚手架 | references/flat-by-aggregate.md |
| 通信 | 端口与适配器 / ACL、事件 + 事务性发件箱、SSE 实时通信 | references/acl-and-communication.md |
| 韧性 | 退避 + 全抖动、熔断器、重试预算、幂等性、隔舱、超时 | references/resilience.md |
| 2026 技术栈 | 前端、后端、数据、可观测性、持久化工作流、决策 | references/stack-2026.md |
| 架构文档 | 构建精美且自包含的 HTML 架构文档,配有 SVG 图表 | references/architecture-doc.md + assets/architecture-template.html |
| 验证 | 用于检查结构和模块边界的确定性检查 | scripts/validate-structure.mjs、scripts/validate-boundaries.mjs |
不要一次性加载所有参考资料。仅在当前阶段需要时阅读相应资料(下方工作流会说明何时需要)。
工作流
无论你是在设计新系统还是审查现有系统,都使用此工作流。按顺序推进各阶段;每个阶段都有退出标准。明确说明假设;如果领域不清楚,请先询问,不要猜测。
阶段 0 — 界定范围
确认:这是一个新平台、现有平台中的新模块,还是一次评审?确认运行时/技术栈约束(默认目标是 2026 TypeScript 技术栈——请参阅 references/stack-2026.md)。除非存在硬性约束,否则默认采用一次部署(模块化单体)。
退出条件:记录范围和约束。
阶段 1 — 领域发现(DDD 战略设计)
阅读 references/ddd.md。根据业务语言识别子域,将每个子域划分为核心、支撑或通用,并找出每个子域的通用语言。不要按技术层分组。如果存在多种有界上下文解释,请一并列出——不要默默替用户做决定。
退出条件:列出候选有界上下文,并为每个上下文标明分类、用一句话说明职责以及列出关键聚合。
阶段 2 — 边界与上下文映射
绘制上下文映射:有哪些上下文、它们如何关联(客户/供应商、遵从者、开放主机服务、发布语言、共享内核、防腐层),以及哪些是核心上下文。确定状态所有权:可以使用一个数据库,但每个模块只能写入自己的表——模块边界之间不得设置外键;通过 id 引用其他上下文。保持聚合内聚(不要过度拆分事务性核心)。
退出条件:上下文映射 + 表所有权映射(一个模块对应自己的表)。
阶段 3 — 模块内部结构(按聚合扁平组织)
阅读 references/flat-by-aggregate.md。在每个模块内部,按聚合而非技术层组织:1 个业务概念 = 1 个文件夹;技术层通过文件后缀表示(.entity.ts、.service.ts、.controller.ts)。层级深度保持 ≤ 2(扁平)或 ≤ 3(按子域组织)。整洁架构的依赖规则仍然适用(表示层 → 应用层 → 领域层 ← 基础设施层)——只是通过后缀和共置来体现,而非通过分层文件夹。使用 6 项标准测试来决定采用扁平结构还是按子域组织;默认采用扁平结构。
退出条件:每个模块的文件夹布局,以及扁平结构与按子域组织的决策和理由。
阶段 4 — 通信与防腐层
阅读 references/acl-and-communication.md。每个外部系统都必须通过端口 + 适配器(ACL)接入——包括由其他团队负责的内部服务。领域使用自身的语言定义端口;适配器负责转换外部模型的输入和输出。内部模块之间:仅在聚合内部同步通信(一个 ACID 事务);跨模块通过事务发件箱传递事件,并使用幂等消费者。当用户体验需要服务器向客户端推送实时更新时,添加 SSE。
退出条件:端口 + 适配器列表;领域事件列表,采用 module.aggregate.action 命名;同步与异步决策。
阶段 5 — 弹性
阅读 references/resilience.md。为每个外部/服务间调用添加保护:超时 → 熔断器 → 重试(有上限的指数退避 + 完全抖动)。仅重试幂等操作(写入操作必须要求幂等键)。将重试限制在预算内(约占流量的 10%),根据滑动窗口错误率触发熔断器,并为每个熔断器指定具名降级方案。只有当长时间运行的多步骤流程必须在重启后继续时,才添加持久化执行机制。
退出条件:为每个适配器制定弹性策略,并为写入操作设置幂等键。
阶段 6 — 技术栈与演进
阅读 references/stack-2026.md。选择具体技术栈并说明权衡(运行时、API 风格、缓存、实时传输)。然后说明演进路径:阶段 1(模块化单体 + 清晰边界,并已设置事件/发件箱)是当前状态;只有当某个模块自身的指标证明有必要时,才将其拆分为独立应用/数据库。
退出条件:技术栈表 + 演进说明。
阶段 7 — 编写架构文档(HTML)
制作一份精致、独立的 HTML 架构文档,并配上优雅的手绘风格 SVG 图表。阅读 references/architecture-doc.md,并从 assets/architecture-template.html 开始:复制模板,保持其 CSS 和视觉系统不变,替换占位内容。构建标准章节(概览、领域、原则、单体映射图、限界上下文、ACL、通信、从前端到后端、模块、弹性、实时性、演进、技术栈),并按顺序为图表编号(“图表 N — …”)。保持视觉风格:配色、Lato 和 JetBrains Mono 字体、圆角矩形、箭头标记、柔和渐变和斜体说明文字。输出为一个可直接在浏览器中打开的 HTML 文件,无需构建步骤。
验收标准:一个独立的 HTML 文件,图表风格一致,页内导航可正常使用。
决策规则(速查表)
- 子域类别: 竞争优势 → 核心;业务特定但不具差异化 → 支撑;由你使用、已解决的问题 → 通用。
- 战术建模强度: 核心领域使用完整建模(丰富的聚合、值对象、不变量、事件);支撑领域使用中等强度;通用领域尽量精简(在没有不变量的地方强行丰富建模属于过度设计)。详见
references/ddd.md。 - 扁平结构还是按子域划分: 默认采用扁平结构(深度为 2)。仅当 6 项标准中有 4 项或以上符合时,才按子域划分(深度为 3):不同的角色、授权、执行模型、扩展能力、部署、故障隔离。详见
references/flat-by-aggregate.md。 - 同步还是事件: 同一聚合内采用同步方式(原子性很重要);跨模块采用 outbox 传递事件(可容忍最终一致性)。
- 持久化执行: 仅在流程长时间运行、包含多个步骤且必须支持恢复时添加——不要用于普通请求。
硬性规则(不可妥协)
- 每个模块只能写入自己的表;跨上下文链接通过 id 建立,并在代码中验证(
enforce-module-boundaries)。 - 禁止直接跨模块导入——通过 facade/contract 或事件通信。
- 每个外部系统都必须置于 port + ACL 之后——供应商模型不得泄漏到领域中。
- 仅重试幂等操作;写入操作必须携带幂等键。
- 模块化原则(P1–P10)优先于结构原则(P11–P19)。 如果将代码放在一起会导致跨模块实体导入,就使用 facade + DTO;如果拆分聚合会破坏事务,就将其保留在一起。
自动化检查
将原则落实为可执行检查,而不是依赖评审。请在 CI 中和合并前运行以下脚本(均为零依赖的 Node ESM 脚本;传入 libs/packages 根目录,或让脚本自动检测):
node scripts/validate-structure.mjs [root]— 强制检查按聚合扁平组织原则(P11–P17):不得有技术分层文件夹、不得有单文件文件夹(__test__/除外)、深度 ≤ 3、聚合内不得有 README。node scripts/validate-boundaries.mjs [root]— 强制检查模块边界(P1、P3、P8):不得有深层跨模块导入(仅可通过 barrel/facade 导入)、不得有重复或未加前缀的实体名称、不得有跨上下文关系。
出现违规时,这两个脚本都会以非零状态码退出,并打印违规路径。结构检查失败应视为阻断项;团队采纳约定后,边界检查结果也应视为阻断项。
示例
示例 1:设计一个新平台
用户说:“设计一个面向客户 ERP 的应付账款平台架构。” 操作:
- 阶段 1 — 发现子域;进行分类(例如,应付账款和运营属于核心子域;文档、审计和游戏化属于支撑子域;身份和通知属于通用子域)。
- 阶段 2 — 绘制上下文映射图 + 采用单数据库,并明确每个模块对其表的所有权。
- 阶段 3 — 按模块采用按聚合划分的扁平布局。
- 阶段 4 — 将 ERP、工单系统和存储置于端口 + ACL 后;通过 outbox 传递事件;为操作员队列使用 SSE。
- 阶段 5 — 在 ERP 适配器上制定弹性策略(幂等键 = payment id)。
- 阶段 6 — 选择 2026 技术栈 + 制定演进说明(当前只部署一个应用)。 结果:上下文映射图、模块布局、端口/适配器列表、弹性策略以及技术栈 + 演进计划——每项都有相应参考资料作为依据。
示例 2:组织一个模块
用户说:“如何组织 billing 模块?”
操作:阅读 references/flat-by-aggregate.md;提出 billing/subscription/、billing/invoice/、billing/payment/ 目录,文件与 __test__/ 放在一起;执行 6 项标准测试(billing = 扁平布局)。结果:一个扁平的文件夹树及其设计依据,并通过后缀保留依赖规则。
示例 3:与供应商解耦
用户说:“我不想被 OMIE 绑定。”
操作:阅读 references/acl-and-communication.md;使用领域语言定义 ErpLedgerPort;实现 OmieAdapter;在边界处转换 OMIE 模型;说明更换 ERP 只需更换适配器。结果:一个端口接口 + 适配器方案;领域层绝不导入供应商类型。
反模式 / 危险信号
- ❌ 从第一天起就采用微服务或多个数据库(“感觉规模很大”不是理由)。
- ❌ 在模块中使用技术分层目录(
core/service/、http/controller/、persistence/entity/)——这是按聚合划分的扁平布局所要取代的旧模式。 - ❌ 一个模块读取或写入另一个模块的表。
- ❌ 供应商 SDK 类型渗入领域层(没有 ACL)。
- ❌ 重试非幂等写入;重试时不采用退避 + 抖动;重试不设预算。
- ❌ 将内聚的事务型核心拆分成由事件耦合的片段。
- ❌ 对没有不变量的通用子域强行采用丰富的战术 DDD。
参考指南
| 加载此文件 | 适用场景 |
|---|---|
references/principles.md | 需要准确的原则文本,或需要解决结构与模块化之间的冲突。 |
references/ddd.md | 阶段 1–2:对子域分类、绘制上下文映射图、决定战术设计的应用深度。 |
references/flat-by-aggregate.md | 阶段 3:布局模块;选择扁平布局还是子域布局;脚手架;门面;测试。 |
references/acl-and-communication.md | 阶段 4:端口/适配器/ACL、事件 + outbox、SSE。 |
references/resilience.md | 阶段 5:退避/抖动、熔断器、幂等性、舱壁、持久化执行。 |
references/stack-2026.md | 阶段 0/6:具体的技术栈选择及权衡。 |
references/architecture-doc.md + assets/architecture-template.html | 阶段 7:生成 HTML 架构文档及其图表。 |
scripts/validate-structure.mjs、scripts/validate-boundaries.mjs | 验证:在 CI 中或合并前强制检查结构和模块边界。 |