用途
codebase-design 是一套用于设计“深模块”(deep modules)的共享词汇与原则。它适用于任何正在设计或重构代码的场合,目标是:为调用方提供杠杆(leverage),为维护者提供局部性(locality),并让所有人获得可测试性。
核心概念
该技能定义了一组用于架构推理的术语:
- Module(模块):任何具有接口和实现的东西。刻意与规模无关,可以是函数、类、包或跨层切片。避免使用 unit、component、service 等词。
- Interface(接口):调用方正确使用模块所需知道的一切,包括类型签名、不变量、顺序约束、错误模式、必需配置和性能特征。避免使用 API、signature,因为它们仅指类型层面的表面。
- Implementation(实现):模块内部、其代码主体。与 Adapter 不同:一个东西可以是小适配器配大实现(如 Postgres 仓库),也可以是大适配器配小实现(如内存假实现)。当接缝是主题时用 adapter,否则用 implementation。
- Depth(深度):接口处的杠杆。调用方(或测试)每学习一单位接口所能行使的行为量。大量行为位于小接口之后即为深,接口几乎与实现一样复杂即为浅。
- Seam(接缝):Michael Feathers 提出的概念,指可以在不编辑该处的情况下改变行为的地方;模块接口所在的位置。接缝放在哪里是独立的设计决策。避免使用 boundary,因其与 DDD 的限界上下文混淆。
- Adapter(适配器):在接缝处满足接口的具体事物。描述角色(填充什么槽位),而非实质(内部是什么)。
- Leverage(杠杆):调用方从深度中获得的东西。每学习一单位接口获得更多能力。一个实现可在 N 个调用点和 M 个测试中得到回报。
- Locality(局部性):维护者从深度中获得的东西。变更、缺陷、知识和验证集中在一处,而非分散到调用方。修一次,处处修复。
深模块与浅模块
深模块 = 小接口 + 大量实现:少量方法、简单参数,复杂逻辑被隐藏。
浅模块 = 大接口 + 少量实现(应避免):大量方法、复杂参数,实现只是透传。
设计接口时自问:能否减少方法数量?能否简化参数?能否在内部隐藏更多复杂性?
原则
- 深度是接口的属性,而非实现的属性。深模块内部可以由小的、可 mock、可替换的部分组成,只是它们不属于接口。模块可以有内部接缝(对其实现私有,供自身测试使用)以及接口处的外部接缝。
- 删除测试:想象删除该模块。如果复杂性消失,它只是透传;如果复杂性在 N 个调用方处重新出现,它就在发挥价值。
- 接口即测试面:调用方和测试跨越同一接缝。如果想测试接口之外,模块形状可能不对。
- 一个适配器意味着假设的接缝,两个适配器意味着真实的接缝。除非确实有东西在接缝处变化,否则不要引入接缝。
为可测试性而设计
良好接口让测试自然:
- 接受依赖,不要创建依赖。例如
function processOrder(order, paymentGateway) {}可测试,而内部new StripeGateway()则难以测试。 - 返回结果,不要产生副作用。例如
function calculateDiscount(cart): Discount {}可测试,而applyDiscount(cart): void直接修改 cart 则难以测试。 - 缩小接口面积。方法越少,需要的测试越少;参数越少,测试设置越简单。
关系
- 一个 Module 恰好有一个 Interface(呈现给调用方和测试的表面)。
- Depth 是 Module 的属性,相对于其 Interface 衡量。
- Seam 是 Module 的 Interface 所在之处。
- Adapter 位于 Seam 处并满足 Interface。
- Depth 为调用方产生 Leverage,为维护者产生 Locality。
被拒绝的框架
- 将深度视为实现行数与接口行数的比率(Ousterhout):会奖励填充实现。此处使用“深度即杠杆”。
- 将“Interface”视为 TypeScript 的 interface 关键字或类的公共方法:太窄;此处的接口包括调用方必须知道的一切事实。
- “Boundary”:与 DDD 的限界上下文混淆。应说 seam 或 interface。
深入
- 给定依赖关系深化一个集群,参见 DEEPENING.md:依赖类别、接缝纪律、替换而非分层测试。
- 探索替代接口,参见 DESIGN-IT-TWICE.md:启动并行子代理,以几种截然不同的方式设计接口,然后按深度、局部性和接缝位置进行比较。
- 当所请求的接口或深化评估识别出调用方知识、隐藏实现、权衡和有用的测试接缝时完成;接受的领域变更通过 /domain-modeling 协调。
适用场景
当用户想要设计或改进模块接口、寻找深化机会、决定接缝位置,或需要一套共享词汇来讨论代码结构时使用。
限制
该技能本身不提供具体代码实现或自动化工具,而是一套概念框架和设计原则。其效果取决于使用者对现有代码库的理解和判断。关于收费、价格、平台支持等具体信息,资料中暂未提供。