Matt Pocock 代码库架构改进技能:让 AI 深度理解代码的艺术
Matt Pocock 代码库架构改进技能:让 AI 深度理解代码的艺术
原文:https://github.com/mattpocock/skills/tree/main/skills/engineering/improve-codebase-architecture
一、项目概述
Matt Pocock 的 skills 项目是一套面向 AI Agent 的工程技能库,其中 improve-codebase-architecture 是专门用来发现代码库架构问题并提出深度改进方案的技能。它不是简单的代码审查工具,而是一套完整的方法论——教会 AI 如何像资深架构师一样,用统一的设计词汇审视代码、发现浅层模块、并把它们"加深"为深模块。
这个技能的核心目标有两个:
- 可测试性(Testability):让代码可以通过接口进行测试,而不是依赖脆弱的内部状态
- AI 可导航性(AI Navigability):让 AI 能够清晰地理解模块的边界、接口和实现,从而更准确地修改代码
整个技能体系包含三个核心技能互相配合:
codebase-design:统一的架构设计词汇和原则improve-codebase-architecture:发现架构问题和深化机会grilling:决策树式深度推演(本文重点解析前两个)
二、统一的设计词汇:代码架构的"普通话"
这是整个技能体系最核心的设计决策——强制使用统一的设计词汇来描述代码架构,避免 AI 在分析代码时出现术语漂移。
2.1 六个核心术语
| 术语 | 含义 | 举例 |
|---|---|---|
| Module(模块) | 有接口和实现的任何代码单元,可以是函数、类、包或跨层切片 | OrderHandler、PricingClient |
| Interface(接口) | 调用者正确使用模块需要知道的一切:类型签名、不变量、约束、错误模式、配置要求、性能特征 | 调用方需要知道先 validate() 再 submit() |
| Depth(深度) | 接口的杠杆效应——单位接口能调动多少行为 | 深度模块 = 小接口 + 大量实现 |
| Seam(接缝) | Michael Feathers 提出的概念:可以改变行为但不需要在那个位置编辑的地点,即模块接口所在的边界 | 两个模块之间的抽象层 |
| Adapter(适配器) | 插在 Seam 上、满足接口的具体实现 | 生产环境用 HTTP 适配器,测试用内存适配器 |
| Leverage(杠杆) | 调用者从深度中获得的东西:每学习一个接口单元,获得更多能力 | 一个实现服务于 N 个调用点和 M 个测试 |
| Locality(局部性) | 维护者从深度中获得的东西:变更、bug、知识集中在一处 | 修一处,全部生效 |
2.2 严格禁止的术语
为了避免 AI 在架构分析时出现歧义,以下术语被明确禁止:
- 禁止用
component/service—— 用module - 禁止用
API/signature—— 用interface - 禁止用
boundary—— 用seam(因为 boundary 在 DDD 中有"限界上下文"的特殊含义) - 禁止用
layer/wrapper来描述模块——用module
这种强制性词汇统一是整个方法论的基础。当 AI 和开发者都用同一套语言讨论架构时,沟通摩擦大幅降低,AI 提出的建议也更精准。
三、深模块 vs 浅模块:架构的核心矛盾
3.1 什么是深模块?
深模块(Deep Module) = 小接口 + 大量实现。一个模块把大量复杂的逻辑隐藏在简洁的接口后面,调用者只需要知道很少的信息,就能完成很多工作。
┌─────────────────────┐
│ Small Interface │ ← 少量方法,参数简单
├─────────────────────┤
│ │
│ Deep Implementation│ ← 复杂逻辑被隐藏在内
│ │
└─────────────────────┘
经典案例:Unix 的 read() 系统调用——接口极简(文件描述符 + 缓冲区 + 字节数),但内部处理了页面调度、缓存管理、磁盘 I/O 等海量复杂性。
3.2 什么是浅模块?
浅模块(Shallow Module) = 接口几乎和实现一样复杂。调用者需要了解大量细节才能使用它,模块本身却没提供多少价值。
┌─────────────────────────────────┐
│ Large Interface │ ← 大量方法,复杂参数
├─────────────────────────────────┤
│ Thin Implementation │ ← 只是透传,没有实质逻辑
└─────────────────────────────────┘
反模式案例:很多项目里常见的"XxxUtils"、"XxxHelper"类——方法众多但每个都只是简单包装,调用者要学很多东西却得不到多少。
3.3 深度是接口的属性,不是实现的属性
这里有一个关键洞察:深度是接口的属性,而非实现的属性。一个深模块内部可以由许多小的、可 mock 的、可替换的部件组成——只要这些内部细节不对外暴露即可。
深模块可以有内部接缝(internal seam,模块私有,仅供自身测试使用),但只有外部接缝(external seam,模块的公共接口)是调用者和测试的入口。
四、三大设计原则
原则一:删除测试(Deletion Test)
当你怀疑某个模块是浅模块时,想象把它删掉会怎样:
- 如果删除后复杂度消失了,说明它只是个透传层,从未创造价值
- 如果删除后复杂度分散到 N 个调用者中,说明它原本在集中复杂度,删对了
"是,复杂度集中了" —— 这才是你想要的信号。
原则二:接口即测试表面(The Interface is the Test Surface)
调用者和测试走的是同一个接缝。如果你想要"穿过接口测试",说明这个模块的形状可能有问题。
这意味着:
- 测试应该通过公共接口进行
- 测试应该断言可观测的行为结果,而非内部状态
- 测试应该能挺过内部重构——如果改一下实现测试就挂了,那测试的是错误的层面
原则三:一个适配器 = 假设性接缝,两个 = 真实接缝
不要为了"可替换性"而凭空引入接缝。只有当至少两个适配器真正需要插在这个位置时,才值得定义一个接口。
| 适配器数量 | 含义 |
|---|---|
| 0 个 | 还没有定义接缝的必要 |
| 1 个 | 假设性接缝——可能是过度设计 |
| 2+ 个 | 真实接缝——值得定义接口 |
五、发现架构问题:系统化探索流程
5.1 优先看热区,不要全局扫描
YAGNI 警告:深化一个模块的收益来自于让未来对它的修改更容易。因此,应该重点关注最近频繁变更的区域,而非地毯式扫描整个代码库。
具体方法:
- 翻阅
git log --oneline,找到持续出现变更的文件和区域 - 让这些"热区"引导你的注意力,而非先入为主地假设哪里有问题
- 如果变更分散没有明显热点,扩大扫描范围
5.2 主动寻找的七种架构摩擦
在探索代码库时,AI 需要主动发现以下问题信号:
① 理解一个概念需要在多个小模块之间跳跃
→ 说明模块划分过细,缺乏聚合
② 模块是浅层的——接口复杂度和实现复杂度几乎一样
→ 说明接口没有隐藏足够多的复杂性
③ 为测试性提取了纯函数,但真正的 bug 藏在调用方式里(缺乏局部性)
→ 说明提取方向错了,局部性比纯函数更重要
④ 紧耦合的模块跨越了接缝
→ 应该有接缝的地方没有接缝
⑤ 代码难以测试,或需要大量 mock 才能测到当前接口
→ 接口设计可能有问题
⑥ 理解一个模块需要了解太多调用者的细节
→ 说明实现细节泄露到了接口
⑦ 模块间的依赖关系形成复杂的网状结构
→ 说明缺乏清晰的层次和边界
六、产出物:HTML 架构报告
当 AI 完成探索后,会生成一份自包含的 HTML 报告,写入系统临时目录。每份报告包含:
6.1 报告结构
报告标题(代码库名称 + 日期)
├── 图例说明(实线=模块,虚线=接缝,红色=泄露,黑色粗线=深模块)
├── 候选深化方案卡片(每个一张)
│ ├── 标题(如"合并订单接入管道")
│ ├── 推荐强度标签(Strong / Worth exploring / Speculative)
│ ├── 涉及文件
│ ├── Before/After 可视化对比图
│ ├── 问题(一句话描述当前架构痛点)
│ ├── 解决方案(一句话描述改进方向)
│ ├── 收益要点(≤6 词每条,用设计词汇描述)
│ └── ADR 冲突警告(如有)
└── 首要推荐章节
6.2 可视化策略
报告使用 Tailwind CSS(CDN)+ Mermaid 图(CDN)+ 手绘 SVG 的混合方案:
- Mermaid 图:用于依赖关系、调用流程、序列图等图状关系
- 手绘 SVG:用于更编辑性的可视化,如质量图、剖面图
- 交叉截面图(Cross-section):展示调用链路的层次,改进前是 6 层薄层,改进后是 1 层厚层
- 质量图(Mass diagram):对比接口和实现的相对大小,直观看出"浅"还是"深"
关键设计原则:图表才是报告的核心,文字只是辅助。如果一张图需要一段话来解释,说明应该重画这张图。
6.3 报告示例用语
报告使用严格的设计词汇撰写,确保语言精准:
"Order intake module is shallow: interface nearly matches the implementation."
"Pricing leaks across the seam."
"Deepen: one interface, one place to test."
"Two adapters justify the seam: HTTP in prod, in-memory in tests."
七、深化集群:依赖分类与测试策略
7.1 四类依赖的处理方式
不是所有模块都可以用同一种方式深化——取决于依赖的性质:
| 依赖类型 | 特征 | 深化策略 | 测试方式 |
|---|---|---|---|
| 进程内(In-process) | 纯计算、内存状态、无 I/O | 直接合并 | 通过新接口直接测试 |
| 本地可替代(Local-substitutable) | 有本地测试替身(PGLite、内存文件系统) | 可深化 | 用替身在测试套件中运行 |
| 远程但自建(Ports & Adapters) | 自有的跨网络服务(微服务、内部 API) | 在接缝处定义 port,注入 adapter | 用内存 adapter 测试 |
| 纯外部(Mock) | Stripe、Twilio 等第三方服务 | 注入 port | 用 mock adapter 测试 |
7.2 核心原则:替换而非分层(Replace, Don't Layer)
这是测试策略的关键转变:
- 旧单位测试(针对浅模块的)→ 一旦在深模块接口上有了测试,这些旧测试就成了冗余,应该删除
- 新测试 → 在深模块的接口层面编写,断言可观测行为
- 测试应该能挺过内部重构——如果改实现导致测试失败,说明测试位置不对
八、设计两次:接口探索的并行子 Agent 模式
当用户选定了一个深化候选方案后,还有一个高级模式叫 Design It Twice——用并行子 Agent 从不同约束角度设计多个完全不同的接口方案,再对比选择。
8.1 流程
- 问题空间对齐:向用户解释问题的约束、依赖类别、代码草图
- 并行子 Agent 设计:同时启动 3-4 个 Agent,每个用不同约束条件设计接口
- Agent 1:最小化接口(1-3 个入口,最大化杠杆)
- Agent 2:最大化灵活性(支持多种使用场景和扩展)
- Agent 3:优化最常见调用方(默认用例零门槛)
- Agent 4(如适用):围绕 Ports & Adapters 设计跨接缝依赖
- 对比呈现:按深度(杠杆)、局部性(变更集中度)和接缝位置三个维度对比
8.2 对比维度
每个设计方案输出:
- 接口(类型、方法、参数、不变量、错误模式)
- 使用示例
- 实现隐藏了什么
- 依赖策略和适配器方案
- 权衡分析(杠杆高的地方、薄的地方)
最终给出明确的推荐,而非让用户自己选。
九、ADR 冲突处理
如果在探索过程中发现候选方案与现有 ADR(Architecture Decision Record,架构决策记录)冲突:
- 不要把所有 ADR 禁止的理论重构都列出来
- 只在摩擦足够真实、值得重新审视 ADR 时才暴露冲突
- 用明确标注提示:"contradicts ADR-0007, but worth reopening because…"
- 如果用户用有充分理由拒绝了候选方案,可以将其记录为新 ADR,防止未来重复提议
十、归纳总结:核心观点与设计哲学
10.1 十大核心观点
① 深度是接口的属性,不是实现的属性
模块内部可以很复杂,只要不泄露到接口即可。
② 接口即测试表面
调用者和测试走同一条接缝,不存在"单元测试内部细节"这种说法。
③ 浅模块是架构的万恶之源
接口复杂度 ≈ 实现复杂度的模块既没有隐藏复杂性,也没有提供杠杆,是最大的浪费。
④ 统一词汇是协作的基础
Matt Pocock 强制整个技能体系使用同一套术语,避免 AI 在分析中出现语义漂移。
⑤ 不要为了抽象而抽象——两个适配器才定义一个接缝
一个适配器的抽象是过度设计,两个才是真实需求。
⑥ YAGNI 应用于架构改进
只深化那些确实需要经常变更的模块,不要地毯式重构。
⑦ 热区比全局更重要
翻 git log 找热区,让变更历史引导你找到真正需要深化的模块。
⑧ 删除测试验证价值
如果删除模块后复杂度消失,它只是个透传;如果复杂度扩散到调用者,它在创造价值。
⑨ 测试策略:替换而非分层
深模块接口测试替代浅模块单位测试,删除不再需要的旧测试。
⑩ 设计两次,用并行 Agent 探索多解
第一个想法很少是最优解,多角度并行设计才能找到真正好的接口。
10.2 设计哲学
整个方法论建立在一个核心信念上:
好的架构不是画出来的,是通过词汇、原则和流程逐步逼近的。
Matt Pocock 的技能体系没有发明新的架构范式,而是把软件工程中已有的好原则(深模块、最小化接口、关注点分离、测试作为接口的消费者)用一套严格的设计词汇和一个可操作的流程包装起来,让 AI 能够系统化地应用这些原则。
它不追求一次性设计出完美架构,而是通过"探索 → 呈现候选 → 深度推演 → 决策"的循环,让架构演进成为一个持续、可导航、有记录的过程。
十一、实战建议:如何在自己的项目中应用
立即可执行
- 采用统一词汇:在团队内强制使用 module/interface/depth/seam/adapter/leverage/locality 这七个词,废弃 service/API/boundary 等模糊术语
- 删除测试:对每个疑似浅模块执行"删除测试",把价值存疑的透传层删掉
- 关注热区:每周翻一次 git log,找到变更最频繁的区域,优先在这些地方寻找深化机会
中期改进
- Ports & Adapters 改造:对远程依赖定义 port 接口,实现生产适配器和测试适配器
- 生成架构报告:用这套方法论为自己的代码库生成 HTML 架构报告
- 建立 ADR 文档:记录架构决策,防止重复踩坑
长期演进
- Design It Twice 流程:对核心模块的新增接口,使用并行 Agent 方式探索多个方案
- 持续深化循环:每季度做一次架构热区扫描,持续改进高频变更区域的模块深度
首发于微信公众号「比特财商」
以上,既然看到这里了,如果觉得不错,随手点个赞、在看、转发三连吧,如果想第一时间收到推送,也可以给我个星标,谢谢你看我的文章,我们,下次再见。
首发于微信公众号「比特财商」
Frequently Asked Questions
Who is behind TopDigg?
TopDigg is created by Eric, a researcher focused on AI trends and SEO/GEO strategies.
How often is content updated?
Blog posts are published regularly. AI Daily is updated daily with the latest AI news.
Can I republish or share content from TopDigg?
Please contact us for content licensing and collaboration inquiries.
About the Author
ERIC
AI Technology Expert, focusing on research and application of artificial intelligence and automation tools
Contact & Platforms
