One minute
Clean Code 读书笔记
最近一直都在读这本书,我买的是kindle电子版的,所以平常上下班坐火车的时候,有时间就拿出kindle读一读。整本书阅读下来收益匪浅,以下就是我在阅读的过程中获得一些体会。
软件开发是一门工程,但是又不同于其他的建筑工程,因为软件工程可以推倒重来。在开发地过程中,我们不仅要写出整洁干净的代码,而且还要使代码具有可阅读性,方便之后的维护人员理解这个变量,这行代码,这个函数,这个类到底是用来干什么的。我通篇阅读下来,觉得整本书的核心思想其实就是一个术语:
Single Responsibility and descriptive name
名字 variable
不管是变量,方法,类,名字一定要有描述性,这样阅读的人能够看一眼,就知道这个东西是用来干什么的。
函数 method
- 函数要尽可能短小精炼,每人喜欢读一个几百行的函数。另外,要使一个函数只做一件事情,这样函数名字就可以以很短的长度来形容函数的功能。
- 函数的参数要保证尽可能的少,过多只会误导读者或者加大阅读系数
- 不要传入布尔值进入函数,因为当你传入一个布尔值进入函数,通常意味着这个函数会做两件事:当这个参数为真时,函数做这件事情,当它为假时,函数又做另外一件事。仔细思考是否可以把这个过程拆分成两个函数。
- 参数是输入值,就尽可能只用于输入值,否则容易造成盲区,因为调用者没有意识到这个参数既是输入值又是输出值。
- 尽量避免一次性反复调用,例如 methodA().methodB().methodC()。如果以后需要添加一个methodD在methodA和methodB之间的话,你需要找到所有的这种代码修改。从另一种角度上来讲,这种写法提高了methodA对methodB的耦合性,不易于以后的维护。
类 class
- 类里面的变量和函数要保证逻辑上的一致性。举个例子就是,如果你有一个类,它是用来生成一个特定格式的pdf文件,它有一个方法,参数是要进入报告的数据,然后生成pdf的二进制。那在这个方法里,你只能做渲染的工作。而不是又把输入的数据再进一次处理加工,再生成报告。
- 类与类之间,尽量使用抽象化的接口交流。因为你一旦使用了一个实现类的接口,那就会导致调用这个接口的方法/类对这个外部的类具有依赖性。
- 成员变量应该赋予最少的访问权限,如果之后有需要,才看是否应该提升它的访问权限(private -> protected -> package -> public)
- 写类和子类的时候,应该多思考,哪些变量是属于具体类,哪些变量应该是放入抽象类的。尽可能把接口抽象化,这样不仅有利于之后的维护,也方便写单元测试。
枚举 Enum
- 枚举是一个很有用的东西。在Java5之前,如果你要创建一种类型(type),通常是创建一个接口或者在一个类中,声明一系列的public static final int/String成员变量(注:这种做法很普遍,我们公司的一个数年之久的JavaEE程序,里面到处都是这样的实现方法),因为他们具体存储的是一个数值,数值在逻辑上是毫无意义的,通常还会造成阅读困难。所以当你需要创建一系列类型的时候,尽量使用enum,因为它不仅使之后的类型判断更易于阅读,同时你也可以在其中创建方法,更易于写出简洁的代码。
注释 Comment
- 有些人喜欢在修改bug的时候,加上一句日志:某年某月,某某某,改动这个的原因。其实这是很不必要的,因为这应该是你的版本管理和issue追踪系统该做的事。这样会导致代码信息过多,逻辑复杂。而且代码是会进化的,可是老的注释却不会。所以碰见这样的注释就删掉吧。
- 注释掉的代码。这应该是版本管理工具该做的事情。该删就删掉,保持代码的简洁。
- 有些人可能会觉得注释要是删掉了,会导致代码阅读的苦难提升,怎么办?其实,就有如前面的要点所说,假如你的代码(变量名,方法名等)本身具有阅读性,那么注释其实是多余的。
重构 Refactor
- 代码不可能是一直都不变的,或者一直都是整洁的。老旧的代码如果长期存在,我们又在上面构建新的代码,会导致后期的维护成本提高。因此,当开发的时候,能把代码变好一点就变好一点,不要觉得这个是浪费时间。
- 重构代码的最大问题在于,可能会对现有的逻辑造成破坏,因此我们需要单元测试。其实不管你是重构代码还是写新的代码,单元测试都是很重要的。因为大型的软件开发通常都会遇见一个常见问题:程序员修改了一个地方A,结果导致另一个地方B出现问题。假如有一个单元测试正好测试了这个地方B的逻辑,那么在integration build里,他们就能很快的意识到出了问题进而改正。
并发 Concurrency
最后,书上还花了一些篇幅写了Java中的并发。
Java5中加入了很多并发的工具,大部分都在被放在了这个包中:java.util.concurrent。本质来讲,当你要实现一个并发的程序的时候,你要使你的操作是atomic。我对atomic的理解就是操作的最小部分。作者举了个例子,一段两行的java代码(java代码是编译成byte code执行的,所以一段两行的代码,在bytecode层了,可能就变成了七八个操作了,入栈,出栈,复制,加值等),可能会形成多种路径,大部分路径得出的结果都是正确的,但是小部分就是概率问题了。但是既然它们有可能出现,我们就得预防,所以对于并发的代码,我们得尽量是使我们的操作原子化。说到操作,本质上就是对于一个变量改来改去,concurrent的包里就提供了很多类型与集合来保证每一步的操作都是原子化。
总结
以上基本上是我读了这本书获得的体会,感觉才获得了百分之三四十的知识,如果有机会的话,我会再读一遍,结合我在工作中的心得,来加深理解。