AIHero
    22 / 25为真正的工程师打造的 AI 技能 · 9 分钟阅读

    /codebase-design 技能

    设计深模块的词汇表。

    Matt Pocock
    Matt Pocock
    下一页

    安装此技能

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

    然后输入 /codebase-design 来调用它。

    本页内容

    它的作用

    codebase-design 定下你设计模块时使用的词汇: module, interface, depth, seam, adapter, leverage, locality。它精确地定义每一个词汇,禁用松散的替代词(「component」「service」「API」「boundary」),并陈述由此得出的几条原则。

    它是一个参考,不是一个流程。没有可运行的循环、不产出任何产物、没有问你问题的检查点。每个涉及设计的其他技能都借用它的词汇;单独使用时,它给你语言然后就停。这是调用它之前要知道的事,因为一个没有流程、没有停止规则的技能,如果你把 会话 盯着它说「开始」——见下面的问题。

    何时使用

    输入 /codebase-design,或当设计任务合适时智能体会自动调用它。

    当你已经知道要重新设计哪段代码、需要思考它的形状时使用它:接缝放在哪、接口能变得多小、抽取是否值回票价。它也是你解决「某个词是什么意思」争论时使用的东西。

    有几个技能与它相近。你想要哪个取决于实际的问题是什么:

    问题技能
    单个模块的形状——它的接口、接缝、深度codebase-design
    这个 领域的词汇 ——「account」有三种含义,两个人对「cancellation」的理解各不相同domain-modeling
    你还不知道 which 要重新设计的模块improve-codebase-architecture ——找到候选方案的调查
    你想要设计被争辩,而不只是被命名追问审视
    有具体行为要构建,而且你想要经得起重构的测试tdd

    词汇表

    词汇表就是技能。每个术语都相对其他术语定义,每个都带它取代的词。

    术语它意味着什么不要说
    模块任何有接口和实现的东西。刻意与规模无关——一个函数、一个类、一个包、一个横跨多层的切片。unit、component、service
    接口调用者正确使用它必须知道的一切:类型签名,以及不变量、顺序约束、错误模式、所需配置、性能特征。API、签名
    深度接口处的杠杆——调用者或测试每学习一单位接口,能驾驭多少行为。 :小接口背后藏着大量行为。 :接口几乎和实现一样复杂。
    接缝Michael Feathers 的术语:一个你可以不在此处编辑就能改变行为的地方。它就是 location 是一个接口的,而放在哪里是它自己的决策,与背后放什么分开。boundary
    适配器在接缝处满足接口的具体事物。命名的是角色而非实体——内存中的 fake 和 Postgres 仓库都是适配器。
    杠杆调用者从深度得到什么:每学习一单位接口,获得更多能力。
    局部性维护者从深度得到什么:改动、bug 和验证集中在一处。修一次,处处修好。

    深度被刻意地 not 定义为实现行数与接口行数之比,这正是 Ousterhout 自己的定义。该指标会奖励注水的实现。因此改用「深度即杠杆」的衡量方式。

    四条原则

    • 深度是接口的属性,不是实现的属性。 深模块内部可以由小而可替换的部件构建。它们只是不会暴露给调用者。一个模块可以有内部测试使用的内部接缝,以及接口处的一个外部接缝。
    • 删除测试。 想象删除这个模块。如果复杂性随之消失,它就是一个传话筒。如果它重新出现在 N 个调用者身上,它就是在值回票价。
    • 接口就是测试表面。 调用者和测试跨越同一个接缝。如果你想测试 past 接口,模块就是错误的形状。
    • 一个适配器意味着假设性接缝。两个适配器意味着真实接缝。 在真正有东西跨越它变化之前,不要切接缝。只有一个适配器的接缝只是间接层。

    两个辅助文件更进一步,技能按需读取它们,而不是预先读取。 DEEPENING.md 对候选方案的依赖进行分类——进程内、可本地替换、远程但自有、真外部——因为类别决定了深化后的模块如何跨越接缝进行测试。 DESIGN-IT-TWICE.md 启动并行 sub-agents 为同一个模块产出三个或更多截然不同的接口,然后从深度、局部性和接缝位置比较它们。

    常见问题

    在 TypeScript 中到底怎么构建深模块?

    这是关于该技能被问最多的问题,而技能没有回答它。它定义了深模块 is;它没有说明如何阻止一个游离的 import 越过接口。 Issue #458 说得直白:「假设我们对接口满意,它隐藏了细节等等。但怎么强制执行?我想没有 lint 或明确的护栏,人类和 LLM 都会随着时间把它弄得一团糟。」Matt 在那条线索里的回答是三个选项:把它包进类或 IIFE,接受类变得巨大;做成 monorepo 里的包,接受 monorepo 工具链;或者用像 dependency-cruiser 来禁止绕过接口的导入。他另外称 Effect 是最好的机制,dependency-cruiser 第二好。有一个 setup-ts-deep-modules 仓库 in-progress/ 桶里放着一个 src/packages/<name>/index.ts 约定,但它是测试渠道的技能,没有文档页,也没有随附的 lint 规则。

    我让一个会话指向它,它烧掉了 10 万 tokens 重新设计我从未要求过的东西。

    已知,并已作为 issue #449。该技能由模型自动调用,自称是词汇表,但其中没有任何东西能硬性阻止智能体把它当作可运行流程。当被告知「在 /codebase-design 中继续并推进未决决策」时,一个智能体伸手去抓它能找到的最具行动形态的内容—— DESIGN-IT-TWICE.md ——重新探索了上个会话已绘制过的代码,跑了很远才问任何问题。驱动技能拥有的护栏(检查点、一次一个问题、不自动推进)这里一个都没有,因为参考技能本来就没有。变通方案是点名一个驱动技能,让这个技能坐在它底下: /grill-with-docs, /improve-codebase-architecture or /tdd with codebase-design 作为词汇表。该 issue 仍然开放。

    原来的 design-an-interface 去哪了?有没有 /interface-design 技能?

    design-an-interface 被移除并并入这个技能。没有损失:它的「设计两次」技巧——源自 Ousterhout 的并行子智能体生成截然不同设计——在这里以 DESIGN-IT-TWICE.md。另外,有几个人要求提供一个专门的 /interface-design 为深模块/薄接口哲学准备的技能;那种哲学已经住在这里,没有计划单独的技能。如果你来找这两个名字中的任何一个,这就是那一页。

    这不就是文件结构约定吗——文件夹、barrel 文件、功能切片?

    不,而且该技能在反复的反对声中坚持了这条线。 Issue #95 提议将形式化的分形树文件结构作为深模块的具体实现;答复是两者正交——「深模块关乎接口的设计,并通过严格接口访问,无论文件系统长什么样。用这种方法完全可能拥有浅模块。」同样的问题出现在 #458:「我觉得你可能把模块概念与文件系统绑得太紧。文件系统当然可以是有用的模块形状提示,但构建深模块不需要使用文件系统。」词汇表把 module 刻意与规模无关。

    是否 tdd 真的会使用这套词汇吗?

    现在可以了。很长一段时间它都不能。以前住在 tdd 在 v1.0 中被移除,让位于这个共享技能,但取代它们的指针从未被添加——所以 tdd 为自己定义「接缝」而没有引用任何东西。缺口已补上:指针现在在技能里,当「接口的形状」而非「测试」成为开放问题时就会用到。 tdd 仍然拥有「接缝」一词,作为你 test 处;这个技能拥有它背后的模块形状。

    「设计两次」模式在 Claude Code 之外有效吗?

    不能干净地做到。 DESIGN-IT-TWICE.md 说「使用 Agent 工具并行派生 3+ 个子智能体」,这是 Claude Code 的 tool 以 Claude Code 的名字。该仓库为其他 harnesses,包括 Codex,而那些可能不以那个名字暴露任何东西——所以并行设计阶段的移植性不如技能元数据所暗示的。已在 issue #564,打开着。

    我能把自定义概念加进词汇表吗——连接性、模块秘密, 渐进披露?

    人们提出过正是这些。 Issue #180 把 Parnas 的模块秘密和 Page-Jones 的连接性作为命名层加进来,用于 what 正跨越接缝泄漏,并附有可用的 diff; issue #303 proposes 渐进披露 在实现内部,所以公共接口处很深的模块,底下也不是一块毫无差别的板。两者都开放且未合并。随附的词汇表刻意保持很小,它保持小的原因在技能自身里写明了:语言一致才是全部意义,一个没人一致使用的术语比没有术语更糟。

    做到以下就算成功

    • 设计对话不再产出「component」「service」「boundary」这些词,开始产出「module」「interface」「seam」。
    • 任何人都能指着提议的抽取,毫不含糊地说它是否通过删除测试。
    • 提议的接缝会附带命名第二个适配器,而不只是第一个。
    • 接口的讨论涵盖不变量、顺序和错误模式——不仅仅是类型签名。
    • 调用它不会启动会话。如果智能体开始读取文件并借 /codebase-design 单独使用时,它把参考误当成了驱动者。

    在流程中的位置

    codebase-design 是一个 随时可调用的独立技能,是工程技能之下的词汇层,而不是任何链上的一步。它最近的邻居是 domain-modeling,与 问题领域的用词,而不是模块的形状——两者通常需要一起考虑,因为给深模块起好名字两者都需要。 improve-codebase-architecture 是另一个:它调查代码库寻找深化候选,并把每一个都用这套词汇写出来,所以它找到模块,而这个技能是你设计它的工作台。当你不确定哪个技能或流程合适时, ask-matt 为你指路。

    技能操作

    安装技能

    Live Skills.sh install count
    npx skills@latest add mattpocock/skills

    安装整套技能,然后在智能体中输入 /codebase-design 来调用它。

    用以下命令更新: npx skills updateSkills.sh