最近重读了一遍《代码整洁之道》,这本书既是整洁代码的定义,也是写出整洁代码的指南。我认为既适合新手阅读,快速提升代码质量;也适合老鸟阅读,持续精进。本篇将汇总《代码整洁之道》的必读要点,把书读薄,方便各位快速阅读。
为什么要阅读《代码整洁之道》
第一,是个程序员;第二,想成为更好的程序员。
一、什么是代码整洁之道?
有多少程序员,就有多少对整洁代码的定义。就像武术家一样,有不同的流派,代码整洁也有不同的思想流派。鲍勃大叔是 「对象导师整洁代码派」的,《代码整洁之道》一书传授正是这一流派的思想和方法。
二、有意义的命名是什么样子的?
- 名副其实
例:使用有意义的名称代替魔法数 - 避免误导
例:避免使用小写字母l和大写字母O作为变量名 - 做有意义的区分
例:添加变量添加数字(a1、a2)、或者废话(nameString)是没有意义的 - 使用读得出来的名称
- 使用可搜索的名称
单字母名称仅用于段方法中的本地变量;变量名称应与其作用域大小相对应。 - 避免使用编码
- 避免思维映射
- 类名
类名和对象名应该是名词或者名词短语 - 方法名
方法名应该是动词或者动词短语 - 别抖机灵
- 每个概念对应一个词
- 别用双关语
- 使用解决方案领域名称
- 使用源自所涉问题领域的名称
- 添加有意义的语境、不要添加没用的语境
三、如何写好函数
每个系统都是使用某种领域特定语言搭建,而这种语言是程序员设计来描述那个系统的。函数是语言的动词,类是名词。编程艺术是且一直就是语言设计的艺术。
大师级程序员把系统当作故事来讲,而不是当作程序来写。他们使用选定编程语言提供的工具构建一种更为丰富且更具表达力的语言,用来讲那个故事。
写函数需要干净利落,这样可以形成一种精确而清晰的语言,帮助讲故事。
- 短小
函数的第一条规则是要短小,第二条规则是还要更短小。 - 只做一件事情
函数应该只做一件事情。做好这件事。只做一件事。 - 每个函数一个抽象层级
- 使用具有描述性的名称
如果每个例程都让你感到深合己意,那就是整洁代码。
别害怕长名称。长而具有描述性的名称,要比短而令人费解的名称好。长而具有描述性的名称,要比描述性的长注释好。使用某种命名约定,让函数名称中的多个单词容易阅读,然后使用这些单词给函数取个能说清其功用的名称。 - 函数参数
函数参数越少越好,最理想的参数数量是0个。
标识参数是丑陋不堪的,想函数传入布尔值简直是骇人听闻的做法,更好的做法是将函数一分为二。
如果函数需要2个、3个或者3个以上的参数,可以将其中一些参数封装成类。 - 无副作用
- 分隔指令与询问
函数应该修改某对象的状态,或是返回该对象有关的信息,如果两样都干,常会导致混乱。 - 使用异常代替返回错误码
- 别重复自己
- 结构化编程
结构化编程认为,每个函数、函数中的每个代码块都应该有一个入口、一个出口。
鲍勃大叔虽然赞成结构化编程的目标和规范,但认为只要函数保持短小,偶尔出现的return、break或continue语句没有坏处,甚至还比单入单出原则更具有表达力。
四、注释
什么也比不上放置良好的注释来得有用。什么也不会比乱七八糟的注释更有本事搞乱一个模块。什么也不会比陈旧、提供错误信息的注释更有破坏性。
好注释与坏注释:
好注释 | 坏注释 |
---|---|
1 法律信息 2 提供信息的注释 3 对意图的解释” 4 阐释 5 警示 6 TODO注释 7 放大 8 公共API中的Javadoc |
1 喃喃自语 2 多余的注释 3 误导性注释 4 循规式注释 5 日志式注释 6 废话注释 7 可怕的废话 8 能用函数或变量时就别用注释 9 位置标记 10 括号后面的注释 11 归属与署名 12 注释掉的代码 13 HTML注释 14 非本地信息 15 信息过多 16 不明显的联系 17 函数头 18 非公共代码中的Javadoc |
五、格式
代码格式不可忽略。代码格式关乎沟通,而沟通是专业开发者的头等大事。
5.1 垂直格式
- 向报纸学习
源文件要像报纸文章那样。名称简单且一目了然。名称本身应该足够告诉我们是否在正确的模块中。
源文件最顶部应该给出高层次概念和算法。细节应该往下渐次展开,直至找到源文件中最底层的函数和细节。 - 概念间垂直方向上的区隔
每个空白行都是一条线索,标识出新的独立概念。 - 垂直方向上靠经
紧密相关的代码应该互相靠近。 - 垂直距离
变量声明应尽可能靠近其使用位置。 - 垂直顺序
被调用的函数应该放在执行调用的函数下面,这样可以建立了一种自顶向下贯穿源代码模块的良好信息流。
5.2 横向格式
一行代码应该有多宽?
应该遵循无需拖动滚动条到右边的原则。鲍勃大叔认为这个上限是120个字符。
- 水平方向上的区隔和靠近
我们使用空格字符将彼此紧密相关的事物连接到一起,也用空格字符把相关性较弱的事物分隔开。 - 水平对齐(变量声明和赋值不需要对齐)
- 缩进
5.3 遵循团队规则
每个程序员都有自己喜欢的格式规则,但如果在一个团队中工作,就是团队说了算。
六、对象和数据结构
将变量设置为私有(private)有一个理由:我们不想其他人依赖这些变量。
-
数据、对象的反对称性
过程式代码(使用数据结构的代码)便于在不改动既有数据结构的前提下添加新函数。
面向对象代码便于在不改动既有函数的前提下添加新类。
所以,对于面向对象较难的事,对于过程式代码却较容易,反之亦然! -
得墨忒耳律认为,模块不应了解它所操作对象的内部情形。
-
数据传送对象:
最为精练的数据结构,是一个只有公共变量、没有函数的类。这种数据结构有时被称为数据传送对象,或DTO(Data Transfer Objects)。DTO是非常有用的结构,尤其是在与数据库通信、或解析套接字传递的消息之类场景中。
对象曝露行为,隐藏数据。数据结构曝露数据,没有明显的行为。
七、错误处理
编写既整洁又强固的代码——雅致地处理错误代码的一些技巧和思路。
- 使用异常而非返回码
- 先写Try-Catch-Finally语句
- 使用不可控异常
- 给出异常发生的环境说明
- 依调用者需要定义异常类
- 定义常规流程
- 别返回null值
- 别传递null值
整洁代码是可读的,但也要强固。可读与强固并不冲突。如果将错误处理隔离看待,独立于主要逻辑之外,就能写出强固而整洁的代码。做到这一步,我们就能单独处理它,也极大地提升了代码的可维护性。
八、边界
如何将外来代码干净整合进自己的代码?这其实就是边界的问题,边界上的代码需要清晰的分割和测试。
九、单元测试
整洁的测试有什么要素?有三个要素:可读性,可读性和可读性。
每个测试函数只测试其中一个概念。每个测试一个断言。
十、类
10.1 类的组织
遵循标准的Java约定,类应该从一组变量列表开始。如果有公共静态常量,应该先出现。然后是私有静态变量,以及私有实体变量。很少会有公共变量。
公共函数应跟在变量列表之后。我们喜欢把由某个公共函数调用的私有工具函数紧随在该公共函数后面。这符合了自顶向下原则,让程序读起来就像一篇报纸文章。
10.2 类应该短小
关于类的第一条规则是类应该短小。第二条规则是还要更短小。
单一职责原则(SRP):类或模块应有且只有一条加以修改的理由。
系统应该由许多短小的类而不是少量巨大的类组成。每个小类封装一个权责,只有一个修改的原因,并与少数其他类一起协同达成期望的系统行为。
十一、系统
系统也应该是整洁的。侵害性架构会湮灭领域逻辑,冲击敏捷能力。当领域逻辑受到困扰,质量也就堪忧,因为缺陷更易隐藏,用户故事更难实现。当敏捷能力受到损害时,生产力也会降低。
在所有的抽象层级上,意图都应该清晰可辨。只有在编写POJO并使用类方面的机制来无损地组合其他关注面时,这种事情才会发生。
无论是设计系统或单独的模块,别忘了使用大概可工作的最简单方案。
十二、逐步改进
鲍勃大叔认为:没什么能比糟糕的代码给开发项目带来更深远和长期的损害了。进度可以重订,需求可以重新定义,团队动态可以修正。但糟糕的代码只是一直腐败发酵,无情地拖着团队的后腿。我无数次看到开发团队蹒跚前行,只因为他们匆匆搞出一片代码沼泽,从此之后命运再也不受自己控制。
注:但是,国内的开发状况却是不管代码质量,只追求快速上线,只追求短期利益,而不做有长期价值的事情。
所以,解决之道就是保持代码持续整洁和简单。永不让腐坏有机会开始。
十三、其他
最后,我认为第17章《味道与启发》可以作为案例来自查和学习,对提高代码质量很有帮助。
一起学习
欢迎各位在评论区或者私信我一起交流讨论,或者加我主页weixin,备注技术渠道(如博客园),进入技术交流群,我们一起讨论和交流,共同进步!
也欢迎大家关注我的掘金、公众号(码上暴富),点赞、留言、转发。你的支持,是我更文的最大动力!