2007-06-30

Java/OOP Code Inspection Checklist

Code Inspection的checklist可以分两方面内容:基本编程原则检查和语言相关检查

基本编程原则

基本编程原则对大多数语言都适用,尤其是面向对象语言。

  • 格式
    • 由于有IDE(Eclipse, Netbeans……)的支持,代码格式可以很容易地自动编排,统一大家的代码格式很方便。
    • 乱糟糟的代码看起来很晕,没法让大家集中精力检查。
  • 命名
    • “编程语言”也是“语言”,需要传递信息。编程语言的规则能保证计算机能理解,但不能保证人能很好地理解。为了让人能理解,必须在变量、方法、类等命名方面下功夫,让人见名知意。
    • 有一些基本的规则,如:类用名词、方法用动词、变量用名词等,可以参考各语言约定俗成的编程规范。
    • 好的命名可以极大增加程序可读性。文档、注释也是为了理解程序。相较而言,程序同时还是最终真正“产品”,因此,应当让程序自身可读性加强,减少对文档和注释量的需求。这样在维护代码时会减少对文档和注释的维护量。
  • 消灭魔数
    • 所谓“魔数”指的是程序逻辑中包含的数字,这些数字可能在多处出现,或可能随时调整,如:
      • if(user.type==1) ......
    • 1代表嘛意思?得写个注释。如果定义成常量,有个名字,这地方就好理解多了。同时修改常量值比在代码中到处替换容易多了。
  • 注释
    • 意义就不用说了,老生常谈了。
    • 虽然老生常谈,但往往做成了两个极端:太少,太多。
      • 太少不奇怪,毕竟没有注释编译时也不会报错,人本性总有惰性。
      • 太多怎么可能呢,多了怕嘛?!的确有太多的情况出现,恨不得每一句话都写一个注释,解释这句话的作用,或者在每个方法、程序块前详细描述其中的操作过程,代码就是注释的映射。这就太过了:首先,打开程序看的应该都是程序员,看合格的代码应该不会比看大段的注释难,注释白费了。其次,稍微修改程序就得同步修改注释,否则以后以谁为准?麻烦得很!
    • 注释解释这段代码解决什么问题;代码本身接受如何解决。
  • 解决两地分居
    • 变量声明和使用相隔太远,或超过了必要的生命范围。
    • 在某些语言中,这是语言自身的限制,只得将就了。但对于变量声明位置灵活的语言,再这样做就不厚道了。
    • 变量就近声明;最小化生命范围。
  • 重复代码
    • 计算机上copy & paste太方便了,以至于大段的代码在程序中不断copy & paste。
    • 由于copy & paste的太快,往往该改的地方没有改过来,产生bug。
    • 修改代码的时候,由于被paste到太多地方,往往修改不完全,产生bug。
    • 应该训练一种意识,写代码时只要按ctrl+C的时候就好好想想能否把copy的东西抽出来做成共用方法,避免重复代码。
    • 即使没有copy & paste,多次手写重复代码也应有以上意识。
  • 长方法
    • 长方法难于阅读,受限于人脑的“缓存”,往往读了后面忘了前面,尤其在上下翻屏的情况下。
    • 抽出多个方法。主逻辑中通过方法名就可以知道逻辑过程,岂不美哉?!
    • 抽出的方法别其他地方调用的可能性大大增加,减少重复代码。
  • 巨类
    • 无所不包的类。由于包含了太多的功能,没有一个明确的现实对应,“四不象”。命名困难就是一个信号。
    • 一个类只应该有一个方面功能,不要多管闲事。
  • 耦合度
    • 类/模块之间的耦合度应尽量低。来回频繁反复调用应该避免。
    • 往往由于类/模块之间功能划分不合理造成。把方法放到合适的类/模块中去。
    • 调用者在一个逻辑中多次调用被调用者的方法。可以认为是“微观管理”。
      • Don't ask for the information you need to do the work; ask the object that has the information to do the work for you.
  • 滥用全局/成员变量
    • 全局变量是否是必须的?
    • 成员变量是否应该是类的一个属性?
  • ……

语言相关检查

各语言有自己的pitfalls需要检查。例如Java中:

  • null
    • 是否在使用对象变量前判断不等于null?
  • equals
    • 对象的比较应该用equals。除非比较两个对象是否为“同一”对象,否则不能用==比较。
    • 自定义类,如果需要用equals比较,是否重写了equals方法?
  • 资源释放
    • 如IO操作使用的file、socket等资源,需要在使用后主动释放。
    • 为了保证资源的释放,需要在finally中主动释放。
  • ……

没有评论: