mcpField
C
code-quality

code-quality

github.com/mthines开发2040 次安装1 天前更新
代码仓库

关于 code-quality

用于提升代码可读性、可维护性和务实性能的 skill,涵盖计划、编写、审查和简化模式。它结合通用规则与特定技术栈指南;可仅报告发现,也可在简化模式中应用选定的机械重构。

主要功能

  1. 01支持计划、编写、审查和简化模式
  2. 02提供语言无关的质量规则
  3. 03包含特定技术栈指南
  4. 04计划和审查模式仅报告发现
  5. 05简化模式应用选定重构

适用场景

  1. 01审查拟议的实现计划
  2. 02编写代码时落实可读性与可维护性原则
  3. 03审计代码或审查拉取请求
  4. 04测试通过后简化已实现的代码

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/mthines/agent-skills --skill code-quality

安装后在 Claude Code 中输入/code-quality确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
citations.md
quick-reference.md
rules/
abstraction.md
api-design.md
architecture.md
cognitive-complexity.md
collaboration.md
comments.md
control-flow.md
correctness.md
error-handling.md
functions.md
maintainability.md
naming.md
output-contract.md
performance.md
plan-mode.md
procedure.md
refactor-recipes.md
review-checklist.md
simplify-mode.md
testability.md
tradeoffs.md
rules/stacks/
README.md
rules/stacks/nextjs/
endpoints.md
rules/stacks/react/
autosave.md
components.md
data-fetching.md
offline-sync.md

详细介绍

代码质量技能

编写易于审查、理解和修改的代码。优先减轻下一位开发者的心智负担,再考虑机器性能,因为可读的代码更容易修改、调试,也更值得信任;而大多数性能提升都来自算法选择和性能分析,而非微优化。

此技能关注以下三个质量维度,按优先级排列:

  1. 可读性——读者首次阅读时就能从头到尾理解代码。
  2. 可维护性——为一个概念添加下一个变体,只需修改一个文件、一处内容;复用现有工具,而非重新发明;每个概念都有唯一的权威归属。
  3. 务实的性能——默认采用算法层面的优化,只有性能分析器指出需要时才进行微优化。

此技能适用于四种模式:

  1. 计划模式——在编写任何代码之前,通过 Skill("code-quality", "plan") 调用。读取 plan.md(或拟议方案)和现有代码库,检查计划的结构是否遵循现有模式,并规避可预见的设计阶段风险(过早使用并行映射、缺少带品牌类型的原始值、错误路径缺少类型、参数蔓延、邻近项不匹配)。仅返回发现的问题,不修改代码。由 autonomous-workflow 的第 1 阶段使用。参见 rules/plan-mode.md。
  2. 编写模式——编写新代码时(例如 TDD 的 GREEN 阶段、新功能)。在编写过程中应用原则,确保第一个版本就达到标准。未传入参数时的默认模式。
  3. 审查模式——代码编写完成后,通过 Skill("code-quality", "code") 或 Skill("code-quality", "review") 调用。进行重构、审查 PR,或收到“清理一下”的请求时使用。根据规则诊断问题并提出针对性的修改建议。仅返回发现的问题,不修改代码。
  4. 简化模式——功能实现且测试通过后,通过 Skill("code-quality", "simplify") 调用。先执行审查,然后在 Skill("confidence", "code") ≥ 90 % 且通过范围限定的快速检查后,逐项应用机械式重构(rules/refactor-recipes.md 中的 M 类方案);失败时回滚。判断类方案(J 类)仅作为建议。参见 rules/simplify-mode.md。变体:simplify aggressive 还会自动应用影响中等的机械式方案;simplify dry-run 只报告,不写入;simplify <path> 将范围限定为指定路径,而非差异内容。

根据 $ARGUMENTS 的第一个词元判断模式:plan → 计划模式;code 或 review → 审查模式;simplify → 简化模式;其他任何内容(包括无参数)→ 编写模式。旧约定“用户说了 review 或 audit”仍会在临时调用时路由到审查模式。


核心主张

认知复杂度——代码有多难理解——是衡量长期可维护性的最佳单一指标。SonarSource 的研究表明,圈复杂度(路径计数)忽略了真正让人头疼的因素:嵌套、线性流程被打断,以及相互叠加的决策。因此,下列规则关注的是认知负担,而非理论复杂度分数。完整引用文献(SonarSource、Clean Code、Knuth、Alexis King、Gary Bernhardt)及每条规则的研究依据见 references/citations.md。

拿不准时,可以用这个启发式问题:读者能否不回头查看,一遍从头到尾理解这个函数? 如果可以,就提交。如果他们必须滚动查看、跳转,或在脑中记住一串条件,就应该修正。

可维护性方面对应的问题是:如果我要为这个概念添加下一个显而易见的变体,需要修改多少个文件?如果漏掉一处,类型系统能否发现? 在一个文件中实现并获得完整类型覆盖是很好的做法;而在四个文件中手动同步四张映射表则属于散弹式修改——应先修正结构,再添加变体。参见 rules/maintainability.md。

快速参考(将这些模式加载到工作记忆中)

坏味道重构为原因
嵌套的 if(3 层以上)守卫子句 + 提前返回每增加一层缩进,心智负担就会增加;扁平结构更容易理解
函数过长(50 行以上,承担多项职责)按意图提取,并按“做什么”而不是“怎么做”命名一个函数 = 一个变更理由
含义晦涩的名称(d、tmp、data)领域名词(priceDifference、pendingOrders)名称就是文档
布尔参数两个有明确名称的函数或一个枚举send(true, false, true) 难以理解
解释“做了什么”的注释重命名或提取函数注释会过时;名称会随代码一起重构
解释“为什么”的注释(针对不明显的约束)保留这是唯一值得保留的注释
针对不可能状态的防御性检查删除信任调用方;在边界处验证
标志/选项参数簇(4 个以上参数)对象参数或构建器工作记忆大约只能容纳 4 个信息块
return/throw 之后的 else删除 else线性流程优于分支
魔法数字/字符串命名常量未来的你不会记得 7 代表什么
针对同一联合类型(以 Status 为键)的并行映射(LABELS、COLORS、ICONS)一个 Record<Status, { label, color, icon }>添加一个变体只需修改一处,而非 N 处
重新实现已有的辅助函数先搜索;使用现有函数两种实现会逐渐偏离;只修复其中一个副本里的 bug
根据某个值分派的 if/else if 链查找表或单一事实来源记录数据结构优于控制流;易于扩展
在多个文件中重复定义同一常量(MAX_RETRIES、状态字符串)提取到一个共享模块中一个概念,一个归属处
添加一个新变体需要修改 4 个以上文件添加变体之前先整合每增加一个变体,散弹式修改都会进一步加剧
为同一形状分别定义 type User = {...} 和 userSchema = z.object({...})使用一个 schema;type User = z.infer<typeof UserSchema>两份声明会逐渐偏离;一份声明则不会
在调用栈深处重复验证已解析的值在边界处解析一次;内部信任类型验证是边界问题,而不是每次调用都要处理的问题
为了“整洁”而把每个嵌套对象都拆成独立的子 schema除非子形状会被复用或有自己的边界,否则保持扁平过早拆分;过度设计
函数混合编排语句与底层细节按抽象层级提取(R16)读者只需关注自己关心的层级
用运行时检查强制规定“这两个字段不能同时设置”使用判别联合(R15)由编译器强制执行不变量;运行时检查也随之消失
Email、UserId、OrderId 使用原始 string 类型通过 schema 为类型添加品牌(R11)混用 ID 会成为编译错误
使用 any 或无正当理由的类型断言来绕过类型检查器使用 schema 解析、收窄后的 unknown,或 // because: 注释(R17)类型 bug 最常见的形式就是无正当理由的 any
函数直接调用 Date.now()/Math.random()注入时钟/随机数生成器(R9)纯函数可测试;非纯函数容易导致测试不稳定
函数因“未找到”而抛错,或返回哨兵值(-1、"")将函数设计为全函数:返回 null 或 Result<T, E>(R10)可以穷尽测试全函数
每个错误都抛出相同的 Error,再从消息中解析信息使用判别联合 AppError(R12)结构化字段优于解析字符串
导入模块会触发副作用使用工厂函数:createX(...)(R20)测试不再意外变成集成测试
可能重试的操作无法安全地调用两次使用幂等键、upsert 或正确的 HTTP 方法(R18)否则重试会破坏状态
以 number 存储金额使用整数最小货币单位或十进制库(R19)浮点数无法精确表示十进制货币
用 === 比较浮点数使用 epsilon 比较,或使用整数刻度0.1 + 0.2 !== 0.3
在本应使用 Promise.all 的 for 循环中使用 await有意识地选择串行或并行意外串行化是性能 bug
每次 open 后都没有对应的 close使用 try/finally 或 using资源泄漏会在不知不觉中不断累积
新文件的模式与相邻文件不一致阅读 2–3 个相邻文件并模仿其模式特例代码会迫使每位读者频繁切换上下文
将重构 PR 与功能 PR 混在一起拆分成两个 PR混合 PR 要么被敷衍批准,要么因不相关的理由被拒绝
辅助函数放在文件顶部,公共函数却在 200 行之后公共接口放在前面;辅助函数按调用顺序放在后面文件是从上到下阅读的
为操作 a 而一路访问 a.b.c.d.method()告诉对象做什么,而不是询问对象:将操作放到 a 上调用方不应遍历私有结构
技术栈重点模式

以下是一些影响最大的技术栈专属规则。rules/stacks/ 下的每个规则文件都包含自己的“常见错误”部分——在对应技术栈中工作时加载该文件。

问题模式重构为位置
React 组件有 6 个或更多属性(尤其是布尔值属性)来控制视觉变化使用深层点号表示法的复合组件(Combobox.Content.List.Item)+ 命名空间控制 Hook(Combobox.useCombobox);通过 Context 共享状态stacks/react/components.md
使用 useEffect(() => { fetch(...).then(setData) }, [id]) 获取服务端数据使用 useQuery({ queryKey, queryFn })(TanStack Query / SWR)stacks/react/data-fetching.md
Mutation 等待服务端响应后才更新 UI在 onMutate 中乐观更新,在 onError 中回滚,在 onSettled 中使缓存失效stacks/react/data-fetching.md
表单每输入一个字符就保存添加约 1000 ms 的防抖 + 最长等待约 5 秒后刷新 + 失焦时保存 + 页面可见性变为隐藏时保存;绝不阻塞输入stacks/react/autosave.md
两个标签页自动保存同一条记录,其中一个静默覆盖另一个使用 ETag + If-Match;遇到 412 时显示“已在其他位置编辑——重新加载 / 保留我的更改”stacks/react/autosave.md
重新加载后 Mutation 丢失,临时重试逻辑散布在各个组件中在 IndexedDB 中使用持久化 Mutation 队列 + 为每个条目设置幂等键;通过 navigator.locks 实现多标签页单写入者stacks/react/offline-sync.md
路由处理程序在未经验证的情况下信任 req.json() 请求体使用共享 Zod Schema 进行 safeParse(FE + BE 导入同一个模块);从判别式 AppError 联合类型映射到统一的错误封装stacks/nextjs/endpoints.md

流程

此技能有四种模式——计划(验证计划)、编写(编写新代码)、审查(重构 / 审计,仅报告发现的问题)和简化(先审查,再自动应用机械化方案)。根据上表从 $ARGUMENTS 判断模式;默认为编写模式。

编写模式(13 步检查清单)和审查模式(8 步检查流程)请加载 rules/procedure.md。简化流程请加载 rules/simplify-mode.md(划分 → 置信度门槛 → 一次应用一个方案 → 作用域内快速检查 → 失败时还原 → 最后验证整个测试套件)。


规则文件

只加载与当前代码相关的内容。每次都阅读所有规则文件只会浪费上下文。该技能的核心与语言无关——下表分为框架无关规则和技术栈专属扩展。只有代码属于某个技术栈时,才加载对应的技术栈文件。

语言无关规则
当代码涉及……加载
条件语句、分支、嵌套rules/control-flow.md
长函数或多用途函数rules/functions.md
变量、函数、类的名称rules/naming.md
注释、文档字符串、文档rules/comments.md
性能问题或热点路径rules/performance.md
错误处理、验证、防御性代码、模式优先验证、Zod / Pydantic、从模式推断类型rules/error-handling.md
审查现有代码rules/review-checklist.md
认知复杂度评分rules/cognitive-complexity.md
带关联数据的联合类型、并行映射、重复常量、“应该放在哪里”、复用决策rules/maintainability.md
抽象层级、类型驱动设计、确保非法状态无法表示、品牌原语、泛型、any/类型断言的使用规范rules/abstraction.md
模块边界、公开接口、依赖方向、函数式核心 / 命令式外壳、DTO ↔ 领域 ↔ 持久化、默认不可变性、有副作用的导入rules/architecture.md
函数签名、参数顺序、全函数、缺失值建模、错误类型系统设计、告诉而非询问、文件阅读顺序rules/api-design.md
幂等性、金钱 / 十进制数 / 浮点数、日期和时间、标识符、编码、确定性、断言、异步 / 并发、资源管理rules/correctness.md
难以测试的代码、注入时钟 / RNG / ID 作为依赖、何时调用 tdd 技能、无需 data-testid 即可通过角色 / 标签定位的 UI 组件rules/testability.md
PR 范围、相邻模式对称性、迁移与演进、处理遗留代码、差异整洁度rules/collaboration.md
在审查输出中命名重构(R1 合并并行映射、R6 将类型声明替换为推断类型等)rules/refactor-recipes.md
在功能开发结束时自动应用机械式重构(先审查再应用、按置信度决定、失败时还原)rules/simplify-mode.md
特定技术栈的规则

索引及添加新技术栈的约定,请参阅 rules/stacks/README.md。

技术栈当代码涉及……加载
React / Next.js任何 UI 文件(*.tsx、*.jsx、React Native 屏幕)——语义化 HTML、ARIA、符合 WCAG 2.2、焦点顺序、对比度、平台指南(Apple HIG、Material Design 3)Skill('ux')(单独的技能)
React拆分组件、复合 / 命名空间组件(Component.List.Item、Component.useComponent)、插槽、RSC 边界rules/stacks/react/components.md
React客户端数据获取、服务端状态、查询缓存、乐观更新、缓存修改(创建 / 更新 / 删除)、查询键、请求瀑布、TanStack Query / React Query / SWR、Next.js App Router 预取、HydrationBoundary、dehydrate、initialData、每请求一个 QueryClientrules/stacks/react/data-fetching.md
React表单自动保存、防抖 + 最大等待时间刷新、失焦 / 可见性 / pagehide 触发器、本地优先的草稿缓冲区(localStorage / IndexedDB)、带 ARIA 实时区域的状态指示器、ETag / If-Match 冲突检测、使用幂等 PATCH 的离线重试(表单基础知识交由 /ux 处理)rules/stacks/react/autosave.md
React全应用离线 + 同步、IndexedDB 中持久化的变更队列 / outbox、前台队列与 Background Sync、TanStack Query networkMode + 持久化 + resumePausedMutations、幂等键、重新连接流程、冲突解决、多标签页协调(navigator.locks + BroadcastChannel)rules/stacks/react/offline-sync.md
Next.js服务端端点、Route Handlers / Server Actions、Zod 边界验证、共享 Schema / 契约(前端 + 后端)、API 错误封装、HTTP 状态映射、身份验证 + 速率限制顺序、请求 ID、为整个处理函数添加带有 semconv 属性的 Span(深入内容交由 /otel-instrumentation + /otel-semantic-conventions 处理)rules/stacks/nextjs/endpoints.md

关键规则(始终适用)

这些规则不可妥协,因为它们反映的是人类认知的局限,而非风格偏好。

1. 线性流程胜过分支

自上而下执行的函数——先做守卫检查,再处理逻辑,最后返回——总是比有深层分支的函数更容易理解。如果 if/else if/else 跨越了 30 行,就应重构。

2. 名称承载主要信息

代码被阅读的次数是编写次数的 10 倍。一个能说明意图的 30 个字符长的名称,节省的时间远超输入它所花费的时间。反过来说,在含义可从上下文中明确判断的紧凑作用域中(循环索引、数学公式),单字母名称也完全可以。

3. 函数只描述一件事

函数名应完整描述它的功能。如果诚实的命名是 validateAndPersistAndNotifyUser,那你就有三个函数。

4. 不要为尚未出现的未来需求提前构建

针对假设性需求的配置参数、抽象层和功能标志,今天只会增加认知负担,在需求真正出现前毫无益处——而大多数需求永远不会出现。先针对眼前的情况构建;等第二种情况出现时再重构。

5. 注释解释原因,而非内容

重复代码内容的注释只是噪声。记录不明显的约束、微妙的不变量,或“我们试过 X,但因为 Y 而失败”的注释则非常宝贵。如果你想写注释,先试着重命名或提取代码,直到代码本身能表达清楚。

6. 测量后再优化

Knuth:“过早优化是万恶之源。”在分析器指出热点路径之前,优先选择易读的写法。只有约 3% 的代码会影响性能;其余 97% 的代码应优先便于人类阅读。

7. 在边界处验证,在内部信任

在边界处验证用户输入、外部 API 响应和不可信数据。不要在内部代码中到处添加防御性空值检查——它们会悄悄吞掉不可能出现的状态,从而掩盖真正的错误。如果某个值在代码的此处不可能为 null,就不要假装它可能为 null。

8. 创建之前先复用

编写辅助函数、类型、常量或格式化器之前,先在代码库中查找是否已有可复用的实现。同一概念的第二种实现比第一种更糟——行为会逐渐偏离,错误只会在其中一个副本中修复,后续读者也不知道哪一个才是规范实现。复用现有代码永远不会过早。

9. 联合类型元数据只保留一个真实来源

当联合类型或枚举有关联数据(标签、颜色、图标、标志、默认值)时,应将其放在一个以该联合类型为键、值为结构化数据的记录中,而不是放在 N 个并行映射中。添加新变体必须只需修改一处,并且类型系统必须能在遗漏字段时捕获错误。针对 OrderStatus 手动同步的四个映射迟早会酿成错误。

10. 尽量缩小改动范围

可维护的改动只涉及少量文件,并且所有文件都经过类型检查。添加某个概念的新变体之前,先问自己:“如果再添加一个,我需要修改多少处?如果漏改一处,编译器会告诉我吗?”如果答案是“很多处”或“不会”,就先重构——通常可以合并并行映射、提取重复的常量,或将数据与相关操作放在一起。参见 rules/maintainability.md §3。

11. 让非法状态无法表示

发现错误最便宜的地方,就是错误无法存在的地方。将约束纳入类型系统:状态机使用可辨识联合类型,使用带有 assertNever 的穷尽式 switch、品牌原始类型、精化类型(NonEmptyArray<T>)。类型系统本可强制执行的运行时检查只是会逐渐偏离的噪声。参见 rules/abstraction.md §2。

12. 纯核心,不纯外壳

决策逻辑应保持纯粹:不执行 I/O、不依赖时间、不使用随机数或全局状态。副作用应放在边缘的薄外壳中。纯代码最容易测试和推理;不纯代码虽不可避免,但应足够精简,以便通过集成测试验证。注入时钟、随机数生成器、获取器和 ID 生成器,而不是直接调用它们。参见 rules/architecture.md §3 和 rules/correctness.md §7。

13. 使用全函数,不要用抛错表示缺失

当每个输入都有确定的输出时,函数就是全函数。对于按设计缺失的值,返回 null;对于预期的失败,返回 Result<T, E>;仅在程序员错误和意外 I/O 失败时使用 throw。哨兵值(-1、""、0)会骗人——每个哨兵值都可能与下一个调用方遇到的真实值冲突。参见 rules/api-design.md §4。

14. 新代码先写测试

编写新函数、模块或行为时,调用 tdd 技能(Skill('tdd')),通过严格的 RED → GREEN → REFACTOR 循环推动实现。在 GREEN 阶段默默应用此技能中的规则;在 REFACTOR 阶段明确应用。仅在简单修改、重构现有代码或用户选择退出时,才跳过交接。参见 rules/testability.md。

15. UI 文件应与 ux 配合

编写或审查用于渲染 UI 的文件(*.tsx、*.jsx、*.vue、*.svelte、React Native 屏幕)时,调用 ux 技能(Skill('ux')),检查 WCAG 2.2、语义化 HTML 和平台指南。无障碍内容归 ux 负责,不在此处处理——本技能会交由其处理。应用 rules/testability.md 中有关定位器稳定性的部分(UI Testability 章节),确保无障碍名称也能提高 E2E 测试的稳定性。仅在文件与 UI 无关,或纯重构且不涉及标记时跳过。在 autonomous-workflow 第 3 阶段调用时,ux 会直接在该阶段运行——不要重复调用;遵循该阶段的调用即可。


冲突处理

当原则彼此冲突时,加载 rules/tradeoffs.md 作为权衡依据(可读性与性能、DRY 与清晰度、复用与过早抽象、简短与清晰的命名、守卫子句与单一返回、就近放置与分层文件夹)。


输出规范

在评审模式下,请将发现整理为 ## Code Quality Review: [target] 区块,并按高 / 中 / 低影响分节;如果评审代码引入或扩展了联合类型、枚举、共享常量或实用工具,还必须提供可维护性方面的发现;如果涉及可重试操作、金额、日期、异步 I/O、资源句柄或非平凡的纯逻辑,还必须提供正确性 / 可测试性方面的发现。加载 rules/output-contract.md 查看完整模板。

在编写模式下,只需编写代码(新代码可先交由 tdd 处理)。默默应用这些原则。不要逐一解释每个守卫子句——用户会在差异中看到整洁的代码。

评论

支持 Markdown