最近抽空阅读了一下《代码简洁之道》这本书,总结了其中一些核心的观点和指导,供大家快速学习。
第一章:整洁代码
阅读本书由两种原因:第一,你是个程序员;第二,你想成为更好的程序员。很好,我们需要更好的程序员。
勒布朗(LeBlanc)法则:稍后等于永不(Later equals never)
我们经常觉得为了赶进度要先把任务完成,以后有时间再优化,而事实上是,我们干完手头的任务马上就会有新的任务,那么就不会再去优化原来的代码。
专业的程序员不应当因为产品或者领导对于进度的把控而丧失对项目与代码的控制权。就像文中的一个例子,病人请求医生尽快做手术而不用浪费时间在术前的洗手上,但是做为医生,你不会听从病人的要求。因为从专业的角度看,医生比病人更了解疾病何感染的风险。如果听从了病人的要求,那就是不专业的表现。
赶上期限的唯一方法——做得快的唯一方法——就是始终尽可能保持代码整洁。
比如完成一个项目,你先用了简单的、复制粘贴的的方式,用了8个人日完成,然后又用了3个人日去做优化。还不如先用3-4个人日去做设计与思考,这样做起来很快,可能之后只要4-5个人日就完成了。
什么是整洁代码?
简单说,就是优雅与高效
如果再往细了说,应该有以下几点:
- 逻辑直接(让别人一眼就看懂你的代码做的是什么工作)
- 减少依赖关系
- 完善错误处理
- 没有重复代码
- 抽离与至简(一个代码块只做好一种工作)
美国童子军的军规:让营地比你来时更干净
换成程序员的话:让你接手的代码比之前更整洁
小提琴家在去表演的路上迷路了,他在街角拦住了一位长者,问他怎么才能去卡耐基音乐厅(Carnegie Hall),长者看了看小提琴,有看了看他手中的秦,说道:“你还得练,孩子,还得练!”
换成程序员的话:你还得多写代码,孩子,多写!(不要停留在写重复代码的层次,要写更优雅的代码!)
第二章:有意义的命名
对于这一掌,我感觉作者列出了很多点,但是与我们的实际工作可能还是有些区别,所以这里的总结,不再按照文章的顺序,而是列出总结点
- 变量不要使用a,e,d这种单字符,鬼知道你命名的是什么意思
- 也不要使用变量的类型直接命名,比如叫arr1,list1这种
- 文章中不建议使用变量名+类型这种方式命名,比如叫nameStr,accountList,用name或者accoutGroup更好(个人以为对于基础类型不要使用类型,在Java等强类型语言中,最好都不加类型,但是对于JS这种,其实加上Arr等可以更好的让读者知道变量的数据类型)
- 不要使用小写的l和大写O,容易混淆(还好,这种情况一般见不到)
- 做有意义的区分,主要是两点,不要用数字系列命名,比如a1,a2这种;也不要说废话,比如Product,ProductInfo,ProductData,Info和Data就像废话(这点不是很赞同,我觉得加上Info更好,作者的理由是这样的区分不是很明显,当然如果有明确的约定,就不是这样了)
- 使用能读出来的名称,不要使用英文缩写或拼音(国内程序员很容易犯得错误)
- 对于单字母名称和数字常量,使用某个常量代替更容易搜索(这个确实,搜索e或者1太难匹配了)
- 避免使用编码和不必要的前后缀
- 避免思维映射(不要让读者看到这个名称再去映射到常用的名称,这一点遇到的还真不多)
- 类名和对象名一般是名词,不要使用动词
- 方法名一般是动词
- 对于方法的属性访问、修改和断言,一般加上get/set/is前缀
- 不要使用俚语和方言(很少遇到)
- 在不同的类中,对于相同的操作,该概念使用相同的词,比如获取数据的方法都叫做fetch(这点我做的还不错)
- 避免使用双关语,比如同样是添加的意思,add最好还是用于数字或者字符串相加,而往数组里添加元素,使用insert代替
- 区分解决方案与问题领域对应的名词,对于接近程序员的话,就用计算机专业术语,对于其他领域,则用他们的专业词汇
- 对于语境的判断(其实就是添加专用的前缀,以及将隶属于同一个语境的变量进行对象抽离,这个不太好做,一个是对于某些情况,使用合适的语境。另一些则不要加没必要的语境。)(在JS中,可以用一个对象包装多个属性,这样就不用都加前缀了)
我做的不好的地方:
- 有时还是会用arr1这种写法
- 对于add/insert的区分是不明显的
- 某些情况存在废话
- 不同的Class里,同样的操作,因为历史原因,命名方式不一样
- 对于常量没有做重命名的操作,所谓的魔术数字
- 单字符还是会用到一些
改善:
- 不要使用单字符或者arr1这种命名
- 对于添加的操作,一律才有add,而不用create与insert,保持统一
- 精准的语境,区分明显,没有废话比如(address和addressInfo,后者就是废话),同类操作保持一致
- 常量的抽离(常见的就是URL的抽离)
第三章 函数
3.1 短小
js中也把函数写的更短小
3.2 只做一件事
js也是一样,一个函数做的事情多了,就拆分
要区分重新诠释代码和改变抽象层级是不同的概念(比如把一个if判断又拆出来,就是重新诠释,没什么意义)
//抽象层级
function test() {
if(true) {
functionA();
}else {
functionB();
}
}
//重复诠释;
function test2() {
function test3();
}
function test3() {
if() {
do something;
}else {
do something other;
}
}
3.3 每个函数一个抽象层级
这一章主要还是讲的自顶向下读代码:向下规则
这个对React来说其实不太容易实现,因为render方法往往在最后,而函数又是绑定在render里,那就要实现自下向上去找了
3.4 switch语句
对于多个需要使用switch的地方,将其封装成一个类,避免每个函数都写switch
3.5 使用描述性的名称
- 别害怕长名称(用缩写可能还要写长注释,还不如直接写长名称!)
- 别害怕花时间取名字
- 选择描述性的名称
- 命名方式要保持一致
3.6 函数参数
最理想的参数数量是零,其次是一,二,三,超过三个以上时,就要考虑用对象将参数包起来了(但是这样有一个问题,还要在注释中加上参数有哪些;或者在函数声明时,使用解构,这样也可以,但是用户需要查找函数声明才能知道传些什么。。)
对于多参数函数,要注意参数顺序,最好符合自然顺序,或者别的某种规律
这本书读起来真是让人感觉压力很大,主要还是对Java语言不熟,很多描述,我觉得太复杂了,其实表达的意思很简单;另外一点令人头疼的是,很多以前养成的不好的编码习惯,要逐渐修改,这个是有点难的,要时刻记着,占用大脑内存。
3.7 无副作用
这一节主要还是说明,函数应该只做一件事,而不应该在里面隐藏着其他的操作,比如一个校验密码的函数checkPassword,如果里面还加了session的操作,那就不对了!
3.8 分隔指令与询问
其实还是一个函数只做一件事,这里举得例子是setter和getter要分离,不过按照这个原则,那么jQuery很多函数,例如设置css、获取css是一个函数,只是参数不同,是否违背了这种原则呢?(我猜是函数内部又拆了若干子函数,这样就可以说的过去了!)
3.9 使用异常提代返回错误码
抽离try/catch代码模块,这里说的主要是把其中的代码块抽离,另外形成函数(这样做是可以接受的)
错误处理只做一件事(还是函数单一性原则)
返回错误码在Java中式枚举类型,而Java是静态语言,一旦错误码的内容新增,其他引入的模块,都需要重新编译和部署,所以作者建议使用异常代替错误码
但是,对于JS是不存在这样的问题的!因为我们是动态语言啊!
3.10 别重复自己
减少重复代码,这个无需多说。
3.11 结构化编程
Edsger Dijkstra认为函数应该遵循单一入口和单一出口,即只有一个return语句,循环中不能有break和continue语句,永远不能有goto语句。
作者在这里是持批判性看法的,对于简短的函数,上面的规则没什么用。对于大函数,可以考虑,避免使用goto是赞成的。
3.12 如何写出这样的函数
作者说并不一开始就按照这些规则写函数(他认为没人能做到),而是写完后再优化。
我的想法和他不太一样,除非工期很紧,我还是建议先想好函数的结构再去写。