同一个模型同一份 review 清单。这次它精准指出这个函数嫉妒了另一个对象的数据该搬过去下次面对更简单的代码它却只回一句整体看起来不错。它不是忘了规则。Feature Envy、Duplicated Code、命名该用领域词汇这些知识它一直都在。变差的不是知识是它当时看到的东西上下文外无物。参数里的规则是固化的、静态的真正决定这一轮怎么做的是它这一轮读进去的东西。规则本身不用教代码坏味道是二十年前就写进书里的公共知识。Fowler 的 12 个 smell、耦合与内聚、“接口即测试面”任何一个训练过代码的模型都反复见过这些文本。所以一份 code-review skill 真正该做的不是把知识再讲一遍。规则只需要点到过哪几个视角、每个视角看什么形状的问题。六个视角各自对应一个可回答的问题——不看注释能否说出这段代码在做哪个用户故事语言改一个概念要动几个文件耦合新人从上往下读要跳转几次阅读删掉所有 mock 测试还跑不跑得起来边界能否向用户演示现在能做什么完整删掉这段代码有没有测试变红无用。每个问题都有个数字或是非答案模型没法用还行糊过去。视角只是方向方向上具体找的是那些有名字的坏味道Feature Envy、Data Clumps、Shotgun Surgery。给坏味道起名字你才看得见它。没有Feature Envy这个词你只会觉得这段读着别扭说不清别扭在哪。为什么会失手review 是个判断任务判断依赖它当时看到的输入而输入经常是脏的。三种脏法各有各的失效方式。最直接的一种是它正在看的代码本身就烂。你让它 review 一段祖传泥球周围全是data、temp、五层嵌套。模型是概率机器被这些劣质样本一带判定基线就往下滑满屏的坏味道看多了它开始觉得这好像就是这个项目的正常水平于是该报的不报了。坏代码不只是被审对象它还在悄悄重设审查者的及格线。需求和命名里的歧义导致的是另一种结果。前期需求澄清时本该锁定的领域词汇如果没锁死模型接手的就是一堆模糊词一个东西在这里叫 order、那里叫 request、注释里又叫 form它没法判断命名是否一致因为它自己都分不清这三个到底是不是一个东西。歧义不产生错误结论它产生的是放弃判断——模型绕开这条视角含糊带过。最隐蔽的是长会话里自相矛盾的上下文。一个多次对话的 session前面说我们用 Result 类型不抛异常后面又贴了一段到处 throw 的代码中间还夹着三次反悔的决定。模型读到的是一份互相打架的上下文它要 review 的那段代码到底该符合哪条约定它不知道会话越长这种矛盾越多判断越像抛硬币。三种脏法都不是模型不懂 review而是它看到的东西不足以支撑一次干净的判断。解法一把不随上下文漂移的尺子问题出在输入被污染那么解法是递一把稳定的尺子让判断有个不跟着会话漂的锚。这把尺子是那份独立的review-lenses.md6 个视角、12 个 smell 写死在文件里不在会话里。它是 review、refactor、TDD 三个环节共用的同一份判定标准改这份文件等于同时改三个 skill 的行为。模型每次 review 都回到这份文件而不是回到那个已经吵了两小时、自相矛盾的对话。尺子上还刻了三条硬规矩每条对着一个脏源。只读、不改代码审查者不下场判断和修复分开脏代码诱不动它顺手就改。发现必须可定位到文件和行号这条逼它给证据堵死整体还行这种被烂代码带出来的含糊结论。还有对照 spec 查实现而不只看代码好不好——会话上下文自相矛盾时spec 是那个不吵架的第三方代码该符合的是它不是最近那条反悔的消息。写得好和做对了是两件事质量轴问代码写得好不好spec 轴问代码做没做对的事查三类偏差spec 要求了但没做的spec 没要求却做了的看着实现了其实做错的。两轴必须分开报因为代码可能六个视角全绿却实现错了需求也可能需求全中但写得一团糟。合成一份打分这两种情况会互相抹平——质量分拉高总分读的人以为没大事。没有 spec 的代码怎么办这里有个明显的反对意见review 的对象常常是遗留代码、别人的 PR、外部 diff它们没有 spec也没有锁定过的领域词汇表。这把尺子靠两样东西校准——spec 和领域词汇表两样都缺那还量什么答案是降级不是硬套。没有 specspec 轴整个跳过并在汇总里注明无 spec 可对照——空着比编一个假 spec 去对照要好。没有领域词汇表视角 1 从命名是否使用锁定的领域词汇退化为命名是否有意义、是否一致。退化后的判断更弱但标准仍然是外部的、稳定的。这也划出了实际能力边界它在上游做过需求与领域词汇锁定的代码上最锋利想让它更锋利得往上游补 spec。开源链接code-reviewCoding Style用在最小实现步骤红→绿的绿不是重构。下笔时就照它写让代码一开始就整洁。重构refactoring-techniques.md是补救处理绿之后才浮现的结构问题。本文件是预防写第一行时就避免产生泥球。review 时review-lenses.md从看的方向复查这些原则是否被遵守。不要因为现有代码劣质就依样画瓢也不要被歧义错词带偏。参考的是这份风格不是身边最脏的那段代码。Unix 哲学Eric Raymond 归纳的 17 条写实现时的正向约束。挑与当前 slice 相关的用。模块用简洁的接口拼合简单的部件。清晰清晰胜于机巧。组合设计时就考虑能被拼接组合。分离策略同机制分离接口同引擎分离。简洁设计要简洁复杂度能低则低。吝啬除非确无它法不写庞大的程序。透明设计要可见以便审查和调试。健壮健壮源于透明与简洁。表示把知识叠入数据以求逻辑质朴而健壮。通俗接口设计避免标新立异最小惊讶。缄默程序没什么好说的就沉默。补救出现异常时马上退出并给出足够错误信息。经济宁花机器一分不花程序员一秒。生成避免手工 hack尽量写程序去生成程序。优化雕琢前先有原型跑之前先学会走。多样不信不二法门的断言。扩展设计着眼未来但别为想象中的需求预留配合 YAGNI。落到当前 slice 的硬约束写每条 slice 时至少守住这几条1. 命名先于实现清晰 表示变量、函数、测试名一律用 grill 锁定的领域词汇不用data/result/temp/handler/utils。命名描述做什么而非怎么做。起不出诚实的名字说明这段设计本身模糊——停下来想别硬写。“傻瓜都能写出计算机可以理解的代码。唯有能写出人类容易理解的代码的才是优秀的程序员。”2. 只写这条 slice 需要的吝啬 简洁 YAGNI最少代码度量的是认知不是行数。不提前抽象、不加 spec 没要求的参数/钩子/未来扩展点。真实需求出现前内联比抽象好。“YAGNI——你不会需要它。”3. 让人从上往下读得懂透明 阅读顺序前提条件卫述句在顶部处理完主逻辑不深嵌。声明和初始化放在一起复杂子表达式提取成有意图的解释型变量。4. 出错就地退出给足信息补救 健壮异常在发生处就地退出不静默吞掉、不返回一个看起来正常的空值让错误往下游漂。错误信息要能定位说清哪个操作、什么输入、期望什么。throw new Error(失败)等于没说要throw new Error(\拉取 ${url} 失败HTTP ${status})。Unix 补救原则出现异常时马上退出并给出足够错误信息——排查的人靠这条信息而不是靠猜。5. 默认不可变表示 健壮更新数据用拷贝不原地改{...user, name}、[...items, x]而非user.name x/items.push(x)。不可变默认让谁改了这个值这个问题消失——状态只在一处产生读代码不用追踪它被谁改过。需要原地修改时性能、大数组显式注释说明为什么。深模块小接口大实现写实现时倾向深模块——把复杂逻辑藏在一个小接口后面而不是摊成一堆浅模块让调用方自己拼。接口小LLM 和人每次要读懂的上下文都少。设计语言、判据删除测试和可测性原则见module-design.md——写、review、重构三态共用同一份。