关于 clean-code
面向开发者的编码 Skill,强调代码易读、易维护,并避免为假设需求增加抽象。它提供从界定改动范围、选择简单实现到测试和交付前检查的工作流程。
主要功能
- 01将改动限定在请求范围内
- 02优先选择简单实现
- 03使用体现用途的命名
- 04保持函数职责单一
- 05测试行为与边缘情况
- 06交付前检查改动范围
适用场景
- 01审查拟议的代码改动
- 02实现范围明确的功能或修复
- 03重构时减少不必要的抽象
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ mindrally/ skills --skill clean-code安装后在 Claude Code 中输入/clean-code确认已加载。
详细介绍
整洁代码
这项技能涵盖如何编写易于阅读和修改的代码,以及同样重要的内容——避免以“最佳实践”之名过度设计,让代码更难阅读和修改。这两方面同样重要:整洁代码就是简洁的代码,而不只是装饰得很漂亮的代码。
编写或审查代码的工作流
- 明确变更范围 — 准确找出需求。动手之前,先记下哪些内容不在范围内。
- 优先尝试最简单的方案 — 优先采用直接、清晰的实现,而不是通用或可配置的方案,除非当前确有具体需求需要这样做。
- 根据用途命名 — 在编写函数主体或确定类型结构之前,选择能体现意图的名称。
- 让函数各司其职 — 如果需要用注释解释函数的作用,就拆分它。
- 有意识地消除重复 — 只有在确实出现重复之后才提取共用逻辑(参见下文的三次原则),不要提前处理。
- 编写或更新测试 — 覆盖新增行为及其引入的边缘情况。
- 交付前确认范围 — 确认只修改了需求涉及的代码,检查是否有更简单的方案,并确认没有触及未要求修改的文件。
有意义的名称
- 变量、函数和类的名称应该能直接体现其用途。
- 名称应该说明某项内容为何存在以及如何使用,而不只是描述其类型或内容(
activeUserIds,而不是list1)。 - 避免使用缩写,除非它们在相关领域中广为人知(
id、url可以;usrCfgTmp不行)。
用常量替代魔法数字
- 将硬编码的值替换为命名常量(
MAX_RETRY_COUNT = 3,而不是在后面的三个调用位置直接写3)。 - 使用能说明值的用途,而不只是描述值本身的常量名称。
- 将常量放在文件顶部;如果多个文件共用,则放在专用的常量模块中。
有用的注释
- 不要注释代码的作用;应通过命名和结构让代码自我说明。
- 使用注释解释为何要以某种方式实现,尤其是代码中看不出原因时(例如规避库的缺陷,或非显而易见的顺序要求)。
- 为公共 API、真正复杂的算法以及不明显的副作用编写说明。
单一职责
- 每个函数只做一件事。
- 函数应足够小且专注,无需滚动页面就能理解。
- 如果需要用注释解释函数的作用,就应该将它拆分为命名清晰的子函数。
DRY — 不要重复自己
- 只有在确实出现重复之后才将重复代码提取为可复用函数,不要预先设想重复。
- 通过恰当的抽象共享通用逻辑——使用共用函数或模块,而不是稍作修改后复制粘贴。
- 对每一项业务逻辑或配置值维护唯一事实来源。
封装
- 将实现细节隐藏在清晰的接口之后;调用方不应需要了解某项内容的工作原理才能使用它。
- 将嵌套条件逻辑移入命名清晰的函数或保护子句中,避免深层的
if/else嵌套。
// Before
function canCheckout(cart) {
if (cart.items.length > 0) {
if (cart.user.isVerified) {
if (cart.total <= cart.user.creditLimit) {
return true;
}
}
}
return false;
}
// After
function canCheckout(cart) {
const hasItems = cart.items.length > 0;
const isWithinCreditLimit = cart.total <= cart.user.creditLimit;
return hasItems && cart.user.isVerified && isWithinCreditLimit;
}
清晰的结构
- 将相关代码放在一起(某项功能的组件、钩子和样式应放在同一目录中,而不是按文件类型分散存放)。
- 按照对领域的理解,以合乎逻辑的层级组织代码。
- 在整个代码库中采用一致的文件和文件夹命名规范。
避免过度设计
- 只修改要求修改的内容。首先选择能满足需求的最简单方案。
- 如果不确定合适的抽象层级,请先询问,而不是猜测并选择更复杂的方案。
- 不要修改未要求修改的代码,即使它看起来可以改进也是如此——顺手重构无关函数会扩大审查范围和改动风险。
- 不要在没有明确、当前需求的情况下添加抽象(接口、工厂、插件系统、配置层)。单一实现不需要为了“以防”以后出现第二个实现而添加接口——这是投机性通用设计(YAGNI:“你不会需要它”)。
- 不要为了一个现有代码几行就能解决的问题引入新依赖。
- 小改动不要重写整个文件——与重写整个文件相比,有针对性的差异更容易审查,也更安全。
- 如果根据周边代码的保证,某些情况不可能发生,就不要为这些情况添加错误处理——针对不可能状态编写防御性代码会增加阅读成本,却不会提升安全性。
三次原则
- 某种模式第一次和第二次出现时,允许重复。
- 第三次出现时再提取抽象,此时共享逻辑的实际形态已经清晰——在只有一两个实例时就提取,往往会误判真正共享的内容。
过度设计的迹象
- 某个配置选项一直只被设为一个值。
- 某个接口只有一个实现,也没有需要第二个实现的测试替身。
- 一个通用的
options对象不断增加字段,只为满足假设中的未来调用方。 - 在还没有两种策略可供切换之前,就引入插件/策略模式。
代码质量维护
- 持续进行小步重构,而不是把清理工作推迟到专门的“重构冲刺”。
- 及早修复技术债务,此时你仍清楚代码为何如此编写。
- 在你正在处理的范围内,让代码比接手时更整洁——但这并不意味着可以重构无关文件。
测试
- 修复错误前先编写一个会失败的测试,以验证修复有效,并防止错误悄然复发。
- 保持测试易读、易维护——如果测试比被测代码更难理解,那它就没有完成自己的职责。
- 明确测试边界情况和错误条件,而不只是测试正常路径。
版本控制
- 编写清晰、具体的提交信息,说明为何进行这项更改。
- 将更改拆分为小而专注的提交——每个提交只包含一个逻辑上的更改。
- 使用能描述工作内容、而非作者或日期的有意义的分支名称。
交付前检查清单
- 只修改了要求修改的代码——没有触及无关文件。
- 没有在缺乏当前具体需求的情况下添加抽象。
- 没有添加与现有功能重复的依赖。
- 已考虑并排除了更简单的方案,而非直接跳过。
- 新行为有测试覆盖,其中至少包含一个边界情况。
评论
支持 Markdown