模块模式通过职责锚定、接口显式化、行为契约化三步,将隐性逻辑转化为可验证、可替换、可组合的明确契约;契约需声明输入输出、副作用、错误分类及非功能承诺,并嵌入开发流程与ci校验,支持演进式维护。

模块模式在组件化架构中不是简单地切分代码,而是通过职责锚定 + 接口显式化 + 行为契约化三步,把隐性逻辑变成可验证、可替换、可组合的明确契约。关键不在于“怎么拆”,而在于“拆完之后,谁承诺什么、谁依赖什么、变更时边界在哪”。
明确行为契约,是高内聚的前提
一个模块若没有清晰的行为契约,就只是代码堆砌。契约不是文档,而是可执行的接口定义:
- 必须声明输入参数类型、约束条件(如
id > 0)、预期副作用(如“触发缓存失效”) - 必须定义返回值语义(成功/失败含义)、错误分类(
NotFoundErrorvsPermissionDenied) - 必须标注非功能性承诺(如“响应延迟 ≤ 50ms @ p95”,“线程安全”)
例如,在用户资料模块中,UpdateProfile()接口若只写func UpdateProfile(*Profile) error,就不构成契约;加上注释或类型系统约束(如 Go 的 contract 或 TypeScript 的 interface + JSDoc),才算真正落地。
用模块模式动态抽取行为,靠的是“关注点剥离”而非功能归类
不是按“用户”“订单”“通知”分模块,而是按稳定变化维度抽离:
- 抽出纯数据操作(如
UserStore.FindByID()),它只依赖数据库抽象,不关心登录态 - 抽出状态流转逻辑(如
UserSessionManager.Login()),它依赖认证策略和会话存储,但不碰 UI 渲染 - 抽出跨域协同行为(如
UserEventBroadcaster.OnProfileUpdated()),它只发布事件,不调用其他模块
这样抽取出来的每个模块,天然具备高内聚——内部所有代码都服务于同一类变化原因(比如“数据库迁移”只影响 UserStore,不影响 LoginHandler)。
构建契约要嵌入开发流程,不能靠后期补全
- 新增模块必须先写接口定义(
.go中的 interface /.ts中的 type /.php中的 contract),再实现 - 所有对外方法需带
@contract标记(鸿蒙可用@ModuleApi,Go 可用// CONTRACT:注释配合 linter 检查) - CI 流水线强制校验:接口变更必须伴随版本号升级或兼容性说明,否则拒绝合并
- 低代码平台注册组件时,自动解析接口元数据生成配置表单(如
conditions: object→ 自动生成 JSON Schema 表单)
契约不是一成不变,而是可演进的协议
当业务需要新增字段校验,不要改旧接口,而是:
- 增加新方法
UpdateProfileV2()并标注废弃旧版 - 或扩展输入结构体,用
omitempty保持向后兼容 - 同时更新契约文档中的“兼容性矩阵”,注明哪些客户端版本支持哪些字段
真正的高内聚,来自每个模块对自己行为边界的清醒认知;真正的低耦合,来自所有交互都经由这些被共同认可、可独立验证的契约发生。











