Clean Code技能使用说明
2026-03-28
新闻来源:网淘吧
围观:13
电脑广告
手机广告
代码整洁之道
应力求简洁、直接、聚焦解决方案。整洁的代码读起来应如优美的散文——每个名称都揭示意图,每个函数只做一件事,每个抽象都有其存在的价值。
安装
OpenClaw / Moltbot / Clawbot
npx clawhub@latest install clean-code
核心原则
| 原则 | 规则 | 实践检验 |
|---|---|---|
| 单一职责原则 | 单一职责——每个函数/类只做一件事 | “我能否在不使用‘并且’这个词的情况下描述它的功能?” |
| 不要重复自己原则 | 不要重复自己——提取重复内容,实现复用 | “我之前是否写过相同的逻辑?” |
| 保持简单原则 | 保持简单——采用可行的最简单解决方案 | “是否有更简单的方法来实现这个?” |
| 你不会需要它原则 | 你不会需要它——不要构建未使用的功能 | "现在有人需要这个吗?" |
| 童子军 | 离开时让代码比来时更整洁 | "修改后这个文件是否更好了?" |
命名规则
名称是最重要的文档。一个好的名字无需注释。
| 元素 | 惯例 | 差 | 好 |
|---|---|---|---|
| 变量 | 揭示意图 | n,d,tmp | userCount,elapsed,activeUsers |
| 函数 | 动词 + 名词 | user(),calc() | getUserById(),calculateTotal() |
| 布尔值 | 疑问句形式 | active,flag | isActive,hasPermission,canEdit |
| 常量 | SCREAMING_SNAKE | max,timeout | MAX_RETRY_COUNT,REQUEST_TIMEOUT_MS |
| 类 | 名词,单数形式 | Manager,Data | UserRepository,订单服务 |
| 枚举 | 帕斯卡命名法值 | '待处理'字符串 | 状态.待处理 |
规则:如果需要注释来解释一个名称,请重命名它。
命名反模式
| 反模式 | 问题 | 修复方法 |
|---|---|---|
晦涩的缩写 (用户管理器,配置) | 六个月后难以理解 | 拼写出来 —— IDE自动补全让长名称变得免费 |
通用名称 (数据,信息,项目,处理器) | 未说明用途 | 使用能揭示意图的领域特定名称 |
误导性名称 (getUserList返回一个用户) | 主动欺骗读者 | 使名称与行为匹配,或改变行为 |
匈牙利命名法 (strName,nCount,IUser) | 与类型系统冗余 | 让 TypeScript/IDE 显示类型;名称描述目的 |
函数规则
| 规则 | 指导原则 | 原因 |
|---|---|---|
| 小型 | 最多20行,理想情况下5-10行 | 装得进脑子 |
| 单一职责 | 专注一事,精益求精 | 可测试且可命名 |
| 单一抽象层级 | 每个函数保持单一抽象层级 | 自上而下清晰可读 |
| 精简参数 | 最多3个参数,建议0-2个 | 便于正确调用 |
| 无副作用 | 避免意外修改输入参数 | 行为可预测 |
卫语句
用提前返回来展平嵌套条件,嵌套深度不超过2层
// BAD — 5 levels deep
function processOrder(order: Order) {
if (order) {
if (order.items.length > 0) {
if (order.customer) {
if (order.customer.isVerified) {
return submitOrder(order);
}
}
}
}
throw new Error('Invalid order');
}
// GOOD — guard clauses flatten the structure
function processOrder(order: Order) {
if (!order) throw new Error('No order');
if (!order.items.length) throw new Error('No items');
if (!order.customer) throw new Error('No customer');
if (!order.customer.isVerified) throw new Error('Customer not verified');
return submitOrder(order);
}
参数对象
当函数需要超过3个参数时,使用配置对象
// BAD — too many parameters, order matters
createUser('John', 'Doe', 'john@example.com', 'secret', 'admin', 'Engineering');
// GOOD — self-documenting options object
createUser({
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'secret',
role: 'admin',
department: 'Engineering',
});
代码结构模式
| 模式 | 适用场景 | 优势 |
|---|---|---|
| 卫语句 | 在函数起始处处理边界情况 | 扁平化,可读性强的流程 |
| 扁平化优于嵌套化 | 任何超过2层的嵌套 | 降低认知负荷 |
| 组合 | 复杂操作 | 小型、可测试的片段 |
| 共置 | 跨文件的相关代码 | 易于查找和修改 |
| 提取函数 | 用注释分隔“部分” | 自文档化代码 |
组合优于全能函数
// BAD — god function doing everything
async function processOrder(order: Order) {
// Validate... (15 lines)
// Calculate totals... (15 lines)
// Process payment... (10 lines)
// Send notifications... (10 lines)
// Update inventory... (10 lines)
return { success: true };
}
// GOOD — composed of small, focused functions
async function processOrder(order: Order) {
validateOrder(order);
const totals = calculateOrderTotals(order);
const payment = await processPayment(order.customer, totals);
await sendOrderConfirmation(order, payment);
await updateInventory(order.items);
return { success: true, orderId: payment.orderId };
}
返回类型一致性
函数应返回一致的类型。对于多个结果,使用可辨识联合。
// BAD — returns different types
function getUser(id: string) {
const user = database.find(id);
if (!user) return false; // boolean
if (user.isDeleted) return null; // null
return user; // User
}
// GOOD — discriminated union
type GetUserResult =
| { status: 'found'; user: User }
| { status: 'not_found' }
| { status: 'deleted' };
function getUser(id: string): GetUserResult {
const user = database.find(id);
if (!user) return { status: 'not_found' };
if (user.isDeleted) return { status: 'deleted' };
return { status: 'found', user };
}
反模式
| 反模式 | 问题 | 修复 |
|---|---|---|
| 注释每一行 | 噪音掩盖信号 | 删除明显的注释;通过注释为什么,而不是什么 |
| 单行代码的辅助工具 | 不必要的间接性 | 内联代码 |
| 两个对象的工厂 | 过度工程化 | 直接实例化 |
工具文件(utils.ts)仅含一个函数 | 杂物抽屉文件 | 将代码放在使用它的地方 |
| 深层嵌套 | 难以理解的流程 | 防护子句和提前返回 |
| 魔法数字 | 意图不明确 | 命名常量 |
| 全能函数(上帝函数) | 难以测试、难以阅读 | 按职责拆分 |
| 已注释掉的代码 | 死代码混淆 | 删除它;Git 会记住 |
| TODO 蔓延 | 永远无法完成 | 在问题跟踪器中记录,而非代码中 |
| 过早抽象 | 错误的抽象比没有抽象更糟 | 等待出现3个以上重复项后再进行抽象 |
| 复制粘贴式编程 | 重复出现的错误 | 提取共享逻辑 |
| 异常驱动的控制流 | 缓慢且令人困惑 | 使用显式条件语句 |
| 字符串类型代码 | 拼写错误和遗漏的情况 | 使用枚举或联合类型 |
| 回调地狱 | 末日金字塔 | 使用 async/await |
编辑前安全检查
在更改任何文件之前,回答这些问题以避免连锁破坏:
| 问题 | 原因 |
|---|---|
| 哪些文件导入了此文件? | 接口变更可能导致依赖项失效 |
| 这个文件导入了什么? | 您可能需要更新契约 |
| 哪些测试覆盖了此功能? | 测试可能失败——请随代码同步更新 |
| 这是共享组件吗? | 多消费者意味着更广的波及范围 |
File to edit: UserService.ts
├── Who imports this? → UserController.ts, AuthController.ts
├── Do they need changes too? → Check function signatures
└── What tests cover this? → UserService.test.ts
规则:在同一任务中编辑文件及所有依赖文件。切勿遗留损坏的导入或缺失的更新。
完成前自检
在标记任何任务完成前,请验证:
| 检查 | 问题 |
|---|---|
| 目标达成? | 我是否严格按要求执行? |
| 文件已编辑? | 我是否修改了所有必要文件(包括依赖项)? |
| 代码可运行? | 我是否已验证变更可编译并运行? |
| 无报错? | 代码规范和类型检查是否通过? |
| 没有遗漏什么吗? | 有没有错过任何边界情况或依赖文件? |
绝对不要
- 绝对不要添加仅重复代码内容的注释——如果代码需要注释来解释其功能,那就重命名直到无需注释为止
- 绝对不要为少于3个用例创建抽象——过早抽象比重复代码更糟糕
- 绝对不要在代码库中留下被注释掉的代码——直接删除;版本控制系统就是用来记录历史的
- 绝对不要编写超过20行的函数——提取子函数,直到每个函数只做一件事
- 绝对不要让嵌套深度超过2层——使用保护子句、提前返回或提取函数
- 绝对不要使用魔法数字或字符串——定义具有清晰语义的命名常量
- 绝对不要在不检查其依赖关系的情况下编辑文件——在多文件变更中,导入中断和更新缺失是最常见的错误来源
- 绝不要留下未通过代码检查或类型检查的任务—— 在标记完成之前修复所有错误
参考资料
关于特定整洁代码主题的详细指南:
| 参考 | 描述 |
|---|---|
| 反模式 | 涵盖命名、函数、结构和注释的21个常见错误,附有劣质/优质代码示例 |
| 代码异味 | 经典代码异味目录,包含检测模式——臃肿体、面向对象滥用者、变更阻碍者、可丢弃物、耦合体 |
| 重构目录 | 包含重构前后示例及逐步操作要点的核心重构模式 |
文章底部电脑广告
手机广告位-内容正文底部


微信扫一扫,打赏作者吧~