编写会说话的代码:前端整洁代码指南

2025/07/01 clean

译文: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 亿美元的航天器在进入火星大气层时解体。
  • 原因:团队使用了混合测量系统(公制与英制),而代码库未能强制使用一致的单位。
  • 教训:整洁的代码本应强制更好的变量命名、类型检查和模块化设计。

📖 阅读更多 (opens new window)

# 2. 🏦 Knight Capital交易故障(2012年)

  • 留在生产代码中的测试功能失控,在 45 分钟内执行了数十亿美元的交易。
  • 损失:4.4亿美元,公司破产。
  • 教训:应始终清理无用代码,发布管道应防止未经审查的更改。

📖 阅读更多 (opens new window)

# 3. 🔐 Apple 的 SSL "goto fail" 漏洞(2014年)

  • 重复的 goto fail; 行破坏了 iOS/macOS 上的 SSL 证书验证。
  • 影响:使所有Apple用户面临中间人攻击风险。
  • 教训:缩进、大括号和自动格式化很重要。Linter 本应捕获此问题。

📖 阅读更多 (opens new window)

# 4. 🛒 塔吉特加拿大供应链崩溃(2013年)

  • 塔吉特进入加拿大市场,但由于库存系统故障无法保持货架库存。
  • 原因:混乱的代码、损坏的逻辑和不可维护的系统。
  • 教训:整洁的代码确保大规模企业系统的可靠性。

# 5. 🚗 丰田意外加速事件(2009-2010年)

  • 某些丰田车型自行加速,导致事故和死亡。
  • 调查结果:NASA 报告指出嵌入式代码混乱、不可测试且存在内存泄漏。
  • 代价:12亿美元和解和大规模召回。

📖 参考摘要 (opens new window)

💡 整洁的代码不仅仅是「开发者习惯」,它关乎构建人们可以信任的软件。

# 整洁代码是一种投资

领域 优势
可读性 加速理解
可维护性 减少 bug 与技术债务
测试 更易验证逻辑
团队效率 改进协作
安全性 限制攻击面
性能 更容易隔离和修复瓶颈

# 临别赠言 - 整洁代码是一场旅程

如果您已经读到这里,说明您已经在做最难的部分:足够关心并愿意改进

整洁代码不是在一个项目或一周内就能掌握的技能,它是你通过一次次函数编写、一次次重构、一次次评审中逐渐培养的能力。你有时仍会写出混乱的代码(我们都这样)。但随着每个拉取请求、每次反馈周期和解决的每个 bug,你会越来越擅长编写清晰整洁的代码。

请记住:

💡 你不仅是为机器编写代码,你也在为其他人,包括未来的自己编写代码

所以今天就从一小步开始 —— 重命名一个变量,移除一个嵌套 if,编写一个更清晰的函数。所有这些都会累积起来。

感谢阅读。让我们每天努力使我们的代码以及我们的技艺,变得更加整洁一点。

上次更新: 2025/7/1 03:41:50