技能手册
24 / 27 AI 工程技能 · 8 分钟读完 · 更新于 2026 年 8 月 24 日

/codebase-design 技能

设计深度模块所用的词汇。

下一篇

安装此技能

npx skills@latest add mattpocock/skills --skill=codebase-design

然后在你的编码 agent 里输入 /codebase-design 。

本页目录

它做什么

codebase-design 固定你设计一个模块时所用的词:模块(module)、接口(interface)、深度(depth)、接缝(seam)、适配器(adapter)、杠杆(leverage)、局部性(locality)。它精确地定义每一个词,禁用那些松散的替代说法(“组件”、“服务”、“API”、“边界”),并陈述由这些词得出的少数几条原则。

它是一份参考(reference),不是一套流程。它不跑任何循环,不产出任何产物,也从不停下来问你一个问题。其他每一个涉及设计的技能都使用它的词汇。单独运行它时,它只给你这些词,然后就停下。调用它之前要知道这一点。如果你把一场会话(session)对准一个没有流程、也没有停止规则的技能,然后说「开始」,agent 就会发明一套流程。下面这些问题展示了那是什么样子。

什么时候用它

输入 /codebase-design,或者当一个设计任务匹配时由 agent 自动去拿它。

当你已经知道自己在重新设计哪段代码、需要思考它的形状时,就用它:接缝放在哪里,接口能小到什么程度,一次提取是否把复杂度从调用方(caller)那里移走了。也用它来裁定一场关于某个设计词含义的争论。

有几个技能与它接近。按你手头的问题来选:

问题技能
一个模块的形状:它的接口、它的接缝、它的深度codebase-design
领域的词:「account」有三层意思,两个人对「cancellation」的理解不同domain-modeling
你还不知道该重新设计哪个模块improve-codebase-architecture(普查,负责找出候选项(candidate))
你想让设计被辩驳,而不只是被命名grilling
有一个具体行为要构建,你想要能扛过重构的测试tdd

词汇

词汇表(glossary)就是这个技能。技能用其他词定义每一个词,并给每一个词配上它所取代的那个词。

术语含义不要这样说
模块任何有接口和实现的东西。刻意不限定规模:一个函数、一个类、一个包、一个跨层的切片。单元、组件、服务
接口调用方正确使用它必须知道的一切:类型签名,加上不变量(invariants)、顺序约束、错误模式、必需的配置、性能特征。API、签名
深度接口处的杠杆:调用方或测试每学习一单位接口,能触达多少行为。深:小接口后面藏着大量行为。浅:接口几乎和实现一样复杂。无
接缝Michael Feathers 的术语:一个你可以在不修改该处代码的情况下改变行为的地方。它是接口的位置,而把它放在哪里本身就是一项决定,与它后面放什么分开。边界
适配器在接缝处满足某个接口的具体事物。它命名的是一种角色,不是一类东西:一个内存中的假实现和 Postgres 仓库都是适配器。无
杠杆调用方从深度中得到的东西:每学习一单位接口,换来更多能力。无
局部性维护者从深度中得到的东西:改动、bug 和验证都留在一处,所以一次修复覆盖每一个调用方。无

这个技能不把深度定义成实现行数与接口行数的比值,那是 Ousterhout 自己的定义。那个指标会奖励往实现里灌水,所以这个技能改用「深度即杠杆」。

四条原则

  • 深度是接口的属性,不是实现的属性。 一个深度模块(deep module)内部可以由小的、可替换的部件搭成。调用方只是看不到它们。一个模块可以有供自己测试使用的内部接缝,以及接口处的一道外部接缝。
  • 删除测试(deletion test)。 想象把这个模块删掉。如果复杂度消失了,这个模块就是直通的(pass-through)。如果复杂度在 N 个调用方那里重新出现,这个模块就在隐藏真正的复杂度。
  • 接口就是测试面。 调用方和测试穿过同一道接缝。如果你想绕过接口去测试,这个模块的形状就错了。
  • 一个适配器意味着假想的接缝。两个适配器才意味着真实的接缝。 在有东西跨过接缝变化之前,不要切出接缝。单适配器的接缝只是间接层。

两个辅助文件走得更远,技能按需读取它们,而不是一上来就读。DEEPENING.md 把一个候选项的依赖分成四类(进程内、可本地替换、远程但自有、真正外部),因为类别决定你如何跨接缝测试深化(deepening)后的模块。DESIGN-IT-TWICE.md 启动并行的子代理(subagent),为同一个模块产出三个或更多截然不同的接口,然后按深度、局部性和接缝位置比较它们。

常见问题

我到底该怎么在 TypeScript 里构建一个深度模块?

这是关于这个技能被问得最多的问题,而这个技能并不回答它。它定义深度模块是什么;它对如何阻止一个走偏的 import 伸过接口只字未提。Issue #458 把这一点说得很直白:「假设我们对接口满意,它隐藏了细节,等等。但我们怎么强制执行它?我认为没有 lint 检查或明确的护栏,人类和 LLM 都会随着时间把它弄乱。」那个讨论串里的答案给了三个选项:把它包进一个类或 IIFE,并接受这个类会变得巨大;把它做成 monorepo 里的一个包,并接受 monorepo 工具链;或者用一个像 dependency-cruiser 这样的 linter 来禁止绕过接口的 import。在这些机制里,Effect 最好,dependency-cruiser 次之。仓库的 in-progress/ 桶里有一个 setup-ts-deep-modules 技能,它确立 src/packages/<name>/index.ts 的约定,但它是一个 beta 通道技能,没有文档页,也不附带任何 lint 规则。

我把一场会话对准它,它烧了 100k token 去重新设计我从来没问过的东西。

这是一个已知问题,记录为 issue #449。这个技能是模型调用(model-invoked)的,并把自己描述成词汇,但其中没有任何东西硬性阻止 agent 把它当作一套可运行的流程。被告知「在 /codebase-design 里继续,并推进那些悬而未决的决定」后,一个 agent 挑中了技能里最接近流程的那部分:DESIGN-IT-TWICE.md 里的并行子代理。它重新探索了上一场会话已经摸清的代码,并且工作了很长时间才开始问任何东西。这个技能没有驱动者(driver)所拥有的任何护栏(检查点、一次一个问题、不自动推进),因为它是一份参考。变通办法是调用一个驱动技能(/grill-with-docs、/improve-codebase-architecture 或 /tdd),并把 codebase-design 当作它的词汇。该 issue 仍然打开。

design-an-interface 去哪了?还有,有没有一个 /interface-design 技能?

这个技能取代了 design-an-interface,并接管了它的内容。什么都没有缺失。它的「设计两次」(design-it-twice)技巧(并行的子代理产出截然不同的设计,来自 Ousterhout)作为 DESIGN-IT-TWICE.md 在这里发布。另外,有几个人要过一个专门的 /interface-design 技能来承载深度模块/薄接口哲学;这个技能已经覆盖了那套哲学,也没有计划再做一个单独技能。如果你是在找这两个名字中的任何一个,就是这一页。

这不就是一种文件结构约定吗,比如文件夹、桶文件(barrel file)、功能切片?

不是。人们已经就此反驳过很多次,而这个技能没有改变。Issue #95 提议把形式化的分形树文件结构作为深度模块的具体实现;回答是两者相互独立:「深度模块关乎接口的设计,以及通过严格的接口访问,不管文件系统长什么样。用这种做法,你似乎完全可能得到浅模块(shallow module)。」#458 里也出现了同样的说法:「我认为你可能把模块的概念和文件系统绑得太紧了。文件系统当然可以是模块形状的有用提示,但构建深度模块时没必要使用文件系统。」词汇表刻意把模块定义为不限定规模。

tdd 真的使用这套词汇吗?

现在用了,但很长时间里没有。v1.0 从 tdd 里删掉了内联的深度模块笔记,改用这份共享技能,但没有人加上一个指针来替代它们,所以 tdd 自己定义了「接缝」,什么也没有引用。现在指针在 tdd 里,当悬而未决的问题是接口的形状而不是测试时,agent 会跟随它。tdd 仍然拥有「接缝」——你测试所依赖的边界;这个技能拥有接缝后面的模块形状。

设计两次这个模式在 Claude Code 之外能工作吗?

不能干净地工作。DESIGN-IT-TWICE.md 说「使用 Agent 工具并行启动 3 个以上的子代理」,而「Agent」是一个 Claude Code 工具的名字。仓库为其他运行环境(harness)(包括 Codex)发布元数据,而那些环境可能没有同名的工具。所以并行设计阶段的可移植性,比技能的元数据所暗示的要差。Issue #564 追踪这件事,它仍然打开。

我能把自己的概念加进词汇表吗,比如 connascence、模块秘密(module secrets)、渐进式披露(progressive disclosure)?

人们提议过这些。Issue #180 把 Parnas 的模块秘密和 Page-Jones 的 connascence 加为命名层,用来描述什么在跨接缝泄漏,并附了一个可用的 diff;issue #303 提议在实现内部做渐进式披露,让一个在公共接口上很深的模块内部也有结构。两个都开着,没有合并。发布的词汇表刻意很小,技能本身给出了理由:一致的语言就是全部要点,而一个没人一致使用的术语比没有术语更糟。

它生效的标志

  • 设计对话不再产出「组件」「服务」「边界」这些词,而开始产出「模块」「接口」「接缝」。
  • 有人能指着一个提议的提取,说它是否通过删除测试,而且不打太极。
  • 一个提议的接缝会连同第二个适配器一起被点名,而不只是第一个。
  • 关于接口的讨论覆盖不变量、顺序和错误模式,而不只是类型签名。
  • 调用它不会启动一场会话。如果 agent 仅凭 /codebase-design 就开始读文件、提议重构,它就把参考误当成了驱动者。

它在体系中的位置

codebase-design 是一个随时可用的独立技能(Standalones),是工程技能底下的词汇层,而不是任何链条上的一步。它最近的邻居是 domain-modeling,那是关于问题领域的词而非模块形状的平行参考。两者通常会被一起需要,因为要给一个深度模块起好名字,两者都得有。improve-codebase-architecture 是另一个:它普查一个代码库里的深化候选项,并把每一个都用这套词汇写出来,于是它找出模块,而你用这个技能的词汇设计它。当你不确定哪个技能或哪条流程合适时,ask-matt 会为你路由。


原文:aihero.dev/skills-codebase-design