mcpField
C
clean-code

clean-code

github.com/wondelai开发2.5k6.7k 次安装7 周前更新
代码仓库

关于 clean-code

clean-code 是面向编写、审查和重构代码的开发技能,重点在于可读性与可维护性。它涵盖命名、函数、错误处理、测试和代码异味,并提供评分方法来找出改进方向。

主要功能

  1. 01表达意图的命名原则
  2. 02专注型函数设计
  3. 03注释与格式指导
  4. 04错误处理实践
  5. 05单元测试原则
  6. 06代码异味诊断

适用场景

  1. 01审查拉取请求的代码清晰度
  2. 02重构难以阅读的函数
  3. 03评估测试与错误路径质量

安装

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

$npx skills add https://github.com/wondelai/skills --skill clean-code

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

包含的文件

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

references/
code-smells.md
comments-formatting.md
error-handling.md
functions-and-methods.md
naming-conventions.md
testing-principles.md

详细介绍

Clean Code Framework

一种严谨的代码编写方法,让代码清晰表达意图、尽量减少意外,并乐于拥抱变化。在编写新代码、审查拉取请求、重构旧系统或提供代码质量建议时,应用这些原则。

核心原则

代码被阅读的次数远多于编写的次数——应以读者为先。 阅读与编写的比例远高于 10:1,因此每个命名选择、函数边界和格式决定,要么提升清晰度,要么增加成本。整洁的代码读起来就像行文优美的文字:名称揭示意图,函数一步步讲述一个故事,并且遵循童子军规则——离开时总要让代码比接手时更整洁。

评分

目标:10/10。 根据以下原则,为任意代码打 0–10 分。报告当前得分,以及达到 10/10 所需的具体改进。

  • 9–10: 名称清晰表达意图,函数短小而专注,错误处理一致,测试整洁且全面
  • 7–8: 整体整洁,仅有轻微命名歧义或少数过长函数;测试可能缺少边界情况
  • 5–6: 优缺点并存——既有良好模式,也存在名称不清、逻辑重复或错误处理不一致的问题
  • 3–4: 函数过长且职责繁多,名称具有误导性,测试质量差或缺失
  • 1–2: 几乎无法阅读——充斥魔法数字和晦涩缩写,没有结构,也没有测试

Clean Code Framework

六项准则,让代码清晰表达意图并适应变化:

1. 有意义的名称

核心概念: 名称应揭示意图、避免误导,并让代码读起来像行文。如果一个名称需要注释解释,那它就不合适。

为何有效: 名称是最普遍的文档形式——恰当的名称让人无需阅读实现便能理解;糟糕的名称则迫使每位读者反向推断意图。

关键见解:

  • 名称应说明它为何存在、做什么以及如何使用
  • 不要使用编码、前缀或类型信息(不要使用匈牙利命名法);只有在作用域极小的循环计数器中才使用单字母名称
  • 类使用名词;方法使用动词
  • 一个概念使用一个词:不要混用 fetch、retrieve 和 get
  • 作用域越大,名称就应越长、越具体
  • 随时重命名——IDE 让这件事轻而易举

代码应用:

上下文模式示例
变量揭示意图用 elapsedTimeInDays,而不是 d
布尔值使用谓语表达isActive、hasPermission、canEdit
函数动词 + 名词用 calculateMonthlyRevenue(),而不是 calc()
类以名词命名职责用 InvoiceGenerator,而不是 InvoiceManager

重命名或审查名称时,请参阅 references/naming-conventions.md——其中包含各语言的约定、易读易搜的命名对照表,以及修改前后的示例。

2. 函数

核心概念: 函数应当小巧、专注于一件事并把它做好——理想情况下为 4–6 行、零到两个参数,以及一个抽象层级。

有效原因: 小巧且用途单一的函数易于命名、理解、测试和复用;过长的函数会隐藏错误、难以测试,还会积累各种职责。

关键要点:

  • 逐步深入规则:代码自上而下阅读,每个函数依次调用下一个抽象层级的函数
  • 参数数量:零个最佳,一个可以接受,两个尚可,三个及以上需要说明理由
  • 标志参数是异味——说明函数做了两件事;应拆分函数
  • 命令-查询分离:要么改变状态,要么返回值,不能两者兼做
  • 能拆就拆:只要能提取出一个命名函数,就去做
  • 不要有隐藏的副作用——函数名必须如实说明全部行为

代码应用:

场景模式示例
函数过长提取命名步骤validateInput(); transformData(); saveRecord();
标志参数拆分为两个函数renderForPrint() / renderForScreen(),而不是 render(isPrint)
错误情况在开头使用保护子句遇到错误时提前返回,保留单一正常路径
参数过多引入参数对象new DateRange(start, end),而不是 report(start, end, format, locale)
副作用明确说明影响checkPassword() 会启动会话 → 重命名或拆分

拆分过长函数时,请参阅 references/functions-and-methods.md,了解参数数量规则、命令-查询分离和逐步深入的示例。

3. 注释与格式

核心概念: 注释说明你没能在代码中表达清楚的内容。必要时,注释应解释为什么,而不是是什么。格式能构建清晰的视觉结构,让代码易于浏览。

有效原因: 注释会过时——代码变了,注释却常常没变,最终形成比没有文档更糟糕的文档。整洁的格式让开发者能像读报纸一样浏览代码:先看标题,需要时再看细节。

关键要点:

  • 最好的注释是一个命名恰当的提取函数
  • 可以接受的注释:法律声明、TODO、公共 API 文档,以及真正解释“为什么”的说明
  • 删除注释掉的代码和日志式注释——版本控制会记住这些内容
  • 不同概念之间留出垂直空白,概念内部保持垂直紧凑;在变量使用附近声明变量
  • 报纸比喻:文件顶部放置高级函数,细节放在下方

代码应用:

场景模式示例
解释“是什么”换成更好的名称// check if eligible → isEligible()
解释“为什么”保留为注释// RFC 7231 requires this header for proxies
注释掉的代码删除相信版本控制
团队格式规范一次定好,自动执行Prettier、Black、gofmt

决定一条注释是否值得保留时,请参阅 references/comments-formatting.md,了解好注释与坏注释的示例集和垂直格式规则。

4. 错误处理

核心概念: 错误处理是独立于业务逻辑的一项关注点。使用异常而不是返回码,为每个异常提供上下文,并且绝不返回或传递 null。

为何有效: 返回码会让成功路径充斥检查;异常则能清晰地将两者分开。返回 null 会迫使每个调用方都进行 null 检查,而一处遗漏就会导致错误在距离源头很远的地方发生。

关键要点:

  • 先编写 try-catch — 它定义了事务边界
  • 优先使用非受检异常 — 受检异常会违反开闭原则
  • 根据调用方的需求定义异常类,而不是根据失败类型
  • 不要返回 null(使用空集合、Optional 或抛出异常);也不要传递 null
  • 特例 / Null Object 模式:返回具有默认行为的对象,而不是 null

代码应用:

上下文模式示例
返回 null空集合或 Optionalreturn Collections.emptyList(),而不是 return null
错误码替换为异常throw new InsufficientFundsException(balance, amount)
第三方 API使用适配器封装PortfolioService 封装供应商 API,并转换其异常
特殊情况Null Object 模式使用具有默认行为的 GuestUser,而不是进行 null 检查
错误上下文包含操作 + 状态"Failed to save invoice #1234 for customer 'Acme'"

设计异常或 null 策略时,请参阅 references/error-handling.md — 其中包含特例模式和第三方 API 封装示例。

5. 单元测试

核心概念: 测试是一等代码,应以与生产代码相同的规范保持整洁。脏乱的测试比没有测试更糟糕 — 它们会成为负担,拖慢每一次变更。

为何有效: 整洁的测试是可执行文档,也是重构的安全网;脏乱的测试会让每次修改都变成与难以理解的测试代码搏斗。

关键要点:

  • TDD 三定律:先编写一个失败的测试;只编写足以让测试失败的测试;只编写足以让测试通过的代码
  • 每个测试只验证一个概念 — 一个逻辑断言,不一定只有一个 assert
  • F.I.R.S.T.:快速(Fast)、独立(Independent)、可重复(Repeatable)、自验证(Self-validating)、及时(Timely)
  • 构建领域专用测试语言:让辅助函数读起来像 DSL
  • 像重构生产代码一样随时重构测试代码

代码应用:

上下文模式示例
测试结构Arrange-Act-Assert准备、执行、验证 — 清晰分离
测试命名场景 + 预期行为shouldRejectExpiredToken,而不是 test1
共享设置Builder / 工厂辅助函数aUser().withRole(ADMIN).build()
不稳定的测试移除外部依赖模拟时间、网络、文件系统

编写或清理测试时,请参阅 references/testing-principles.md — 其中详细介绍 TDD 定律、F.I.R.S.T. 原则和整洁测试模式。

6. 代码异味与启发式规则

核心概念: 异味是更深层设计问题的表面迹象——学会快速识别它们,并采取有针对性的重构,而不是含糊地“清理”。

为何有效: 异味是无需深入分析便能指向可能问题的启发式规则,能将代码审查的直觉转化为具体、可重复的行动。

关键要点:

  • 函数异味:参数过多、输出参数、标志参数、无用函数
  • 常见异味:重复代码、抽象层次不当、特性依恋、魔法数字
  • 测试异味:覆盖不足、跳过测试、未测试边界条件和失败路径
  • 以小步、经过测试的方式重构——绝不要同时重构和添加功能
  • 童子军规则:让代码比你发现它时更整洁

代码应用:

场景模式示例
重复代码提取共用逻辑通用验证 → validateEmail() 辅助函数
特性依恋将方法移至数据所属的类中order.calculateTotal() 而不是 calculator.total(order)
无用代码删除移除未使用的函数、不可达的分支
魔法数字使用命名常量MAX_LOGIN_ATTEMPTS = 5,而不是直接写 5
霰弹式修改整合相关变更将分散的逻辑归并到单个模块中

遇到难以命名的异味时,请参阅 references/code-smells.md——其中按类别列出了完整目录,并为每种异味配有针对性的重构方法。

常见错误

错误失败原因修正方法
缩写名称写起来省几秒,读起来却要花几小时使用完整且有描述性的名称;IDE 会提供自动补全
“巧妙”的单行代码写起来很炫,调试起来却不可能展开为易读且命名清晰的步骤
用注释代替重构注释会过时;代码才是真相提取一个命名清晰的函数来代替
捕获通用异常连同预期错误一起吞掉程序缺陷捕获特定异常;让其他异常继续传播
错误路径没有测试正常路径可用,边缘情况却会崩溃测试每个分支、边界和失败模式
过早优化为微小收益掩盖代码意图先写整洁的代码;再优化经测量确认的瓶颈
上帝类一个 2000 行的类包办所有事情应用 SRP——按职责拆分
没有测试就重构回归问题没有安全网先编写表征测试
约定不一致每个文件都像来自不同的代码库统一风格;使用 linter 和格式化工具强制执行
到处返回 null空值检查像病毒一样蔓延使用 Optional、空集合或 Null Object

快速诊断

问题如果否行动
不读函数体也能理解每个函数吗?名称没有表达意图重命名,以描述其功能
所有函数都少于 20 行吗?函数做了太多事情将子操作提取为命名清晰的辅助函数
没有注释掉的代码块吗?无用代码造成困惑删除——版本控制中有历史记录
错误处理与业务逻辑分开了吗?try-catch 使主流程杂乱提取处理程序;优先使用异常而不是返回码
每个类都只有单一职责吗?类累积了互不相关的职责拆分为职责明确、命名清晰的类
每个公共方法都有测试吗?变更没有安全网继续修改前先添加测试
测试名称能描述行为吗?难以理解失败原因重命名为 shouldDoXWhenY
重复代码不超过 3 处吗?复制粘贴会传播缺陷提取共用逻辑(§6)
魔法数字都已命名为常量吗?原始值隐藏了意图为常量命名(§6)
所有测试都能在 10 秒内运行完吗?慢速测试不会被运行模拟外部依赖;拆分集成测试

延伸阅读

基于 Robert C. Martin 关于软件工艺的经典指南:

关于作者

Robert C. Martin(“Uncle Bob”) 自 1970 年起从事编程工作,是《敏捷宣言》的共同作者,并创立了 Uncle Bob Consulting 和 Clean Coders。他的著作——Clean Code、The Clean Coder、Clean Architecture 和 Clean Agile——塑造了整整一代开发者对代码质量的看法。他的核心主张是,想要加快速度,唯一的办法就是把事情做好。

评论

支持 Markdown