Clean Code 的一些笔记

August 28, 2023

CS programming style methodology

Clean Code 由 Robert C. Martin 在 2009 年出版。他是一个著名的软件工程师,以推广敏捷开发著称。所以,敏捷开发的思想也渗透在这本书里。在这本书中,他详细描述了编程的方法论,包括最重要的:如何鉴别好代码和坏代码,以及写干净代码的准则。这些准则环环相扣,形成一个统一的整体。

主题

要写干净的代码。没有人能一次写出干净的代码,要多次重写;但是这值得。

命名

计算机不看代码。计算机不认识任何文字。代码是写给人的文章,文章的主角是变量,而情节是指令。写程序是为了向人(自己或者别人)解释我们想要计算机做什么事情。

选择好名字,对同一个概念用同一个名字,不要冗余。

函数

每个函数都应该做一件事情。因为函数如果做很多事,会很难理解,而且容易出错。复杂的函数也很难命名,所以要避免。如果一个函数很长,那么它往往没有做一件事。所以函数应该很短。

函数还应该尽量无副作用。因为副作用很难理解。我们通常把会产生副作用的函数封装成一个类。

函数的控制流应当简明清晰,避免用不相干的语句(例如处理错误码)混杂逻辑,因此使用异常来分离错误和处理错误的代码。

函数的参数要尽可能少,最好一个,以小于三个为宜,最好不要用 flag 来控制函数,因为这意味着函数有多个功能。

不要在输入里输出。

函数之间最好不要有时间上的耦合性(必须先调用 A 再调用 B),如果有,要尽量让它们实际上耦合起来。

注释

注释有害。因为代码更新的时候,注释不一定更新(因为注释更新不是强制的,所以很容易不更新)。这样,注释和代码就不一样了,注释就会误导读者。读者弄不明白:到底注释说的是对的(所以代码有 bug),还是注释错了(所以代码是对的)。

所以注释只应该用来解释设计思想,阐述 “why”,这些往往不变动的内容。而不是具体实现细节。具体实现细节如果需要注释才能看懂,说明这段代码应该重写。

对象和数据结构

对象和数据结构是不同的东西。

对象将数据和方法放在一起。对象容易增加新的种类,而不改变原有的功能(用这个实现多态,取代 if-else 或者 switch)。但是要改变原有的功能时,对象非常麻烦,因为要在接口定义新的虚函数,每一个实现接口的对象都要加入新的内容。与此相反,数据结构容易增加新的行为,只要加入一些函数。但是对已有行为,很难让它适配数据结构。

错误处理

使用异常,而不是错误码。在异常中写明相关信息。

正常的执行流要顺畅。

不要用 null,有需要的话,用 Optional 或者 Status,加上 Monadic 的操作。

边界

调用第三方 API 很常用。

使用一个包管理器。

用写单元测试的方法学习和使用一个第三方库。这样当第三方库更新的时候,你可以知道这个库是否和以前不兼容。

单元测试

测试不是可有可无的。它是软件的一部分,因为程序员需要通过测试明白自己要做什么,用户往往要看测试,才能明白函数如何调用。

测试驱动开发三大定律:

要让单元测试高质量。需要满足下面的特性:快速、独立、可重复、及时、自验证(不需要看日志)

单元测试允许重构。因为如果没有单元测试,你就不知道自己的重构会不会毁了整个代码仓库。

面向对象编程范式通过隐藏状态来管理状态。类应该很小,高内聚低耦合。不同的类之间通过组合沟通,一个类内部最好每个方法使用每个变量。毕竟这是使用类的充分理由。

设计

基本设计规则:1. 运行所有的测试 2. 实现新功能 3. 重构

应该可以一键构建,一键运行测试。

不同层级的抽象不能混杂在一起。

参考资料

[1] Clean Code: A Handbook of Agile Software Craftsmanship, Robert C. Martin, Pearson. 2008.