2008 年,Robert C. Martin 出版了《代码整洁之道》(Clean Code),后来大家更习惯叫他 Uncle Bob。那时候互联网项目的规模正在往上蹿,谁都能写几行,谁也都在头疼接手别人的烂摊子。混乱的代码像野草一样疯长,把各家团队的交付节奏越拖越慢。

Uncle Bob 在书里立下一套规矩。最出名的一句是,代码写出来首先给人读,顺带给机器执行。著名的童子军军规也是那时候普及开的,进营地什么样不管,离开时营地要比来时干净一点。函数尽量小,命名尽量准,动笔改业务前先把测试写出来(TDD)。这套习惯成了几代工程师入行时的底子。
快二十年过去,如今轮到 AI Coding Agent 上场,每秒能吐出几十行代码。代码量变得更大,老毛病其实一点没少。机器生成的代码排版漂亮,乍看挑不出刺,底下往往藏着更难察觉的脆弱逻辑和凑数测试。七十多岁的 Uncle Bob 亲自下场,给这群不知疲倦的机器写下了 ub-mode。
怎么装、怎么用
Uncle Bob 开源的 ub-mode,是专门给 AI 编程助手定制的一套代码整洁技能。如果你手头在用 Claude Code 或 Cursor,在本地跑起来只要几分钟。
1. 安装配套度量工具
整套方案需要 Python 3.11 或更新版本。除了技能文件本身,Uncle Bob 还配了三款用于检查代码质量的看门小工具。变异测试工具需要读取圈复杂度工具的计算结果,最省心的办法是把它们并排克隆在同一个文件夹里。
1 | mkdir -p ~/tools && cd ~/tools |
2. 配置 Agent 技能文件
克隆完工具后,把 ub-mode 仓库里的 SKILL.md 拷贝到你的 Agent 技能目录。以 Claude Code 为例,可以这样放。
1 | mkdir -p ~/.claude/skills/ub-mode |
如果使用其他支持 Agent Skills 的编程环境,同样放进对应的 skills/ub-mode/ 目录下即可。
3. 调用与日常使用
启动开发工具后,在对话框里直接输入命令就可以载入这套规范。
1 | /ub-mode |
载入之后,Agent 会自动遵循先写测试、再改业务、小步提交的节奏。不过,装好这个技能只是第一步,它起效的逻辑,藏在它背后的设计思路里。
别让 AI 审 AI
现在很多人习惯让大模型去审查大模型。靠模型推理来抓代码质量,很难避开模型原生的迎合偏见、幻觉和自我合理化。自己写自己审,两边都在做语义推演,往往各退一步把坏味道当成合理妥协放过去了。
软件工程这么多年守住质量,靠的是确定性。在持续集成(CI)流水线里,任何环节说话只看退出码。程序跑完交出一个状态数字,0 算通过,非 0 算失败,中间没有商量余地。
ub-mode 最有价值的设计,在那三样配套的小工具上。这三样小工具直接在机器本地运行,专门做静态分析和变异测试,不走大模型推理那一套。它们不管大模型怎么解释,只管把代码结构与测试深浅算成具体的数字。Crapper 超过指定阈值、Mutator 检出存活变异体时,会返回非 0 退出码;Dryer 则输出重复报告,成功生成报告后仍返回 0,需要门禁脚本另行读取并判断。把这些检查接入能阻止 Agent 结束的门禁后,检查未通过就会触发返工。

工具检查接入门禁后的流程。门禁脚本需另行配置;仅安装技能不会自动形成阻断。
来看看这三款看门工具是怎么在实战中戳穿漏洞的。
- Crapper 拦截高风险函数
这个工具把函数的圈复杂度与测试覆盖率揉在一起算 CRAP 风险值。计算公式很直接。
CRAP = CC^2 * (1 - coverage)^3 + CC
分支特别多却没写几个测试的函数,这个值会迅速飙高。如果执行 crapper --threshold 10,只要有函数的 CRAP 超过 10,命令直接返回退出码 2。
Mutator 变异测试戳穿假覆盖率
很多测试虽然把每行代码都跑了一遍,断言却写得极松。Mutator 专门对付这种应付了事的测试。它会在源码里故意挑起小破坏,比如把大于号改成大于等于号,把等于改成不等于。有人拿一个 17 行的运费计算函数做实验,测试覆盖率达到了 100%,因为断言只写了返回值不为空,Mutator 注入的 7 个变异体有 4 个大摇大摆活了下来。Mutator 发现有变异体存活,立刻返回退出码 3。直到开发者把边界数值的精准断言补齐,存活变异体归零,门禁才会放行。Dryer 代码结构指纹查重
Agent 写代码时经常把一段逻辑换个变量名复制一遍。Dryer 会抽掉局部变量名和具体字面量,只比对剩余的抽象语法树指纹。如果相似度达到阈值,它就会在报告里标出重复项。
把这些工具以退出码的形式卡在开发流水线里,Agent 就算再想偷懒,面对机器算出来的硬指标也没法蒙混过关。代码整洁到这一步,才算有了落地的底线。