介绍
# Clean Code
> 保持**简洁、直接且以解决方案为重心**。整洁的代码读起来就像优美的散文——每个名称都揭示意图,每个函数只做一件事,每个抽象都各得其所。
## 安装
### OpenClaw / Moltbot / Clawbot
```bash npx clawhub@latest install clean-code ```
---
## 核心原则
| 原则 | 规则 | 实践检验 | |-----------|------|----------------| | **SRP** | 单一职责——每个函数/类只做一件事 | “我能不能不使用‘和’字来描述它是做什么的?” | | **DRY** | 不要重复自己(Don't Repeat Yourself)——提取重复项,复用代码 | “我以前写过这个逻辑吗?” | | **KISS** | 保持简单(Keep It Simple)——最简单的可行方案 | “有没有更简单的方法来实现这一点?” | | **YAGNI** | 你不会需要它(You Aren't Gonna Need It)——不要构建未使用的功能 | “现在有人需要这个吗?” | | **童子军** | 离开时比你来时更整洁 | “我的修改是否让这个文件变得更好了?” |
---
## 命名规则
名称是最重要的文档。好的名称可以消除对注释的需求。
| 元素 | 约定 | 坏示例 | 好示例 | |---------|------------|-----|------| | **变量** | 揭示意图 | `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`, `OrderService` | | **枚举** | PascalCase 值 | `'pending'` 字符串 | `Status.Pending` |
> **规则:** 如果你需要用注释来解释一个名字,请重命名它。
### 命名反模式
| 反模式 | 问题 | 修正 | |--------------|---------|-----| | 晦涩的缩写(`usrMgr`, `cfg`) | 六个月后无法阅读 | 拼写完整——IDE 自动补全让长名字免费 | | 通用名称(`data`, `info`, `item`, `handler`) | 不能说明用途 | 使用能揭示意图的领域特定名称 | | 误导性名称(`getUserList` 只返回一个用户) | 主动欺骗读者 | 让名称与行为匹配,或者改变行为 | | 匈牙利命名法(`strName`, `nCount`, `IUser`) | 与类型系统冗余 | 让 TypeScript/IDE 显示类型;名称描述用途 |
---
## 函数规则
| 规则 | 指导方针 | 原因 | |------|-----------|-----| | **短小** | 最多 20 行,理想情况下 5-10 行 | 适合在脑海中构思 | | **只做一件事** | 做一件事,并做好 | 可测试且可命名 | | **一层抽象** | 每个函数只有一个抽象层级 | 自上而下可读 | | **少参数** | 最多 3 个参数,首选 0-2 个 | 易于正确调用 | | **无副作用** | 不要意外修改输入 | 行为可预测 |
### 卫语句(Guard Clauses)
使用提前返回展平嵌套的条件语句。嵌套永远不要超过 2 层。
```typescript // 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 个参数时,使用选项对象。
```typescript // BAD — too many parameters, order matters createUser('John', 'Doe', '[email protected]', 'secret', 'admin', 'Engineering');
// GOOD — self-documenting options object createUser({ firstName: 'John', lastName: 'Doe', email: '[email protected]', password: 'secret', role: 'admin', department: 'Engineering', }); ```
---
## 代码结构模式
| 模式 | 何时应用 | 好处 | |---------|--------------|---------| | **卫语句(Guard Clauses)** | 函数开始处的边缘情况 | 流程扁平、可读 | | **扁平优于嵌套(Flat > Nested)** | 任何超过 2 层的嵌套 | 降低认知负荷 | | **组合** | 复杂操作 | 小巧、可测试的片段 | | **并置** | 跨文件的相关代码 | 更容易查找和修改 | | **提取函数** | 注释分隔“部分” | 自文档化代码 |
### 组合优于上帝函数
```typescript // 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 }; } ```
---
## 返回类型一致性
函数应该返回一致的类型。对于多种结果,使用可辨识联合(discriminated unions)。
```typescript // 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 }; } ```
---
## 反模式
| 反模式 | 问题 | 修正 | |--------------|---------|-----| | 每行都注释 | 噪音掩盖信号 | 删除显而易见的注释;解释“为什么”,而不是“是什么” | | 为单行代码写辅助函数 | 不必要的间接调用 | 内联代码 | | 为 2 个对象创建工厂 | 过度设计 | 直接实例化 | | 只有 1 个函数的 `utils.ts` | 垃圾抽屉式文件 | 将代码放在使用的地方 | | 深层嵌套 | 流程不可读 | 卫语句和提前返回 | | 魔法数字 | 意图不明确 | 命名常量 | | 上帝函数 | 不可测试,不可读 | 按职责拆分 | | 注释掉的代码 | 死代码混淆视听 | 删除它;git 会记住 | | TODO 满天飞 | 永远不会被完成 | 在问题跟踪器中跟踪,而不是在代码中 | | 过早抽象 | 错误的抽象比没有更糟 | 在抽象之前等待出现 3 个以上重复项 | | 复制粘贴编程 | 重复的 bug | 提取共享逻辑 | | 异常驱动的控制流 | 缓慢且令人困惑 | 使用显式条件语句 | | 字符串类型代码 | 拼写错误和遗漏情况 | 使用枚举或联合类型 | | 回调地狱 | 金字塔式 doom | 使用 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 ```
> **规则:** 在同一个任务中编辑该文件及所有依赖文件。永远不要留下损坏的导入或缺失的更新。
---
## 完成前的自查
在将任何任务标记为完成之前,请验证:
| 检查 | 问题 | |-------|----------| | **目标达成?** | 我是否完全按照要求完成了? | | **文件已编辑?** | 我是否修改了所有必要的文件,包括依赖项? | | **代码有效?** | 我是否验证了更改可以编译并运行? | | **无错误?** | Lint 和类型检查是否通过? | | **没有遗漏?** | 是否遗漏了任何边缘情况或依赖文件? |
---
## 绝对禁止
1. **绝对不要添加重述代码的注释**——如果代码需要注释来解释它是做*什么*的,重命名元素直到不需要为止 2. **绝对不要为少于 3 个用例创建抽象**——过早的抽象比重复更糟糕 3. **绝对不要在代码库中留下注释掉的代码**——删除它;版本控制就是用来记录历史的 4. **绝对不要写超过 20 行的函数**——提取子函数,直到每个函数只做一件事 5. **绝对不要嵌套超过 2 层**——使用卫语句、提前返回或提取函数 6. **绝对不要使用魔法数字或字符串**——定义具有清晰语义的命名常量 7. **绝对不要在未检查依赖关系的情况下编辑文件**——损坏的导入和缺失的更新是多文件更改中最常见的 bug 来源 8. **绝对不要在一个任务中留下未通过 lint 或类型检查的代码**——在标记完成之前修复所有错误
---
## 参考资料
特定整洁代码主题的详细指南:
| 参考资料 | 描述 | |-----------|-------------| | [反模式](references/anti-patterns.md) | 涵盖命名、函数、结构和注释的 21 个常见错误及错误/正确代码示例 | | [代码异味](references/code-smells.md) | 经典代码异味目录及检测模式——膨胀类、面向对象滥用者、更改阻碍者、冗余子、耦合器 | | [重构目录](references/refactoring-catalog.md) | 基本重构模式,包含前/后示例和分步机制 |