第一次读《代码整洁之道》是入行第一年的时候,那时候更多是走马观花地看了一遍,觉得"说的都对",但实际编码时依然我行我素。最近重新翻读,发现很多之前忽略的细节,也才真正理解了为什么这本书能成为经典。
这本书的核心论点其实很简单:代码不仅要能工作,还要易于阅读和理解。因为代码被阅读的次数远远超过被编写的次数。如果一段代码写完之后就再也不需要碰了,那它怎么写都无所谓。但现实是,代码需要被维护、被扩展、被调试——而这些工作的大头往往不是原作者来做的。
命名是一门艺术
书中最让我反复反思的部分是关于命名的章节。作者用了大量反面教材来说明糟糕的命名如何增加代码的理解成本。变量名叫 d 还是 elapsedTime,函数名叫 processData() 还是 calculateMonthlyRevenue(),差别不仅仅是字符数。
好的命名让读者不必再看函数体就能知道它在做什么。如果做不到这一点,至少要让读者知道应该去哪里找答案。
在实践中我发现,给变量起名时多花十几秒想一个准确的名字,能省下后面无数次"这个变量到底是什么意思"的困惑。如果名字需要注释来解释,说明名字起得还不够好。
函数的单一职责
书中对函数的建议非常激进:函数应该尽可能短小,最好只做一件事。一个超过 20 行的函数就应该引起警觉,超过 50 行的大概率有问题。
这个标准在 JavaScript 前端开发中尤其值得注意。我们经常写出一个组件函数几百行——既处理数据转换,又处理状态管理,还包含了 DOM 操作的逻辑。拆分的标准就是:如果函数的名字不能准确描述它做的事情,说明它做了太多事情。
// 不好的例子
function handleFormSubmit(data) {
// 验证数据
// 发送请求
// 更新本地状态
// 显示成功提示
// 重置表单
// 发送埋点数据
}
// 拆分后
function validateForm(data) { /* ... */ }
function submitToServer(data) { /* ... */ }
function showSuccessMessage() { /* ... */ }
function resetForm() { /* ... */ }
function trackEvent(data) { /* ... */ }
function handleFormSubmit(data) {
validateForm(data);
submitToServer(data)
.then(() => {
showSuccessMessage();
resetForm();
trackEvent(data);
});
}
注释不是万能的
这一章颠覆了我以前的认知。我之前总觉得"注释写得多 = 代码写得好"。但作者指出,大多数情况下,注释的存在是因为代码本身不够清晰。如果你需要写注释来解释一段代码在做什么,首先应该考虑的是能不能重构代码让它自解释。
当然,这不是说所有注释都应该删除。好的注释用于解释"为什么这样做"而不是"做了什么"。比如一个奇怪的边界条件处理、一个绕过已知 bug 的 workaround,这些时候注释是有价值的。但类似 // 遍历数组 这种注释,除了增加维护负担外没有任何意义。
错误处理
错误处理是日常开发中容易被忽视的部分。书中强调:错误处理也是一项独立的工作,应该和正常逻辑分开。如果一个函数同时包含正常流程和异常处理,就很难理解它的真正逻辑。
在前端开发中,我们经常在同一个函数里混合了请求、数据处理、UI 更新和错误处理。把错误处理提取出来,用统一的错误边界或者中间件来管理,代码会清晰很多。
实践中的取舍
必须承认,《代码整洁之道》的标准是非常理想化的。在实际项目中,尤其是赶工期的时候,很难做到每一行代码都经过精心打磨。但我发现一个有趣的规律:在关键模块和核心业务逻辑上多花时间打磨代码质量,反而能节省整体的开发时间。因为清晰的结构让后续的修改和调试变得更容易。
我的实践建议是:
- 写代码的时候先求"能跑",这是没问题的
- 但在提交之前,花 10 分钟做一轮 self-review,重点看命名和函数拆分
- 对于公共模块和团队共享的代码,花更多时间打磨质量
- 定期重构,不要等技术债务积累到无法处理
总结
《代码整洁之道》不是一本读一遍就能掌握的书。它的价值在于提供了一套衡量代码质量的标准和语言。读完之后你可能不会立刻变成更好的程序员,但你会开始注意到以前忽略的问题,在写代码的时候多一层考量。这本身就是进步。
如果你还没有读过这本书,推荐入手。不管你是刚入行的新手还是有多年的开发经验,应该都能从中获得一些启发。