mcpField
M
modular-design-principles

modular-design-principles

github.com/tech-leads-club开发7.1k182 次安装3 天前更新
代码仓库

关于 modular-design-principles

用于分析代码库中模块结构与边界的框架无关技能,提供设计原则、审查信号,以及创建、拆分或合并模块的工作流程。

主要功能

  1. 01十项模块化设计原则
  2. 02模块边界与所有权指导
  3. 03有界上下文工作流程
  4. 04拆分或合并模块的判断标准
  5. 05架构合规审查清单

适用场景

  1. 01审查现有代码库的模块边界
  2. 02规划新的有界上下文
  3. 03评估是否拆分或合并模块
  4. 04审计耦合与所有权风险

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/tech-leads-club/agent-skills --skill modular-design-principles

安装后在 Claude Code 中输入/modular-design-principles确认已加载。

附带文件references/principles.md

详细介绍

模块化设计原则

在任何代码库中推理结构和边界时,请使用此技能。它有意避免提及框架名称、文件夹约定和工具;请根据本地技术栈应用这些原则。

加载内容

任务位置
原则表 + 违规情况 + 工作流(此文件)SKILL.md
各项原则的定义、Agent 规则、抽象示例references/principles.md

分层思维模型

  • 组合根(应用程序、主机、运行器):将模块连接起来;保持编排精简。
  • 模块 / 限界上下文:行为和数据所有权内聚的单元;每个单元都应能独立理解和测试。
  • 共享内核(谨慎使用):仅包含稳定且真正横切的概念;避免将其变成“所有人都需要的一切”的大杂烩。

代码在物理上如何布局(单仓库、多仓库、包、库)属于交付选择,而非模块化的定义。以下原则仍然适用。


十项原则

#原则意图
1边界定义明确提供精简、稳定的公共接口;其他内容均为内部实现。使用方依赖契约,而非内部实现。
2可组合性模块可以单独使用,也可以组合使用,无需了解彼此内部实现的特殊知识。
3独立性边界之间不存在隐藏的共享可变状态;每个模块都应可独立测试(在边界处使用伪对象或测试替身)。
4独立扩展在需要时,可以针对每个模块调整资源(计算、存储、速率限制、批次大小),而无需重写其他模块。
5显式通信模块间交互通过有文档说明的契约(API、事件、消息、共享类型)进行,而非依赖偶然形成的耦合。
6可替换性对其他模块的依赖通过接口或协议表达,因此实现可以更换。
7部署独立性除非架构明确规定,否则模块不应假设它们共享进程、主机或发布节奏。
8状态隔离每个模块都拥有自己的持久化状态和命名;不同边界之间不得悄然共享同一逻辑数据存储,也不得使用含义不明的全局名称。
9可观测性每个模块都可以独立诊断:日志、指标、追踪、健康状态均可归因于发出它们的单元。
10故障独立性通过超时、舱壁隔离、断路器、幂等性等机制限制故障范围,避免一个模块发生故障后盲目级联。

原则 8 往往最难落实:数据或名称的所有权不明确,是集成中常见的“原本能用,直到失灵”的问题来源。

如需了解详细内容(每项原则的 Agent 规则和抽象示例),请加载 references/principles.md。


典型违规情形(抽象描述)

  1. 概念冲突 — 不同模块中的不同事物使用相同名称或架构,或者重复的“全局”定义随着时间推移逐渐不一致。
  2. 越界访问持久化存储 — 某个模块未通过约定的契约,直接读取或写入另一个模块的表、存储桶或文档。
  3. 集中式数据所有权 — 单一持久化层注册并暴露所有模块的所有存储,助长隐式耦合。
  4. 边缘层承载逻辑 — 将业务规则放在传输适配器(HTTP 处理程序、UI、CLI)中,而不是领域层或应用层代码中。
  5. 边缘层直接访问存储 — 适配器依赖底层持久化 API,而不是用例或应用服务。
  6. 事务范围不明 — 写入跨越边界,却没有明确的事务所有权和故障语义。
  7. 导出内容泄漏 — 将仓储、内部服务或实现类型暴露为模块的公共 API。
  8. 过于臃肿的门面 — “公共”入口包含查询、映射或策略逻辑,而不是将其委托给模块内部的正确层。

创建限界上下文(工作流)

在引入系统中新的内聚领域(全新模块或提取出的领域)时使用。

  1. 范围和语言 — 为上下文命名;列出核心名词和动词(统一语言)。避免含糊且与其他上下文冲突的名称。
  2. 职责 — 哪些决策只能在此处进行?哪些内容明确不在范围内?
  3. 状态所有权 — 此上下文中的哪些事实具有权威性?从概念上说,它们存储在哪里(即使尚未决定存储技术)?
  4. 公共契约 — 其他上下文可以使用的操作和/或事件。有意对契约进行版本管理或演进。
  5. 集成 — 对每个相邻上下文,选择同步调用、异步消息、共享读取模型或批量同步。记录一致性(即时、最终一致)和故障行为。
  6. 不变量和生命周期 — 此边界内必须始终满足什么条件?什么操作会启动/完成一个生命周期?
  7. 隔离检查 — 是否可以在不启动无关上下文的情况下测试核心行为(在端口处使用伪实现)?
  8. 可观测性 — 如何使用清晰的标识符,追踪请求或作业经过此上下文的过程?

跨模块交互(设计期间):优先采用最精简的契约;为异步交互定义超时、重试和幂等性;不要为图方便而“临时”直接访问其他模块的存储。


何时拆分或合并

**默认原则:**在实际问题出现之前,减少边界——“保持扁平通常更好”,不要过早拆分。拆分会增加协调、版本管理和运维成本。

六项标准测试(多项符合时倾向于拆分)
#标准问题
1语言子领域是否使用不同的词汇,或者对同一个词有相互冲突的定义?
2变化速率各部分是否以不同的节奏变化,或因互不相关的原因而变化(大多数编辑只涉及其中一方)?
3规模/SLO各部分是否需要不同的吞吐量、延迟或可用性目标?
4一致性它们是否需要不同的事务边界(无法干净地共享一个原子写入模型)?
5所有权不同的团队或明确的所有权划分是否有助于减少冲突和反复评审?
6痛点信号是否存在可观测的集成痛点:连锁影响、对变更的顾虑、Bug 归属不清?

内聚性/耦合(定性)。倾向于让模块内部具有高内聚性,模块之间保持低且明确的耦合。如果唯一的动机只是“文件变大了”或“文件夹看起来不够美观”,就合并或暂缓。

何时合并,或暂不拆分
  • 边界是人为划分的(使用相同语言、生命周期相同、频繁相互调用)。
  • 拆分会重复逻辑或数据,且没有明确的单一写入方规则。
  • 团队尚未准备好为额外单元负责其契约、版本管理和运维。
决策提示(简短)
  • 拆分带来的意外耦合减少,是否大于它增加的协调成本?
  • 是否存在自然的通用语言边界,还是只有技术上的分界?

有界上下文内部的子单元

有时,外部边界是合理的,但其内部还包含一些命名子区域(子域、功能区域)。这些原则仍适用于上下文内部。

所有权

  • 在可能的情况下,每个子单元都应负责自己那部分模型和持久化相关内容——避免使用一个庞大的注册层,在同一处连接所有子单元的所有存储和仓库(这会助长越界访问和隐性耦合)。

子单元间访问

  • 优先使用内部应用 API或精简的内部门面(同一上下文内、显式定义的接口),而不是让各子单元直接导入彼此的存储类型。
  • 对于异步流程,优先使用信息更丰富的载荷,这样处理程序就不必在子单元间频繁往返,以获取本可以随事件/命令一起传递的数据。

上下文内的共享内核

  • 少量稳定的共享类型或枚举可以放在范围精简的共享区域中——但要避免不断膨胀的“utils”集合,最后成为真正的耦合点。

反模式: 一个统一的“persistence”或“data”子模块,成为唯一一个了解所有子单元所有表/文档的地方,其他模块再通过它访问数据——这与跨上下文越界访问的问题相同,只不过发生在边界内部。


架构合规检查

用于评审或审计,不预设存在相关工具。将这些项目视为信号,而非证明——请与领域专家确认。

依赖和 API 信号
  • 入向与出向: 依赖应符合所选架构(例如,领域位于中心,适配器位于外围)。基础设施类型向内泄漏到核心逻辑中,是一种异味。
  • 公共接口: 是否可以列出导出的操作/事件/类型,而不包含存储或内部服务?如果不能,说明边界存在泄漏。
  • 相邻模块导入: 在模块 B中使用了来自模块 A的类型或客户端——它们只是契约类型,还是持久化/实现类型?
持久化和数据信号
  • 越界访问: 在约定契约之外引用另一个上下文的物理数据(架构、集合、存储桶名称)。
  • 命名冲突: 不同事物使用相同的逻辑名称,或共用全局 ID,却没有记录映射规则。
  • 事务所有权: 跨上下文写入,却没有明确的 saga、outbox 或单一所有者规则,也没有记录失败场景。
运维信号
  • 问题归属: 出现“我们不知道哪个模块负责这条记录/这种行为”的事故 → 所有权或可观测性存在缺口。
  • 级联故障: 一个依赖的变慢或故障导致无关的用户流程也中断 → 缺少超时、隔离舱或降级路径。
严重程度参考(用于报告)
级别含义
P0存在数据损坏风险、安全边界违规,或跨上下文持久化且没有契约
P1所有权不明确、公共 API 存在泄漏、边界缺少故障语义
P2可观测性缺口、可组合性异味、会加剧未来耦合的技术债

成熟度说明: 除非团队定义了数值门槛,否则评分是定性的。关注趋势:随着时间推移,P0/P1 问题减少,契约更加清晰。


快速检查清单(提出结构方案前)

  • 公共 API 精简;不要随意导出内部实现。
  • 每个模块的命名和存储归属都明确无歧义。
  • 未经明确约定,不得绕过模块边界进行持久化操作。
  • 业务规则应置于清晰的应用层/领域层中,而不能只放在适配器里。
  • 跨模块调用应明确规定失败和超时行为。
  • 无需深入翻查代码,就能通过可观测性回答“哪个模块出了问题,原因是什么?”。
  • 如果上下文中包含子单元:每个单元都应有明确的归属;持久化层不应成为“一站式注册所有内容”的大杂烩。

与特定技术栈技能的关系

当项目有具体约定(框架模块、DI、仓储模式、文件夹布局、代码生成、CI 检查)时,优先参考相关文档了解如何实现。使用本技能了解边界为何存在,以及良好的模块化设计应优化什么——这样,特定技术栈的建议才能与相同原则保持一致。

评论

支持 Markdown