← 返回 Skill 列表
extension
分类: 开发与工程API Key 暂未确认

code-quality

有观点的约束,用于编写可维护、可测试的代码。应用MTE原则,避免过度设计,指导重构,并提供代码审查清单。当用户编写代码、重构或需要代码审查时使用。触发关键词包括“代码质量”、“重构”、“审查”、“MTE”、“code quality”、“refactor”、“review”。

person作者: jakexiaohubgithub

Code Quality

编码和重构时的质量约束(代码质量 SSOT),确保代码可维护、可测试、适度扩展。

Language

  • Accept questions in both Chinese and English
  • Always respond in Chinese

Trigger Conditions

  • 用户正在编写新代码 / 重构现有代码
  • 用户需要 Code Review 检查清单
  • 用户提到 MTE 原则、代码质量、命名、注释、避免过度设计

核心原则:MTE

所有代码必须遵循 MTE 原则:

| 原则 | 说明 | 检查点 | |------|------|--------| | Maintainability | 可维护性 | 职责单一、依赖清晰、命名/注释/日志/错误处理合规、易于理解 | | Testability | 可测试性 | 核心逻辑可单元测试、依赖可 Mock | | Extensibility | 可扩展性 | 预留合理扩展点、接口抽象 |

核心阈值表

全仓唯一权威阈值源。谓词语义统一:≤ 建议值 = 合规;> 建议值且 ≤ 最大值 = [Suggestion];> 最大值 = [Blocker];无建议值的指标(重复代码 / 单类行数)只有两档——≤ 最大值 = 合规,> 最大值 = [Blocker]。镜像边界:agent 侧 references / SKILL 一律改指针不镜像(已迁移:dev-workflow verification-flow Phase 1、本 skill refactor-signals.md);仅用户侧产物模板(会复制进用户项目,届时本 skill 不在场)允许内联数字,且须标注"摘录自本表,变更需同 commit 同步"。

待迁移(本表的已知 agent 侧镜像,未清):refactor/SKILL.md:126-132——非纯镜像,含该 skill 私有的 > 2× 最大值 → P0 优先级映射,需连带重写故单独处理。

| 指标 | 建议值 | 最大值 | 超最大值的重构方向 | |------|-------:|-------:|--------------------| | 函数长度 | 30 行 | 50 行 | 提取函数 | | 参数数量 | 3 个 | 5 个 | 参数对象 | | 嵌套深度 | 2 层 | 3 层 | 早返回、提取函数 | | 重复代码 | — | 3 处(Rule of Three) | 提取公共逻辑(<3 处禁止提前抽象) | | 单类/单文件行数 | — | 500 行 | 拆分职责(上帝类) |

模块设计

单一职责 / 依赖方向的机械判定口径归「设计原则(代码级)」SRP / DIP 两行,本节只给直观示例,不重复判定。

  • 单一职责:一个类/函数只做一件事(UserService 业务 / UserRepository 数据访问 / UserValidator 校验分开;反例:UserManager 全包)
  • 依赖方向:外层依赖内层(Interface → Service → Domain → Infrastructure);依赖接口,不依赖实现
  • 正反例代码见 references/mte-examples.md

命名规范

总原则:

  1. 精确优先:减长度靠删冗词(不重复类型信息),禁止截短单词(实证:完整单词比缩写定位 bug 快 19%,名长 10-16 字符调试成本最低)
  2. 调用点清晰:名字在调用处读起来像自然短语(clarity at the point of use)
  3. 项目一致性:同概念同名;沿用项目既有大小写惯例而非语言默认;引入新名词前先 grep 项目既有词表

分类规则

| 类别 | 规则 | |------|------| | 类/接口 | 名词短语,描述角色而非实现;禁 Manager/Helper/Util/Processor/Info/Data 等空泛后缀收尾 | | 方法/函数 | 有副作用用动词短语、纯查询用名词;全库同一动作只用一个动词(get/fetch/retrieve 选一);get* 禁副作用 | | 变量 | 长度与作用域成正比:循环/闭包 ≤10 行可用惯用单字母(i/j/k/err/ctx);函数级 ≥1 完整词;导出符号默认 ≥2 词自含上下文* | | 布尔 | 读作断言(isEmpty/hasChildren/canEdit);is*/has* 必须返回布尔;禁否定式名(isNotReady) | | 常量 | 魔法数字按含义命名(MAX_RETRIES 而非 FIVE) |

* 调用点已有命名空间上下文时按语言惯例豁免(如 Go 包名 http.Client、Swift 类型命名空间)。

接口 / 协议命名细则

在"类/接口"通则(名词短语、描述角色不暴露实现)上补充,在不破坏项目既有一致性的前提下,优先按语言/生态惯例命名:

| 类型 | 惯例 | 例 | |------|------|-----| | 能力型("能做什么")| -able/-ible 后缀 | Comparable、Iterable、Closeable | | 单方法接口(Go 惯例)| 动作 + -er | Reader、Formatter | | 角色型("是什么角色")| 名词短语 | Repository、PaymentGateway |

  • 禁 I 前缀(IFoo)等类型编码,除非项目既有惯例(如 .NET)——服从项目一致性。
  • 业务抽象接口不暴露可替换实现技术(UserRepository 而非 MySQLUserRepoInterface,禁 Impl 后缀);外部协议/技术边界接口(如 HttpClient、KafkaConsumer)技术名是契约的一部分,不在此限。

命名黑名单(本次 diff 新增/修改命中即 [Blocker];存量未触碰为 [Suggestion])

| 反模式 | 分级 | |--------|------| | 误导名:名实不符(accountList 非 List、is* 返回非布尔、get* 带副作用) | [Blocker](最高红线:误导名同样降低 agent 自身代码分析准确率) | | 泛化名作完整名:data/info/temp/result/obj/item/thing/flag/val(局部惯用语除外) | [Blocker] | | 同概念多名漂移:同一实体 user/account/customer 混用(引入新名词前必须先 grep 项目词表) | [Blocker] | | 类型编码(匈牙利前缀 strName/m_x)、不可发音自造缩写 | [Blocker](接口 I 前缀的语言/项目惯例例外见上节「接口/协议命名细则」)| | 无意义区分(data1/data2、ProductInfo 与 ProductData 并存)、大作用域单字母 | [Suggestion] |

边界:本规范只判定结构合规(白/黑名单、词性、一致性),不裁决具体选词。正反例见 references/naming-examples.md。

注释规范

信息归宿三分法:源码注释 = 面向未来读者的稳定事实;commit message = 本轮变更说明;traceability/任务文档 = 过程追溯。注释唯一合法用途是承载代码无法表达的信息——能用命名/重构表达的不写注释,后两类信息禁止写进源码注释。

白名单(注释必须属于以下类别之一)

| 类别 | 判定 | |------|------| | 公共契约 | exported API 上方,说明调用契约/错误/边界/不变量,不复述函数名和类型 | | 非显然 why | 外部协议、兼容性、性能、并发、安全、算法取舍;删掉后读者无法判断"为什么这样写" | | 不变量/风险约束 | 类型系统与测试名无法表达的业务约束,紧邻校验或状态转换 | | 复杂 what + 出处 | 复杂算法/正则/反惯用绕坑写法,说明不这样写会踩什么坑;出处仅限外部稳定来源(论文/RFC/issue 链接),项目内过程文档(设计/AC/UT)引用归 traceability,不入注释 | | 抑制类 | eslint-disable / ts-ignore 等必须附具体原因 | | 临时脚手架 | 仅限 S2/S3 骨架阶段(TODO / test.skip/todo / 纯 AAA 占位);S4/S6/S7 后必须清除 |

文件头 INPUT/OUTPUT/POS 自描述由 /code-self-describe 独立管理,不受本规范约束。

黑名单(本次 diff 新增/修改命中即 [Blocker];按语义判定,关键词仅作信号)

| 类别 | 判定 | |------|------| | 变更日志式 | 注释描述本轮变更过程而非代码当前状态(信号词:本次/新增/修改/修复/已按要求;描述业务规则的"新增用户走邀请码通道"合法) | | 对审查者说话 | "此处已修复""按要求处理"等面向 reviewer/agent 而非未来读者的话 | | 来源记录式/注释式追溯 | 记录"来自 UT-XX/AC-XX/后置条件/行为契约"等过程来源。⛔ 不得新增 @satisfies / @requirement / @verifies / @testcase 标注——指向外部系统的编号引用,对没有 keel 上下文的维护者是纯噪音,keel 丢失后更是指向虚空的指针;追溯走文档侧(反向依赖)。存量标注留着不清理,只约束新增 | | 复述代码 | 只是翻译紧邻代码(// 校验邮箱 + validateEmail(email)) | | 注释掉的代码 | 整段旧实现注释保留且无 issue/迁移理由 | | 过量注释 | 同函数连续注释 >3 行,或变更块注释行 > 可执行代码行,且不属白名单 |

分级

  • [Blocker]:本次 diff 新增/修改黑名单注释;抑制类注释无理由;S4/S6/S7 后残留骨架脚手架注释;注释与代码当前语义不符(改代码必须同步更新受影响注释,过期注释比没注释更糟)
  • [Suggestion]:存量坏注释(本次未触碰);public API 缺契约注释(仅当缺失已造成安全/兼容/行为歧义时按对应风险升级)

日志规范

日志唯一目标是让线上失败被快速排查 / 审计 / 观测——价值在"对的级别 + 对的上下文 + 不泄密",不在量;烂日志是烂注释的运行时版本(见上节),同样按本次 diff 新增/修改命中分级。设计阶段"在哪打日志点"见 system-design log-design-guide.md,本节是编码纪律 SSOT。

六条硬规则

| 规则 | 判定要点 | |------|----------| | 目的门槛 | 每条日志须服务排查/审计/观测;禁 here/step1/进出方法/"执行完成"等无对象无结果的占位日志 | | 级别纪律 | ERROR/WARN/INFO/DEBUG·TRACE 准入见下表;最常见误用:所有异常都 ERROR、INFO 刷屏、WARN 当 INFO | | 最小上下文 | 业务日志含 event + result + 关联 id + 组件 + 一个安全主对象 id;失败日志另加 error_code/异常类型 + 原因 + 已采取动作;用结构化字段承载,禁纯文本拼接关键上下文(字段名沿用项目词表)| | 异常纪律 | 异常只在处理边界记一次完整堆栈;禁 log-and-throw(逐层 log 再抛 = 重复"根因");禁吞异常只 log(除非契约明确已降级/补偿并注明)| | 安全红线 | 禁入日志:密码、token、session/cookie、密钥、验证码、原始请求/响应体、原始 SQL/查询、PII、支付/银行/医疗数据、未脱敏的第三方或 LLM 原始响应 | | 事实优先 | 写不可变事实 + 系统动作;推测/风险/模型判断须带来源、规则名或置信度(禁 payment service is broken,写 upstream_status=504, retry_scheduled=true)|

级别准入(规则「级别纪律」展开)

| 级别 | 准入判据 | |------|----------| | ERROR | 当前请求/任务/事务失败,用户或系统可感知,需调查或可触发告警 | | WARN | 异常但已处理、系统可继续:降级、重试耗尽前兆、配置风险 | | INFO | 低频且长期有价值的里程碑:启动/停止、配置版本、任务摘要、关键状态变更 | | DEBUG / TRACE | 默认生产关闭的诊断细节;必须排查的失败不得只放 DEBUG |

分级

  • [Blocker]:本次 diff 新增/修改命中安全红线、log-and-throw 重复堆栈 / 吞异常只 log、把推测写成事实
  • [Suggestion]:本次 diff 新增/修改的级别误用、上下文不足、占位日志;存量坏日志(本次未触碰)

不写死(留给项目规范)

日志格式(JSON/logfmt)、字段大小写、每业务事件清单、采样率、保留周期、脱敏或截断后的 SQL/HTTP payload 策略——依赖运行平台与监管,写死有害。(注:原始 SQL/请求/响应体始终属安全红线,禁入日志,不在"留给项目"之列。)

错误处理(编码级)

只定义编码期红线;错误码体系 / 对外错误契约等设计级归 system-design。与日志「异常纪律」同源、互补。

  • 不吞异常:捕获后必须处理、转换或重抛带上下文;空 catch / 仅 log 后照常继续(状态已漂移)→ [Blocker]
  • 保留 cause:包装异常时挂上原始 cause/堆栈,不丢根因;异常转换只在处理边界做一次
  • 错误有语义:用类型化错误 / 错误码表达可区分的失败,调用方能据此分支;不用裸字符串或布尔承载错误
  • 边界 fail-fast:外部输入 / 不变量违反在边界尽早失败,不让坏数据深入领域
  • 对外不泄露内部:返回给用户/上游的错误不含堆栈、SQL、内部路径、实现细节(与安全编码红线、日志安全红线一致)→ [Blocker]
  • 可恢复 vs 不可恢复分流:可恢复(重试/降级/补偿)须显式策略,不可恢复直接失败,不静默兜底

分级:吞异常 / 丢 cause / 对外泄露内部 = [Blocker](本次 diff 新增/修改);其余为 [Suggestion]。

安全编码红线

通用编码期红线(本次 diff 新增/修改命中默认 [Blocker]);深度安全(威胁建模 / 加密选型 / 合规)留项目或专门规范。

  • 输入不可信:所有外部输入(用户 / 网络 / 文件 / 上游)先校验再入域;SQL 参数化、输出按上下文转义(防注入 / XSS)
  • 鉴权在服务端:权限 / 越权检查必须服务端,前端隐藏不算控制
  • 密钥与敏感数据:密钥 / token / PII 不硬编码、不入日志、不进版本库(见日志安全红线);传输与存储按需加密
  • 最小权限:组件 / 凭证只取必需权限
  • 错误信息不泄露:对外错误不暴露内部实现(与错误处理一致)
  • 依赖安全:不引入已知漏洞依赖,不用废弃算法(MD5/SHA1 存口令、DES 等)

类型与数据契约

  • 外部数据先校验为领域类型/形状再入域:网络 / 存储 / 配置反序列化后即校验为领域类型,不让未校验数据流入业务(类型契约维度;注入 / XSS / 越权等安全维度的校验分级归安全编码红线,不在此重判)
  • null / optional 显式建模:用语言机制(Optional / 可空标注 / Result)表达"可能没有",不靠隐式 null 漫游
  • 避免 stringly-typed:有限状态 / 类别用枚举或类型,不用裸字符串承载领域语义
  • 不绕编译器:禁用宽类型(any / interface{} / 强制转换)掩盖类型问题,除非边界适配并附理由
  • DTO 与 domain 分离:传输 / 持久化模型与领域模型分离,转换在边界完成

分级:stringly-typed、为绕编译器滥用宽类型、类型/形状校验缺失 = [Suggestion](安全维度的输入校验缺失分级归安全编码红线)。

状态与副作用

  • 核心逻辑优先纯函数:业务计算无副作用、可重放(可测试性角度见「可测试性设计」,不重复)
  • 副作用集中边界:IO / 全局状态 / 时间 / 随机集中在边界层,领域层保持纯净
  • 共享可变状态须有主:跨线程 / 协程的共享可变状态必须有明确所有权或同步;能不共享就不共享
  • 异步须善后:异步 / 后台任务考虑取消、超时、幂等、资源释放,不留悬挂任务

设计原则(代码级)

SOLID + 迪米特六大原则的代码级/diff 级可机械判定特征。设计级判定(启发式阈值/三态结论表/ADR 联动)权威归 system-design solid-principles-guide.md,本节不替代。

| 原则 | 代码级判定特征 | |------|---------------| | SRP 单一职责 | 类/函数职责描述含"和/并且"等多职责连接词 | | OCP 开闭 | 新增类型靠修改已有 switch/if-else 分支扩展 | | LSP 里氏替换 | 子类/实现抛出父类(接口)契约外异常,或强化前置条件/弱化后置条件 | | LoD 迪米特 | 链式跨层调用 a.getB().getC().getD()(跨 >2 层;fluent API/builder 除外) | | ISP 接口隔离 | 单接口方法数 >7,或消费方使用比例 <50%(胖接口) | | DIP 依赖倒置 | 跨模块依赖出现具体实现类名而非接口 |

分级:DIP 违反为 [Blocker](与设计级硬约束对齐);其余五条为 [Suggestion](启发式,违反须说明理由)。

可测试性设计

可测试代码三要素(详细测试编写规范见 /testing-guide):

  1. 依赖可注入 —— 外部依赖通过参数/构造器传入,不硬编码
  2. 纯函数优先 —— 业务逻辑无副作用,相同输入相同输出
  3. 边界分离 —— 业务逻辑与 IO 分离

正反例见 references/mte-examples.md。

避免过度设计

  • YAGNI:不为假设需求添加配置/扩展点
  • Rule of Three:3 个以上实现才建接口(例外:跨模块边界 / 外部依赖 / 可测试性边界,为解耦可先建接口);重复 ≤3 处合规(第 3 处建议提取、不阻塞;<3 处禁止提前抽象),>3 处未提取 = [Blocker];3 个以上相似场景才建基类
  • 简单方案优先:简单场景不套复杂模式
  • 可选增强 · 专项复杂度审查:环境若提供专查过度工程的审查能力(如 /ponytail-review 审 diff、/ponytail-audit 审全仓),可在本节自查后追加一轮——它只找「该删什么」,与本 skill 的正确性 + 阈值审查互补。无该能力就止于本节清单,⛔ 不因缺它跳过或降低最小审查清单;其结论按本 skill 反馈分级归一化后再落审查报告,⛔ 不另立一套级别
  • 正反例见 references/mte-examples.md

设计模式使用

  • 必要时才用:解决实际问题,不为炫技
  • 说明理由:为什么选择这个模式
  • 保持一致:相同问题用相同模式

模式选择是设计时决策,场景→模式映射表权威见 system-design design-patterns.md(由 02-system-design §6 设计模式章节消费),本文件不镜像。

重构指导

安全约束(不可降):

  • [ ] 重构前必须有测试覆盖(无测试先补测试)
  • [ ] 每步重构后运行测试,小步前进
  • [ ] 不在重构中添加新功能,不在添加功能时重构
  • [ ] 单次重构只改一类问题

Code Smells 触发信号、风险评估、详细流程见 references/refactor-signals.md;系统性重构工作流(范围分析 + 测试门禁)用 /refactor。

Code Review

反馈分级

全仓反馈分级元语义(Blocker/Suggestion/Question/Nice 的含义与处置要求)以本表为权威;各审查场景(verification-flow / ui-quality-checklist / adversarial-review 等)只定义领域特定判定条目,不重定义级别含义。

| 级别 | 标记 | 含义 | 要求 | |------|------|------|------| | 阻塞 | [Blocker] | 必须修复才能合并 | 安全问题(含安全编码红线)、逻辑错误、核心阈值表超最大值、命名/注释/日志黑名单、错误吞异常/丢 cause/对外泄露内部、DIP 违反 | | 建议 | [Suggestion] | 建议修改但不阻塞 | 超建议值、代码风格、小优化 | | 疑问 | [Question] | 需要作者解释 | 不理解的设计决策 | | 赞 | [Nice] | 写得好的地方 | 鼓励好的实践 |

最小审查清单

  • [ ] 核心阈值表全部合规(函数/参数/嵌套/重复/单类)
  • [ ] 命名无黑名单命中(误导名/泛化名/同概念漂移/类型编码)
  • [ ] 注释无黑名单命中(变更日志式/对审查者说话/来源记录式/复述代码)
  • [ ] 设计原则(代码级)六条无命中
  • [ ] 依赖可注入、业务逻辑与 IO 分离
  • [ ] 无过度设计(YAGNI / Rule of Three)
  • [ ] 错误处理:不吞异常、保留 cause、对外不泄露内部(详见错误处理节)
  • [ ] 类型与数据契约:外部输入先校验入域、无 stringly-typed / 宽类型绕编译器
  • [ ] 日志:级别正确、含关联 id + 最小上下文、无 log-and-throw(命中安全红线即 Blocker,详见日志规范)
  • [ ] 安全编码红线:输入校验·参数化、鉴权在服务端、密钥/PII 不硬编码不输出(注入/XSS/越权 = Blocker)

反馈必须分级并说明理由;安全问题必须 [Blocker]。完整审查维度与输出格式见 references/review-rubric.md。

参考资料

| 文件 | 内容 | |------|------| | references/mte-examples.md | 模块/函数/可测试性/YAGNI 正反例代码 | | references/naming-examples.md | 命名正反例、大小写惯例、命名空间例外 | | references/refactor-signals.md | Code Smells 信号、重构流程、风险评估 | | references/review-rubric.md | Review 详细清单与输出格式 |