{title="📊 页面导航"]

适用角色与上手难度

角色推荐度上手难度
🛠️ 开发★★★★★★★★☆☆
🧪 测试★★★★☆★★★☆☆
📦 产品★☆☆☆☆★★★★★

🎯 学习产出: 掌握深层模块设计词汇和原则,能设计接口小、实现深、可测试的模块

🚀 AI 能力提升: 架构设计、接口设计

codebase-design

预计阅读时间: 6 分钟

深层模块设计。设计深层模块:大量行为藏在小型接口后面,放在干净的接缝上,通过接口可测试。目标是调用者的杠杆、维护者的局部性、所有人的可测试性

概述

它是被其它技能引用的共享词汇层——设计或重构代码时就用这套语言和原则。一致的语言就是全部意义:别用"component"、"service"、"API"、"boundary"替代。

日常使用

> 帮我设计一下支付网关模块的接口
> 这个模块该不该拆?
> 这个接口怎么设计才能好测?

实战

词汇表(用词要精确)

词汇含义
模块有接口和实现的东西。刻意跨尺度:函数、类、包、跨层切片。避免:unit/component/service
接口调用者正确使用模块所需知道的一切:类型签名 + 不变量 + 顺序约束 + 错误模式 + 必需配置 + 性能特征。避免:API/signature(太窄)
实现模块内部的东西。与适配器区分:可以是小适配器大实现(Postgres repo),或大适配器小实现(内存 fake)。谈接缝时说 adapter,否则说 implementation
深度接口的杠杆:调用者每学一单位接口能行使多少行为。 = 大量行为在小接口后; = 接口和实现一样复杂
接缝(Michael Feathers)不改动此处就能改变行为的位置——模块接口所在处。接缝放哪是独立设计决策。避免:boundary(DDD 重载)
适配器在接缝上满足接口的具体东西。描述角色(占哪个槽),不是实质(里面是什么)
杠杆调用者从深度得到的东西:学一单位接口,一次实现回报 N 个调用点和 M 个测试
局部性维护者从深度得到的东西:改动、bug、知识、验证集中在一处——修一次,处处修好

深 vs 浅

深模块 = 小接口 + 大实现         浅模块 = 大接口 + 薄实现(避免)
┌─────────────────────┐      ┌─────────────────────────┐
│   Small Interface   │      │     Large Interface     │
├─────────────────────┤      ├─────────────────────────┤
│  Deep Implementation│      │  Thin Implementation    │
└─────────────────────┘      └─────────────────────────┘

设计接口时问:能减少方法数吗?能简化参数吗?能把更多复杂度藏进里面吗?

原则

  • 深度是接口的属性,不是实现的。深模块内部可以是小的、可 mock、可替换的部分——它们不是接口的一部分。模块可以有内部接缝(实现私有,自有测试用)和外部接缝(接口处)
  • 删除测试:想象删除这个模块。复杂度消失了 → 它是透传;复杂度重新散布到 N 个调用者 → 它值回票价
  • 接口即测试面:调用者和测试穿过同一个接缝。想测接口,模块形状多半错了
  • 一个适配器 = 假设的接缝;两个适配器 = 真实的接缝。没有东西真的在变化,就别引入接缝

可测试性设计

  1. 接受依赖,不创建依赖
// 可测
function processOrder(order, paymentGateway) {}

// 难测
function processOrder(order) {
  const gateway = new StripeGateway();
}
  1. 返回结果,不产生副作用
// 可测
function calculateDiscount(cart): Discount {}

// 难测
function applyDiscount(cart): void {
  cart.total -= discount;
}
  1. 小表面积:方法越少测试越少,参数越少测试设置越简单。

关系

模块有一个接口;深度是模块相对接口的属性;接缝是接口所在处;适配器在接缝上满足接口;深度产生调用者的杠杆和维护者的局部性。

被拒绝的框架

  • 深度 = 实现行数/接口行数之比(Ousterhout)——奖励注水实现。我们用"深度即杠杆"
  • "接口" = TypeScript interface 关键字或类公共方法——太窄;接口包含调用者必须知道的每个事实
  • "Boundary"——被 DDD 的 bounded context 重载。说接缝或接口

深入

  • 深化集群(给定依赖):见 DEEPENING.md——依赖分类、接缝纪律、replace-don't-layer 测试
  • 探索替代接口:见 DESIGN-IT-TWICE.md——并行派子 agent 以截然不同的方式设计接口,然后在深度、局部性、接缝位置上比较

与其它技能的关系

  • 消费者tdd(接口形状存疑时查阅)、improve-codebase-architecture(深化候选)、/implement
  • 词汇层domain-modeling 提供领域语言,本技能提供架构语言