Blog·Tanky WooABOUTRSS

读《代码整洁之道》

22 Jan 2014

前阵子找 Jerry 借了《Clean Code》,这两天抽时间简单过了一遍,把对自己有用的记录一下。

首先很喜欢第一章1.2节最后提到的勒布朗(LeBlanc)法则:

稍后等于永不(Later equals never)

对于糟糕的代码,就应该马上去修改清理,不能拖,否则随着特性越来越多,代码也越来越烂,越来越难维护,最终导致失控。

命名

命名这个话题太老了,尤其 变量名一定要能清晰的表达出这个变量的作用,当年谭浩强的那本C语言教材,让各种 a, b, c, z 这样的变量名在代码里到处飞,我估计翻下我之前ACM的题解,也可以找到这样的变量名。现在已经基本不用了,除非是一些2、3行代码快里的临时变量。

不要用一些误导性的词。比如一组帐号不要用accountList,可以换成accountGroup。这个确实有道理,毕竟在很多语言里,List都会被认为是一个内置类型,如果accountList不是一个列表,会让人误以为是使用了匈牙利命名方式,以为是一个列表类型的变量。

使用可搜索的名称。经常会遇到一些代码,里面各种数字,但是这些数字的意义都不清楚,如果用一个有意义、可搜索的名称,那么代码也会明了很多。

关于命名方式,比如匈牙利命名、驼峰式、下划线命名等等,书上不赞成使用匈牙利命名了,当然也提到了它产生的历史。当然我也很少使用匈牙利命名。驼峰式这种现在应该算是很普遍的吧,也是我比较喜欢的。当然,这个也没必要是纠结,我觉得最主要的是形成一个个人固定的命名风格。

类名和对象名是名词,方法名是动词

最后,关于命名这块,之前看过 Tony Bai 的 《那些代码中的“中国式”命名》,里面提到了 Quora 上的一个调查 程序员职业生涯中最难的事是什么?,结果最困难的Top1就是命名,命名确实是门技术活。。。

函数

函数的第一规则是要短小,第二条规则还要更短小。一个太长的函数,让人都没有读的欲望,而且还容易让代码变复杂。忘了以前在哪看过一句话,大概意思是:

如果你的函数超过了X(20?30?or?)行,那么就应该考虑分割成多个函数了”,

函数应该做一件事。做好这件事。只做这一件事。我记得这句话应该是 Jerry 最喜欢说的。同上面说的,如果代码同时处理了几件事,那么这个代码就应该继续分割了。

关于如何控制代码只做一件事,书中提到了 每个函数一个抽象层级。一个函数中的语句都应该在一个抽象层级上。

关于函数参数这块。书上提到的是 最理想的是零参数函数,然后依次增多,越来越不推荐。在这点上面没有过多的感触,不发言。。。

抽离 try/catch 代码块的主体部分。因为上面提到了函数只做一件事,而错误处理就是一件事

最后一个就是 消灭重复。重复就意味着可以抽出成一个函数。

注释

注释这里比较有意思,作者说 写注释,因为自己的表达能力不够,无法用代码来表达意图,这里比较逗,不过书上也解释了原因,因为代码一直在变动,如果注释没有及时更新,就会造成问题了。

当然,这里也是有点夸张的意思,该注释的地方,肯定不能吝啬注释。后面书上也提到了 有些注释是必须的,也是有利的

关于注释这块,简单的说就几句话:

  1. 能用代码表达意图的,不要用注释
  2. 杜绝任何无用和多余的注释,其实和上一条一个意思。
  3. 如果需要注释,那也不要去吝啬

另外,还有一些其他的,比如 TODO注释,现在的IDE都会对这些特俗标记识别,这个推荐使用,但是要定期查看,删除不需要的,保持代码干净。

最后一个就是直接把代码注释掉是一个令人讨厌的做法,有时因为一些问题,会把一些代码注释掉,这样导致别人也不敢去删除这些代码,而本人也不一定会回头来修改这些代码。这里也可以因用到开头提到的勒布朗法则,要么就当是把这块代码处理了,永远不要相信自己的记性。。。当然,最佳的办法还是源代码版本管理,用了版本管理工具,还在乎这些问题?该删就立马删掉!

格式

代码格式也是为了保证代码干净、正解、易读。

主要是纵向上该空行的要空行、该紧凑的要紧凑,横向上该空格的要空格,让代码可读性强。

另外 水平对齐 这个没必要,因为本来是横向的关系,因为对齐,让纵向的视觉感更强。比如:

this.context            =  s.context;
socket                  =  s.socket;
input                   =  s.getInputStream();
output                  =  s.getOutputStream();
requestParsingTimeLimit =  100000;

让人更容易从上到下阅读代码,而忽视了他们的类型。

关于横向的一行长度, 一般都提倡不超过80列,书上也提到了,死守80个字符的上限有点僵化,可以适当增大,但是不应该偏离太多,毕竟有些语言一行就没法短下来 :(

类应该短小,这点和函数类似。不过对于函数,是通过计算代码行数来衡量大小,对于类,是通过计算职责(responsibility)。(书上翻译成"权责",我半天不明白是啥。。。)

单一职责原则(Single Responsibility Principle),书上对这段的解释,我读了几遍都不明白,直接翻的原文:

The Single Responsibility Principle (SRP) states that a class or module should have one, and only one, reason to change. This principle gives us both a definition of responsibility, and a guidelines for class size. Classes should have one responsibility—one reason to change.

依然读起来怪怪的。。。

直接上维基百科的解释:

在面向对象编程领域中,单一功能原则(Single responsibility principle)规定每个类都应该有一个单一的功能,并且该功能应该由这个类完全封装起来。所有它的(这个类的)服务都应该严密的和该功能平行(功能平行,意味着没有依赖)。

当然这个术语也是此书作者引入的。上面的维基百科链接里又解释到上面那段英文的意思。

网上这篇文章 也解释的比较清楚。

大意就是一个类,应该只有一个功能,这样可以保证低耦合高内聚。职责过多,引起它变化的原因就越多,这将导致职责依赖,相互之间就产生影响,从而极大的损伤其内聚性和耦合度。

总结

大致看了2/3的篇幅,有些就直接略过了,收获还是挺大的。

对于这类书,我一直保持的一个观点就是:

一定不能把经验当教条!见过有些人,没有任何实践经验,去把《代码大全》里的内容都当教条死记硬背,这样肯定会粗大事。。。能力不够就去修炼神功,会练出内伤。。。

这种书适合多次阅读,因为随着经验的增长,每次读,都会有不同的理解,刚开始几遍可以泛读。

我现在《代码大全》估计1/10都没看到,但是每次读,我都会发现有以前读不懂的地方,现在能读懂了;以前理解的地方,现在理解更深了。

(完)