深度模块架构
创建时间: 2026-04-30
来源: [[sources/How To De-Slop A Codebase Ruined By AI (with one skill) - 逐字稿]]、John Ousterhout《A Philosophy of Software Design》
相关: Harness-Engineering、Agent-First-Repository-Design、Generator-Evaluator-Architecture、Agent-Paradigm-Shift、Vibe-Coding-in-Prod、Extreme-Co-Design、Software-Fundamentals-in-AI-Coding
问题:AI 加速软件熵增
AI 让代码变得”便宜”——LinkedIn CEO 们宣称他们可以比以往更快地交付。但现实是:AI 正在加速软件熵增。每次 AI 做出的变更不考虑整个代码库时,就会引入微小的、奇怪的东西,让代码库越来越难改。这就像滚雪球,最终变成一团巨大的泥球(ball of mud)。
AI doesn’t make code good. It makes code fast. Speed without design = entropy.
问题的根本症结在于:AI 生成的代码倾向于创建浅模块(shallow modules)——接口复杂但实现空洞的模块——而非深模块。同时 AI 缺乏对模块间依赖关系的全局视野,制造出大量低 locality 的散落代码。
在 Software-Fundamentals-in-AI-Coding 中,Matt Pocock 把这一点放进更大的论证:AI 时代“代码很便宜”是危险错觉,坏代码会直接削弱 AI 的可理解性、可测试性和反馈循环。深模块不是单纯的代码整洁技巧,而是让人类能够“设计接口、委托实现”的认知边界。
理论基础:John Ousterhout 的模块设计
核心原语
| 概念 | 定义 | 例子 |
|---|---|---|
| 模块(Module) | 应用中的功能单元 | React 组件集合、认证函数族、日志器 |
| 接口(Interface) | 调用者必须知道的一切才能正确使用模块 | signIn() / signOut() 方法签名、文档、调用约定 |
| 实现(Implementation) | 模块内部实际做的事 | 调用 signIn() 时发生的所有逻辑 |
| 深度(Depth) | 调用者每学习一单位接口,能获得的行为量 | TanStack Query:极简 API,隐藏大量复杂性 |
深模块 vs 浅模块
深模块(Deep Module) 浅模块(Shallow Module)
┌──────────────────┐ ┌──────────────────────┐
│ 简单接口 │ │ 复杂接口 │
│ ┌────────────┐ │ │ ┌────────────────┐ │
│ │ signIn() │ │ │ │ signIn() │ │
│ │ signOut() │ │ │ │ signOut() │ │
│ └────────────┘ │ │ │ refreshToken() │ │
│ │ │ │ validate() │ │
│ 大量隐藏实现 │ │ │ configure() │ │
│ ┌────────────┐ │ │ └────────────────┘ │
│ │ ██████████ │ │ │ │
│ │ ██████████ │ │ │ 少量实现 │
│ │ ██████████ │ │ │ ┌────┐ │
│ └────────────┘ │ │ │ ██ │ │
└──────────────────┘ └──────────────────────┘
好的设计 差的设计
判断标准:最好的开源库(如 TanStack Query)几乎都是深模块——它们在极简接口背后隐藏了大量复杂性。
接缝(Seams)与适配器(Adapters)
模块之间存在依赖关系,这些依赖的边界就是 seams——模块接口在应用中存在的位置。Seams 是你做单元测试和集成测试的地方。
在 seam 处,可以有多个适配器来满足同一个接口(来自六边形架构):
应用核心
│
┌─────┴─────┐
│ Clock 接口 │ ← seam
└─────┬─────┘
┌────┴────┐
│ │
真实时钟 假时钟
(生产) (测试)
这样你不需要等两周来跑完测试——在 seam 处插入 fake adapter 即可。
两个收益:Locality 与 Leverage
深度模块架构带来两类人两种收益:
| 受益者 | 收益 | 含义 |
|---|---|---|
| 维护者(写代码的人) | Locality(局部性) | 变更和 bug 修复集中在模块内部,而非散落各处 |
| 使用者(调模块的人) | Leverage(杠杆) | 模块越深,每学一单位接口就能获得越多能力 |
改善代码库时,你要瞄准的就是这两个属性:提高 locality,增加 leverage。
Locality 差的表现:同一个概念在前后端各有一套独立实现,两者的 seam 未经测试。前端改了,后端可能不同步。
工具:Improve Codebase Architecture Skill
Matt Pocock 开发了一个 Claude Code skill(已获 41.5K GitHub stars),将上述理论操作化为可执行的 AI 工作流:
工作流程
- Explore:AI 遍历代码库,搜索 deepening opportunities(浅模块、低 locality、未测试的 seams)
- Identify:列出候选项(如”这个概念有两个并行实现,seam 未测试”)
- Grilling Session:AI 与人类进行结构化对话——
- 展示具体代码证据
- 提出模块重组方案
- 询问架构决策偏好
- Sketch Interface:AI 起草新模块的 TypeScript 接口
- Output:产出 GitHub issue,可由 AFK agent 后续执行
术语表(共享词汇)
技能内置了一个术语表(glossary),确保人类和 AI 使用相同的精确语言讨论架构。这是关键设计——共享词汇使沟通变得精确。
人机分工:战略与战术
这个技能的核心洞见是角色分层:
| 层级 | 角色 | 职责 |
|---|---|---|
| 战略层(General) | 人类程序员 | 做判断、决策长期健康、选择架构方向 |
| 战术层(Sergeant) | AI Agent | 跑代码库、找机会、提方案、写代码 |
该技能要求你做出判断——它不是可以放手让 AI 自动持续改善代码库的 AFK 技能。AI 在战术层面非常出色(快速遍历、识别模式、起草方案),但架构决策需要人类战略眼光。
Matt 建议每几天跑一次这个 skill,尤其在快速迭代的代码库里,会源源不断涌现出 deepening opportunities。
测试作为乘数效应
好的 seams → 清晰的深模块 → 好的测试 → 更好的 agent 输出。
这是一个正向反馈循环:
- 清晰的模块边界使测试容易写
- 好测试为 AI agent 提供安全网
- AI 在有安全网的环境中产生更高质量的输出
- 更高质量的输出进一步巩固模块边界
对于遗留代码库(legacy codebase = bad codebase = 难以修改的代码库),在开始让 AI 做任何变更之前,必须先搭建测试 harness。Improve Codebase Architecture 技能正是这个前置步骤——先整顿架构,再让 AI 进场。
关键引用
“Code bases are falling apart faster than they ever have before. Because every time that you make a change that doesn’t take into account the entire codebase, you are likely to introduce little things that make the codebase harder to change.”
“I think of agents as really, really good tactical programmers… but they need someone on the level above them who is the strategic programmer.”
“The better your tests are, the better the output from the agent is going to be.”
参考资料
- 来源:Matt Pocock — How To De-Slop A Codebase Ruined By AI (with one skill)
- 理论根基:John Ousterhout《A Philosophy of Software Design》
- 相关项目:Matt Pocock’s GitHub Skills Repo(41.5K stars)
- 工具:Matt Pocock 的 “improve codebase architecture” Claude Code skill