对 HEAD 与用户提供的固定基点之间的差异进行双向审查:
- 标准:代码是否符合此仓库已记录的编码标准?
- 规范:代码是否忠实实现了原始问题/规范?
两个维度作为并行子代理运行,以免污染彼此的上下文,然后此技能汇总它们的发现。
问题追踪器应已提供给你。如果没有,请告知用户运行 /setup-matt-pocock-skills。
流程
1. 确定固定基点
无论用户指定的固定基点是什么(一个提交 SHA、分支名、标签、main、HEAD~5 等)。如果用户未指定,请询问。
一次性捕获差异命令:git diff <fixed-point>...HEAD(使用三点,以便与合并基准进行比较)。同时通过 git log <fixed-point>..HEAD --oneline 记录提交列表。
在进一步操作之前,确认固定基点可以解析(git rev-parse <fixed-point>)并且差异不为空。错误的引用或空差异应在此处失败,而不是在两个并行子代理内部。
2. 识别规范来源
按以下顺序查找原始规范:
- 提交消息中的问题引用(
#123,Closes #45,GitLab!67等),通过追踪器文档中的工作流程获取。 - 用户作为参数传递的路径。
docs/,specs/或.scratch/下与分支名或功能匹配的规范文件。- 如果未找到任何内容,请询问用户规范的位置。如果用户说没有,那么规范子代理将跳过并报告“无可用规范”。
3. 识别标准来源
搜索仓库中所有描述代码应如何编写的文件。如果存在 CODING_STANDARDS.md 或 CONTRIBUTING.md,则必须将其列入列表。
除仓库文档中的内容外,标准轴始终附带以下坏味基线:一组固定的 Fowler 代码坏味(《重构》第 3 章),即使仓库没有任何文档也适用。有两个规则约束它:
- 仓库覆盖。 已记录的仓库标准始终优先;如果仓库认可基线会标记的内容,则抑制该坏味。
- 始终是判断。 每个坏味都是一个带标签的启发式规则(“可能的依恋情结”),而不是硬性违规。与这里的任何标准一样,跳过任何工具已强制执行的内容。
每个坏味都说明它是什么 → 如何修复;将其与差异进行匹配:
- 神秘命名:函数、变量或类型的名称无法揭示其功能或含义。→ 重命名;如果想不出合适的名称,说明设计不清晰。
- 重复代码:相同的逻辑结构出现在变更中的多个块或文件中。→ 提取共享结构,从两处调用。
- 依恋情结:一个方法访问另一个对象的数据比访问自身的数据更多。→ 将方法移动到它依恋的对象上。
- 数据泥团:相同的少数字段或参数不断一起出现(一个亟待诞生的类型)。→ 将它们捆绑成一个类型,传递该类型。
- 基本类型偏执:基本类型或字符串代替了本应拥有自己类型的领域概念。→ 为该概念赋予自己的小型类型。
- 重复的 switch:相同的
switch/if级联在变更中重复出现。→ 用多态替换,或使用一个两者共享的映射。 - 霰弹式修改:一个逻辑变更迫使差异中的许多文件分散修改。→ 将变更内容集中到一个模块中。
- 发散式变化:一个文件或模块因多个无关原因被修改。→ 拆分,使每个模块只为一个原因更改。
- 过度泛化:为规范不存在的需求添加的抽象、参数或钩子。→ 删除;内联直至出现真正的需求。
- 消息链:调用者不应依赖的长
a.b().c().d()导航。→ 将遍历隐藏在第一个对象上的一个方法后面。 - 中间人:一个类或函数主要只是将职责委托下去。→ 删除它,直接调用真正的目标。
- 拒绝继承:一个子类或实现者忽略或覆盖了大部分继承的内容。→ 放弃继承,使用组合。
4. 并行生成两个子代理
同时发起两个子代理调用,在前台进行,并汇总它们返回的报告。
标准子代理提示应包括:
- 完整的差异命令和提交列表。
- 你在步骤 3 中找到的标准源文件列表,以及步骤 3 中的坏味基线(完整粘贴,因为子代理无法通过其他方式访问它)。
- 简要说明:“报告每个相关文件/块中:(a)差异违反已记录标准的每个地方:引用标准(文件 + 规则);以及(b)你发现的任何基线坏味:命名它并引用该块。区分硬性违规与判断性判断:已记录标准的违规可能是硬性的,但基线坏味始终是判断性判断,并且已记录的仓库标准覆盖基线。跳过任何工具强制执行的内容。不超过 400 字。”
规范子代理提示应包括:
- 差异命令和提交列表。
- 规范的路径或获取的内容。
- 简要说明:“报告:(a)规范要求的但缺失或不完整的需求;(b)差异中未要求的行为(范围蔓延);(c)看起来已实现但实现似乎有误的需求。为每个发现引用规范行。不超过 400 字。”
如果规范缺失,则跳过规范子代理,并在最终报告中注明。
5. 汇总
将两个报告分别放在 ## 标准 和 ## 规范 标题下,逐字或轻度清理后呈现。不要合并或重新排序发现,因为这两个维度是故意分开的(见_为何分为两个维度_)。
以一个单行摘要结束:每个维度的发现总数,以及每个维度内最严重的问题(如果有)。不要在维度之间选出一个最终的胜者:这正是分离要防止的重新排序。
为何分为两个维度
一个变更可以通过一个维度而失败于另一个维度:
- 代码遵循了所有标准但实现了错误的内容 → 标准通过,规范失败。
- 代码完全按照问题的要求做但却违反了项目的约定 → 规范通过,标准失败。
分别报告它们可以防止一个维度掩盖另一个维度。