译文:Write Code That Speaks: A Developer’s Guide to Clean Code (opens new window)
"Code is read more often than it is written." — Uncle Bob
# 引言 - 从挫折到基础
编写整洁的代码是每个开发者都曾经历过的噩梦(我自己也亲身经历过这个噩梦)。
当我刚入行时,没有人给我一份整洁代码的清单。我写的代码只要能运行就行。它确实能运行,直到出现 bug、代码评审耗时且费劲,以及未来的修改变成雷区。
我曾经害怕代码评审。问题不仅在于代码是否能运行,而在于为什么它如此难以阅读。但随着时间的推移,通过大量尝试、犯错和资深开发者的指导,我开始掌握一些模式。慢慢地,这些模式变成了习惯。
如今,这些习惯帮助我:
- 编写更容易调试的代码(不是没有bug,而是不那么痛苦)
- 帮助团队成员理解该做什么和避免什么
- 在漏洞变成代价高昂的错误之前发现它们
整洁的代码不是魔法技能,而是一种实践。一步一个脚印。这篇文章就是这些虽小但有力的步骤的集合。让我们开始吧 👇
# 为什么整洁的代码很重要
整洁的代码不是「锦上添花」,它是可扩展、可维护和可协作软件的要求。
- ✅ 更易于阅读
- ✅ 更易于调试
- ✅ 更易于测试
- ✅ 更易于重构
- ✅ 更易于团队在此基础上构建
无论你使用的是 JavaScript、TypeScript 还是其他现代语言,这些原则都是一样的。
# 整洁代码基础 - 初级
# 1. 使用清晰的,描述性的命名
❌ 不好的:
let a = 5;
✅ 好的:
let retryLimit = 5;
好的命名可以减少代码中的注释,帮助未来的读者理解你的意图。
# 2. 单一职责函数
❌ 混乱:
function processUser(user) {
validateUser(user);
saveToDB(user);
sendEmail(user);
logActivity(user);
}
✅ 更清晰:
function processUser(user) {
if (!isValidUser(user)) return;
saveUser(user);
notifyUser(user);
trackSignup(user);
}
将函数按职责拆分。小而精的函数更强大。
# 3. 避免魔法数字和字符串
❌ 令人迷惑的:
if (user.age > 17 && user.age < 65) {
// ...
}
✅ 清晰可维护的:
const MIN_ELIGIBLE_AGE = 18;
const MAX_ELIGIBLE_AGE = 64;
if (user.age >= MIN_ELIGIBLE_AGE && user.age <= MAX_ELIGIBLE_AGE) {
// ...
}
# 4. 守护子句优于嵌套 If-Else
❌ 难以理解的:
if (user) {
if (user.age > 18) {
if (user.isActive) {
return true;
}
}
}
return false;
✅ 扁平且易读:
if (!user || user.age <= 18 || !user.isActive) return false;
return true;
# 5. 简化复杂条件
❌ 令人困惑:
if ((user.isAdmin && !user.isBanned) || (user.age > 21 && user.isVerified)) {
// ...
}
✅ 更简单:
const isPrivileged = user.isAdmin && !user.isBanned;
const isTrusted = user.age > 21 && user.isVerified;
if (isPrivileged || isTrusted) {
// ...
}
将逻辑分解为中间布尔变量。这提高了清晰度和可调试性。
# 整洁代码模式 - 中级
# 1. 错误处理不容妥协
✅ 始终处理预期失败:
try {
const data = await fetchData(url);
} catch (error) {
logger.error('Failed to fetch:', error);
}
# 2. 避免混合使用 if 和 switch
❌ 过于复杂:
if (user.isActive) {
switch (user.role) {
case 'admin':
return 'full';
case 'editor':
return 'edit';
default:
return 'read';
}
} else {
return 'suspended';
}
✅ 前置返回更清晰:
if (!user.isActive) return 'suspended';
switch (user.role) {
case 'admin': return 'full';
case 'editor': return 'edit';
default: return 'read';
}
✅ 使用对象更佳:
const roles = {
admin: 'full',
editor: 'edit',
viewer: 'read',
};
return user.isActive ? roles[user.role] || 'read' : 'suspended';
# 类与函数 - 最佳实践
# 1. 保持函数小而专注
✅ 一个函数应该只做一件事,并做好它:
function sendWelcomeEmail(user: User) { ... }
function saveUserToDatabase(user: User) { ... }
# 2. 不要让类做太多事
❌ 上帝类:
class UserManager {
createUser() {}
emailUser() {}
trackActivity() {}
}
✅ 拆分逻辑:
class UserService { createUser() { ... } }
class EmailService { sendEmail() { ... } }
class AnalyticsService { logEvent() { ... } }
# 高效整洁代码习惯
# 1. 遵循样式指南
使用工具强制执行样式:
- Prettier & ESLint (JavaScript/TypeScript)
- Git hooks (lint-staged, husky)
- CI pipelines
- 让工具处理格式化,你专注于逻辑处理
# 2. 不要重复自己(DRY 原则)
❌ 重复:
sendEmail(user1);
sendEmail(user2);
sendEmail(user3);
✅ DRY:
[ user1, user2, user3 ].forEach(sendEmail);
# 3. 注释说明「为什么」,而不是「是什么」
❌ 无用:
i++; // 加 1
✅ 有帮助:
i++; // 跳过已处理的元素
# 随时重构
重构是开发过程的一部分,而不是事后补救。重命名令人困惑的变量,删除无用代码,将逻辑提取到辅助函数中。
# 编写测试,即使它能工作™
没有测试的好代码就像没有负载测试的桥梁。
- ✅ 对小型工具进行单元测试
- ✅ 使用 mock 模拟 API
- ✅ 验证边缘情况
# 谨慎使用依赖项
您安装的每个 npm 包:
- 增加体积
- 可能引入安全问题
- 可能不再维护
更推荐:
- 内置工具(Array.map, Intl, Date)
- 被广泛采用的轻量级库
# 直观地组织项目结构
文件夹结构影响开发效率。
❌ 分散:
utils.js
index.ts
api.js
✅ 有组织:
src/
components/
features/
auth/
cart/
services/
utils/
按功能而非类型分组文件。
# 整洁代码还能提升…
🔐 安全性
- 通过清晰的抽象层防止数据泄露
- 使用 SonarQube 和 Snyk 等工具更易于审计
- 清晰的分离 = 减少认证、验证或存储中的错误
🚀 性能
- 更容易识别和重构瓶颈
- 鼓励更小、更快、更纯粹的函数
- 实现更高效的内存和网络使用
👩💻 开发效率
- 加速代码评审和新成员上手
- 使 bug 更易定位和修复
- 减少开发中的上下文切换
# 当混乱代码演变为灾难
糟糕的代码不仅会导致 bug。在现实世界中,它曾让团队损失数百万美元,引发诉讼,甚至在某些情况下危及生命。
以下是几个备受关注的案例:
# 1. 🚀 NASA火星气候轨道器(1999年)
- 价值 3.27 亿美元的航天器在进入火星大气层时解体。
- 原因:团队使用了混合测量系统(公制与英制),而代码库未能强制使用一致的单位。
- 教训:整洁的代码本应强制更好的变量命名、类型检查和模块化设计。
# 2. 🏦 Knight Capital交易故障(2012年)
- 留在生产代码中的测试功能失控,在 45 分钟内执行了数十亿美元的交易。
- 损失:4.4亿美元,公司破产。
- 教训:应始终清理无用代码,发布管道应防止未经审查的更改。
# 3. 🔐 Apple 的 SSL "goto fail" 漏洞(2014年)
- 重复的
goto fail;
行破坏了 iOS/macOS 上的 SSL 证书验证。 - 影响:使所有Apple用户面临中间人攻击风险。
- 教训:缩进、大括号和自动格式化很重要。Linter 本应捕获此问题。
# 4. 🛒 塔吉特加拿大供应链崩溃(2013年)
- 塔吉特进入加拿大市场,但由于库存系统故障无法保持货架库存。
- 原因:混乱的代码、损坏的逻辑和不可维护的系统。
- 教训:整洁的代码确保大规模企业系统的可靠性。
# 5. 🚗 丰田意外加速事件(2009-2010年)
- 某些丰田车型自行加速,导致事故和死亡。
- 调查结果:NASA 报告指出嵌入式代码混乱、不可测试且存在内存泄漏。
- 代价:12亿美元和解和大规模召回。
💡 整洁的代码不仅仅是「开发者习惯」,它关乎构建人们可以信任的软件。
# 整洁代码是一种投资
领域 | 优势 |
---|---|
可读性 | 加速理解 |
可维护性 | 减少 bug 与技术债务 |
测试 | 更易验证逻辑 |
团队效率 | 改进协作 |
安全性 | 限制攻击面 |
性能 | 更容易隔离和修复瓶颈 |
# 临别赠言 - 整洁代码是一场旅程
如果您已经读到这里,说明您已经在做最难的部分:足够关心并愿意改进。
整洁代码不是在一个项目或一周内就能掌握的技能,它是你通过一次次函数编写、一次次重构、一次次评审中逐渐培养的能力。你有时仍会写出混乱的代码(我们都这样)。但随着每个拉取请求、每次反馈周期和解决的每个 bug,你会越来越擅长编写清晰整洁的代码。
请记住:
💡 你不仅是为机器编写代码,你也在为其他人,包括未来的自己编写代码。
所以今天就从一小步开始 —— 重命名一个变量,移除一个嵌套 if,编写一个更清晰的函数。所有这些都会累积起来。
感谢阅读。让我们每天努力使我们的代码以及我们的技艺,变得更加整洁一点。