一、有意义的命名
-
名副其实
让变量、函数、参数、类和封装的命名具有实际意义,好的命名具有自注释性
-
避免误导
- 避免使用与本意相悖的词,例如accountList,除非它真的是个list
- 避免使用差异较小的名称,例如
XYZControllerForEfficientHandlingOfStrings
和XYZControllerForEfficientStroageOfStrings
就很难辨别 - 单纯的字母l和o具有误导性,例如”lo”容易被误人为是”10”
-
做有意义的区分
- 避免使用数字字母序列:A1,A2,A3…
- 少说废话,例如已经有了一个
Product
类,再添加ProductInfo
和ProductData
就很有混淆性,因为Info
和Data
在这里意义不大
-
使用读的出来的名称
易读的名称便于讨论,例如
generationTimestamp
就比genymdhms
要好 -
使用可搜索的的名称
- 使用有意义的宏变量名代替阿拉伯数字,便于搜索和维护,例如
MAX_CLASSES_PER_STUDENT
就比数字7好搜索很多 - 名称长短与作用域大小相对应,作用域越大名称应该越长
- 使用有意义的宏变量名代替阿拉伯数字,便于搜索和维护,例如
-
类名
类名和对象名应该是用名词或名词短语,不应当是动词
-
方法名
方法名应该是动词或动词短语
-
给每个抽象概念选一个词,并且一以贯之。
例如fetch,retrive和get只需要选一个词来表示这个概念即可
-
别用双关语
避免使用一个有多重意思的词作为名称
-
起其他程序员看得懂的名称
尽量在程序员的知识背景中选择名称,而不是其他领域的专业名词,毕竟你的代码是给程序员看的
-
为名称添加语境
使用前后缀或者类把相关的名称关联起来,便于理解
-
取名称最难的是需要良好描述技巧和共有文化背景
二、函数
-
函数应该尽量短小
-
代码块与缩进
函数的缩进层级不宜多于一层或两层
-
函数只做一件事
函数应该做一件事,做好这件事,只做这一件事
-
每个函数一个抽象层级
- 每个函数内应该只包含一个抽象层级的代码,混有多个抽象层级代码的函数容易使人迷惑
- 函数与函数之间应该抽象层级逐步降低,每个函数后跟着更低抽象层级的函数,这样便于自上而下的阅读
-
使用具有描述性的名称
-
名称应该较好的描述函数所做的事,长而具有描述性的文章比短而令人费解的名称好
-
命名方式要保持一致,函数名应与模块名一脉相承
-
-
函数参数
函数参数数量越少越好,零参数函数最好,单参数函数次之。较多的函数参数会增大测试工作的复杂性
- 尽量避免使用表示参数,向函数传入布尔值不是一种好做法。可以将函数一分为二来替代
- 对于一元函数,函数名和参数名组成动词/名词对有助于理解,例如write(name)
-
分隔指令与询问
将指令与询问放在一起不利于提高程序的可读性,为了避免这个问题可以将指令与询问分割开来
-
使用异常替代返回错误码
善用异常,有利于指令与询问的分离
- 抽离Try/Catch代码块,将其从主体函数中抽离出来
- 错误处理只做一件事,处理错误的函数不该做其他数
-
避免代码块的重复
重复就会带来问题,许多原则与实践规则都是为了控制与消除重复而创建的,例如面向对象编程、面向方面编程和面向组件编程等等
-
避免使用goto语句
-
先写出来再慢慢打磨
先实现函数功能,并辅以单元测试。后期再打磨代码、分解函数、修改名称、消除重复
没有人可以一开始就按照规则写函数,好的代码需要反复打磨
三、注释
不准确的注释比没注释坏的多,应该时刻记得尽量减少注释
-
注释救不了烂代码
-
好的名称可以起到注释的效果
-
值得写的注释
- 法律信息,包括版权和著作声明
- 提供信息的注释,帮助程序员理解代码
- 对意图的解释,解释代码的设计思想
- 阐释,把某些晦涩难懂的参数和返回值翻译成可读形式
- 警示,用于警告其他程序员会出现某种后果
- TODO注释,用于记录待办事项,所以要定期查看定期处理
- 放大,放大某些看似不合理之物的重要性
-
不值得写的注释
-
喃喃自语,写出来只能给自己看的注释
-
多余的注释,如果代码本身比较简单,写出冗长的注释显然是不值得的
-
误导性注释
-
循规式注释
-
日志式注释,记录代码修改的每次记录是完全不需要的,不然要git干嘛
-
废话式注释,用整理代码的决心替代创造废话的冲动吧
-
能用函数或变量就别用注释
-
少用位置标记,减少背景噪音
-
括号右边的注释
例如:
while(step==END){ ... } //while
正确的做法应该是减少函数的行数,而非添加括号注释
-
归属与署名注释,同样可以被git完美替代
-
注释掉的代码,注释掉的代码没人敢动,最终会越积越多。尽量减少注释掉太多的代码
-
HTML注释
-
非本地信息,描述远在他方的其他函数往往让人不知所云
-
与代码没有明显联系的代码,注释的作用是解释未能自行解释的代码,如果注释本身还需要解释那就太遗憾了
-
函数头注释,写函数头注释不如为一系列短函数起好名字
-
四、格式
-
格式的意义
代码格式关乎沟通,而沟通是专业开发者的头等大事
-
简洁有条理
源文件名称应该简洁且一目了然,源文件顶部给出高层次概念和算法。细节往下渐次展开,知道找到源文件中最底层的细节和函数
-
垂直方向上的区隔
在封包声明、导入声明和每个函数之间,都有空白行隔开,标识出新的独立概念的出现
-
垂直方向上的靠近
紧密相关的代码应该相互靠近
-
横向格式
一行保持在80个字符以内,至多不能超过120
-
赋值操作在”=”两段加空格,起到强调赋值操作效果的作用
-
在函数名和左圆括号之间不加空格,因为函数名与函数参数有着强相关,加了空格就会显得两者毫无关系。
-
用空格把函数调用参数相互隔开,强调逗号,表示函数的各个参数是互相分离的
-
空格还可以用来强调前面的运算符
例如:
double determinant(double a, double b, double c){ return b*b - 4*a*c; }
这种灵活的空格用法强调了较低优先级的加减法运算,使之不易被忽略
-
-
遵守团队规则
五、对象和数据结构
-
得墨忒耳律
模块不应该了解它所操作对象的内部情形
六、错误处理
-
使用异常而非返回码
-
先写try-catch-finally语句
先搭建好异常捕获的框架在向其中补充具体的异常处理方法
-
使用不可控异常