分享总结:更好地 CodeReview

  

      阅读一些网上的文章, 结合我们的具体实践, 总结一下:
 
         0.   我非常认同和拥护 CodeReview 这件事; 需要寻找更好地 CodeReview 的方法, 使之更有成效。
 
         1.   充分重视CodeReview 工作, 定期抽出时间来做这件事, 养成CodeReview的好习惯。
               每周抽出半天时间, 暂停开发工作, 主要用来做 CodeReview; 
               适当的 Develop: CodeReview 比例比单纯 Develop 价值要更优一些。
 
         2.    CodeReview, 一方面检测是否有常见错误或潜在的隐患, 另一方面要检测业务逻辑是否正确合理。
               检查第二个方面时, 一定要向代码提交者请教清楚相关的业务才可以。
 
               代码Review 不应该检测编程风格。 编程风格两次不过关的同学要暂时剥夺其提交代码的资格。
               Code reviews 不应该承担发现代码错误的职责。Code Review主要是审核代码的质量,如可读性,可维护性,以及程序的逻辑和对需求和设计的实现。代码中的bug和错误应该由单元测试,功能测试,性能测试,回归测试来保证。
 
         3.   检测出问题时, 截图及时告知代码提交同学, 避免其在很久之后才看到Review意见;
               同样, 代码提交同学修复问题之后要及时告知代码 Review 同学; 这样才完成一次完整的双向通信。
               相互告知时, 注意将 Review 链接及 Review主题带上,避免相关同学去搜索耗费时间。
 
         4.   提交代码Review的同学, 一次提交尽可能不超过 3-5 个文件,  每个文件改动不超过 30-50 行;
               如果一个改动涉及多个改动地方, 则需要进行分解这个改动点: 基础层, 服务层, 业务层。
               基础层是一些自依赖的基本方法和 Utils, DAO, 服务层是 Service ; 业务层是真正处理逻辑的部分。
               基础层和服务层通常比较容易 Review , 因为不太涉及具体业务逻辑, 只要有一定开发经验的同学就可以胜任;
               除去基础层和服务层, 业务层的改动就相对少很多, 代码 Review 压力也小不少。 
               代码提交 Review 的注释也要写清楚, 比如:
               主要完成 XXX 功能或需求或 fix bug XXX   ------- 此提交完成 DAO 相关的功能及测试;
                          (代码Review 注释的前缀)           ------- 此提交完成 Service 相关的功能及测试;
                                                                                ------- 此提交完成具体业务逻辑及测试, 有XXX 注意事项。
                
                代码提交同学应为代码 Review 的同学着想, 同时也可以锻炼自己分解功能实现、 整体设计的能力。 
 
          5.   每次提交变更尽可能小一点, 但是保证每次的变更都是正确和完整的, 合并到代码库中持续增强系统。
                持续增强的含义: 不引入 Bug 的前提下, 增添可复用的基础方法或增强系统的处理能力和处理范围;  
                这样可以考虑使用 TDD 开发模式, 写少量单元测试, 写一个小的功能实现, 然后提交, Review, 合并; 
                Continue 下一个。 每天至少可以合并 2-3 个小功能, 小步快跑。
 
          6.   提交代码更少, 代码 Review 的节奏就更敏捷; 积极看待 Review , 作为提升自己的机会。
 
          7.    提交代码标准:  
                 编译通过且可成功启动应用; 变更有相应单元测试且通过; 全量单元测试本地通过;
                 代码整洁清晰, 遵循代码规范; 适宜地处理错误与异常, 输出合理级别和合适detail的日志; 
                 消除了无用的代码、注释, 消除警告; 消除了重复代码; 没有硬编码; 没有未实现的 TODO 桩; 
                 考虑性能、安全、线程安全及死锁; 考虑(http, db, file)资源被正确释放 ;
                 适当的方法 Javadoc , 注明用途及作者、日期;  文档化边界点、例外情况、极端情况以及特殊处理。
 
          8.   不能因为业务快速多变, 就妥协 CodeReview 的标准和实践; 简化需求, 以高优先级的需求为重。
 
          9.   熟悉 CodeReview 检查项, 从而有据可依, 在开发时尽力遵循。
                Code Review 时, 不应以发现别人的错误为乐, 以发现和协助修复重要错误为宗旨。
 
              CodeReview 检查类型及优先级:
    • General Unit Testing   单元测试 = High
    • Error Handling            错误处理 = High
    • Resource Leaks           资源泄露 = High
    • Thread Safety              线程安全 = High
    • Performance               性能问题 = High
    • Functionality               功能问题 = High
    • Security                      安全问题 = High
    • Redundant Code        重复或无用代码 = High
    • Control Structures  and Logical issues    控制结构和逻辑错误 Medium or High
    • Comment and Coding Conventions       注释与代码风格 = Low
 
               CodeReview Checklist:  (相关书籍: 《Effective Java》 《Clean Code》)
           
检查项 清单项目 分类
信息安全
或权限访问
如果不用于继承,使类为final 可访问性的扩展(Accessibility Extensibility)
最小化包,类,接口,方法和域的可访问性 可访问性的扩展(Accessibility Extensibility)
为native方法定义包装类(而不是定义native方法为public) 可访问性的扩展(Accessibility Extensibility)
注释出安全相关的信息 文档化
系统的输入必须检查是否有效和在允许范围内 拒绝服务(Denial of Service)
检验输入是否含有非法或恶意字符, 防止注入性攻击  拒绝服务(Denial of Service)
避免对于一些不寻常行为的过分日志 拒绝服务(Denial of Service)
把从不可信对象得到的输出作为输入来检验 输入检验(Input Validation)
对命令行执行的代码,需要详细检查命令行参数 输入检验(Input Validation)
WEB类程序检查是否对访问参数进行合法性验证 输入检验(Input Validation)
使public static域为final(避免调用方(caller)修改它的值) 访问限制
避免服务器暴露应用系统的目录结构的配置 访问限制
定义合理的角色权限分级, 并授予合适的人员 访问限制
从异常中清除敏感信息(暴露文件路径,系统内部相关,配置) 私密信息(Confidential Information)
不要把高度敏感的信息写到日志 私密信息(Confidential Information)
考虑把高度敏感的信息在使用后从内存中清除 私密信息(Confidential Information)
重要信息如密码的保存是否选用难以破解的不可逆加密算法 私密信息(Confidential Information)
通讯时考虑是否使用了安全的通讯方式 私密信息(Confidential Information)
避免暴露敏感类的构造函数 对象构造
避免安全敏感类的序列化 序列化反序列化(Serialization Deserialization)
通过序列化来保护敏感数据 序列化反序列化(Serialization Deserialization)
小心地缓存潜在的特权操作结果 序列化反序列化(Serialization Deserialization)
只有在需要的时候才使用JNI 访问限制
   
并发安全 代码中所有的全局可见可变变量是否是线程安全的 并发
需要被多个线程访问的对象是否线程安全,有无通过同步方法保护 并发
同步对象上的锁是否按相同的顺序获得和释放以避免死锁,注意错误处理代码 并发
是否存在可能的死锁或是竞争 并发
对共享可变的数据使用同步访问 并发
使用executors而不是task和thread ; 使用并发库、框架而不是线程对象 并发
   
性能 同步方法是否过度使用, 同步区域是否过大 并发
拼接大量字符串时是否使用 StringBuilder 而不是 String  综合编程
处理大量数据时,是否选取了合适的数据结构和高效的算法 综合编程
对hashtable,vector等集合类数据结构的选择和设置是否合适,如正确设置capacity,load factor等参数,数据结构的是否是同步的 综合编程
有无滥用String对象, 不停地创建 String 对象 综合编程
是否采用通用的线程池、对象池、连接池等cache技术以提高性能 综合编程
是否采用内存或硬盘缓冲机制以提高效率 综合编程
I/O方面是否使用了合适的类或采用良好的方法以提高性能(如减少序列化,使用buffer类封装流等) 综合编程
递归方法中的叠代次数是否合适,应该保证在合理的栈空间范围内 综合编程
如果调用了阻塞方法,是否考虑了保证性能的措施 综合编程
避免过度优化,对性能要求高的代码是否使用profile工具,如Jprobe等 工具使用
   
通用 避免重复代码 综合编程
在public类中,使用访问器方法(getter/setter方法)而不是public域 类和接口
最小化局部变量的范围, 需要使用时才定义 基础
遵循广泛接受的命名规则, 排版、缩进、空白行、格式化等 基础
使用枚举来代替 int, string 常量 基础
使用标记接口(marker interface)来定义类型 基础
数组类结构是否做了边界校验 基础
变量在使用前是否做了初始化 基础
注释中适宜地描述了方法的用途、业务逻辑、作者及日期 基础
   
静态代码检查 查看静态代码分析器的报告来进行类的添加和修改 工具使用
资源回收与泄露 是否集合中的失效对象的reference 已经设置为 null 可以被回收 综合编程
是否所有的资源对象被正确释放,如数据库连接、Socket、文件等 综合编程
资源是否被释放多次 综合编程
避免使用finalizer 综合编程
   
控制流与逻辑 循环初始值、结束条件以及循环变量递进是否正确 基础
是否避免了死循环的产生(for, 递归, 对象嵌套) 基础
循环次数是否正确 基础
是否在 for 循环的过程中删除元素 基础
switch case 是否缺少 break 和 default; 基础
if-else 嵌套是否正确 基础
&&, ||, ! 逻辑运算符是否使用正确 基础
   
数据库访问 数据库设计或SQL语句是否便于移植(注意和性能方面会存在冲突) 综合编程
数据库资源是否正常关闭和释放 综合编程
数据库访问模块是否正确封装,便于管理和提高性能 综合编程
是否采用合适的事务隔离级别 综合编程
是否采用存储过程以提高性能 综合编程
是否采用PreparedStatement以提高性能 综合编程
   
网络通信 socket通讯是否存在长期阻塞问题 综合编程
发送接收的数据流是否采用缓冲机制 综合编程
socket超时处理,异常处理 综合编程
数据传输的流量控制问题 综合编程
   
错误处理 每次当方法返回时是否正确处理了异常,记录日志到日志文件中 日志
是否对数据的值和范围的合法进行校验 输入检验(Input Validation)
在出错路径上是否所有的资源和内存都已经释放 综合编程
所有抛出的异常都得到正确的处理,特别是对子方法抛出的异常,在整个调用栈中必须能够被捕捉并处理 异常
当调用导致错误发生时,方法的调用者应该得到一个通知 异常
对可以恢复的情况使用已受检异常(checked exceptions),对于程序错误使用运行时异常(runtime exceptions) 异常
是否更多地使用标准异常 异常
是否定义了具有合理名称的自定义异常 异常
是否“默默地吞掉了”异常 异常
   
面向对象编程 通过接口而不是实现类来引用对象, 是否符合面向接口编程的思想 设计与重构
方法API是否被良好定义, 便于维护和重构 设计与重构
重写对象的equals时, 总是重写hashCode 基础
总是重写对象的 toString 基础
对象的传值或传引用方面有无问题 基础
需要 update 的对象的值是否正确地设置 基础
是否大量或频繁地创建临时对象 基础
是否尽量使用局部对象(堆栈对象)  基础
是否使用了全局可变对象且在某处代码里进行了修改 基础
是否修改了全局可见 final Reference 的内容  基础
在只需要对象reference的地方是否创建了不必要的对象实例 基础
类的接口是否定义良好,如参数类型等,避免内部转换 基础
是否有丑陋的强制类型转换 基础
是否存在不必要的使用反射来获取私密信息 基础
返回堆对象的reference,不要返回栈对象的reference 基础
   
测试 代码变更存在有效的单元测试用例 基础
是否对错误处理部分的代码进行了测试 基础
   
代码规范 是否符合JAVA编码规范(Java Code Conventions) 标准规范
其它 配置信息如何获得, 是否有硬编码            配置
 
 
      关于工作效率:
      
1)增加有用功
 
你得多问问你的需求方,为什么要加这个需求?干这个事到底有多大的价值?能让多少人受益?
你得多问问你的需求方,能不能稍微简化一下需求,这样可以让我付出的努力更少一些?
你得要多去思考一下,你是在干一个建筑队的活呢?还是在干一个装修队的活?
你得要多去思考一下,业务上和用户的最大的痛点是什么?
 
像乔布斯那样,告诉你的产品经理或是业务方,你现在提的10需求,我只能做3个,会是哪3个?为什么是这3个?有用功的来源不是拼命做需求,而是砍需求。
 
2)降低总功
 
你得多问问自己,你有多少时间是在干一些支持性而不是产出性的工作?
你得多问问自己,有没有残酷无情地减少重复劳动的劳动密集型的工作?
 
3)形成合力
 
有一个很不错的产品经理对我说,他看了南京那两个小女孩被饿死的消息,感到很震惊。与之有关联的每一方都说自己尽力,但是最终结果人还是饿死了,你几乎不敢相信这是真的。
 
类比一下我们的项目,这种事似乎又发生在我们的公司当中,尤其是大公司中。每一个团队都说自己尽力了,结果项目就是没做好,底层团队说自己只干底层,已经尽力了,前端说自己只负责前端,也尽力了,后端说自己只管后端,不管前端和底层,运维说对于这样的设计和部署自己也尽力了,产品经理,运营都这样说,自己尽力了。你会发现,你几乎很难批评他们,因为他们的确如他们所说的那样,把他们自己的那块都做得很好了,而且的确做得很好了。但是,最终的结果却是:整个产品问题很多。
 
所以说,效率不是每个团队各自的效率,而是整个团队对整个产品负责的共同使命,这样才会现整体的效率。没有整体的效率,只有个体的效率,最终也等于没有效率。
 
T-Shirt Size Estimation
 
Amazon用一种T-Shirt Size 估计的方式来做项目。
 
产品经理会对每一条需求评估上业务影响力的尺寸,如:XXXL 影响一千万人以上或是可以占到上亿美金的市场,XXL,影响百万用户或是占了千万金级别以上的市场,后面还有XL,L,M,S,这样下来。
开发团队也一样,要评估投入的人员时间成本,XXXL表示要干1年,XXL干半年,XL干3个月,L干两个月,M干一个月,S干两周以下。等等。
于是,
当业务影响力是XL,时间人员成本是S,这是最高优先级。
当业务影响力是M,时间人员成本是M,这是低优先级。
当业务影响力是S,时间人员成本是XL,直接砍掉这个需求。因为是亏的。
当业务影响力是XXL,时间人员成本是XXL,需要简化需求,把需求简化成XL,时间人员成本变成M以下。

         

 

         参考文章:
         1.   《11个高效的同行代码评审最佳实践》:     http://kb.cnblogs.com/page/153632/
         2.   《Java CodeReview 清单》:                http://www.importnew.com/12511.html

 

         3.   《CodeReview是什么》:                         http://www.cnblogs.com/panshuiqing/articles/1147065.html

 

         4.   《Code Review Guidelines》:                http://www.codeproject.com/Articles/524235/Codeplusreviewplusguidelines

 

         5.   《Rework摘录及感想》:                        http://coolshell.cn/articles/9156.html 

 

 

         7.   《从CodeReview谈如何做技术》:         http://coolshell.cn/articles/11432.html       
         8.   《CodeReview Check list》:                http://blog.csdn.net/echoisland/article/details/7220991

 

 

你可能感兴趣的:(code)