为什么要进行Code Review?
- 自我提升工程师个人技术水平。
- 增强代码质量,统一代码的风格,提高可读性,发现潜在bug,降低后期团队维护成本。
- Code Review必然要面对重构,这是很好的锻炼编码技巧的机会。
- 为团队合作提供交流分享的机会,代码贯穿于团队,不再是一个人掌握一块代码。
- 总结错误,提高今后设计开发的预见性。阶段性总结对团队是有益的,可以逐渐培养形成团队的编程规范习惯。
Code Review的层次
- 基本的层次就是编码规范,包名,类名,变量名,方法名等。
- 高层次的就是代码质量,在保证代码的美观后,要保证代码的合理性,健壮性,可读性,可维护性等等。
基本的代码规范就不说了,之前的文章介绍过了,下面列举一些个人总结的关于Code reivew经验:
1. 异常处理:使用try-catch-finally进行异常捕获处理。
凡是会抛出异常的地方都进行捕获,你可以在catch中处理异常,如果不想处理则throw这个异常,由调用者去try-catch处理:
涉及到资源关闭的记得在finally中关闭资源:
另外不要在循环体中捕获异常,放在最外层,以提升性能。
2. 空指针,千万不要理所当然的以为一个对象不会为空,在使用一个变量之前一定要进行判空处理,做好充分的容错处理。
3. 数组越界,使用数组、List之前检查索引和长度。
4. 魔鬼数字:直接写在代码里的数字,一定要用常量符号代替。
5. 对于可以复用的部分,提取成共用的方法或工具类,减少代码量。
6. 删除无用的变量和无用的引入。
7. 代码中的中文字符串最好统一在strings.xml中定义。
8. 所有Activity可继承自一个BaseActivity,便于统一行为管理,构建对话框统一构建器的建立,万一需要整体变动,一处修改到处有效。
9. 数据库表段字段常量和SQL逻辑分离,更清晰。
10. 全局变量放全局类中,模块私有放自己的管理类中,让常量清晰且集中。
11. 不要相信庞大的管理类的东西会带来什么好处,可能是一场灾难,而要时刻注意单一职责原则,一个类专心做好一件事情。
12. 多线程操作数据库时,db关闭了会报错,可能出现互锁的问题,使用事务。
13. 开始之前考虑哪些可以公用,资源,layout,类,做一个结构/架构分析以加快开发,提升代码复用度。
14. 关于形参实参:参数为基本类型传的是传值;参数为对象传递的是引用,即传址,这种改变会作用于原来对象。
15. 控制Activity的代码量,保持主要逻辑清晰。其他类遵守SRP(单一职能),ISP(接口隔离)原则。
16. Log请打上Tag,调试打印一定要做标记,能定位打印位置,否则会尴尬不知道是哪里在打印。
17.与Activity通讯使用Handler更方便; 如果你的框架回调链变长,考虑监听者模式简化回调。
18. 构造函数里面不推荐启动异步线程,会埋下内存隐患。
19. UI显示注意内容过长的情形要提前使用ScrollView否则在小手机上尴尬你懂得。
20. String的比较用equals,不要一时犯傻用了==。
21. Long a; 判断a有没有赋值,if(a == 0)在a没有赋值情况下会报错。应该if(a == null),Integer、Floag等也一样。
22. 编码遇到读写、出入等逻辑要双向考虑,文件导入导出,字符字节相互转换都要两边转码。
23. 从资源文件或者文件加载一张图片时注意其宽高,避免OOM, bitmap的内存占用是宽x高x单位像素占用字节(RGB565是2个字节,ARGB8888是4个字节)。
24. 对于并不那么注重访问性能的较小集合而言,List 则是合理的选择。for循环对下标没有要求的优先使用foreach循环。
25. 选择正确的集合类型使你能够在集合性能与内存占用之间达到合理的平衡。例如某些情况下用SparseArray代替HashMap。
26. 充分利用封装(提供接口类来控制访问数据)和委托(helper对象来实施任务)两种理念。
27. 当逻辑没有明显问题时考虑对象属性、函数参数、网络传输参数是否全部了解,是否设置正确。
28. 拼接字符串避免String进行频繁+操作,应该使用StringBuilder提升性能,多线程使用StringBuffer操作string提高程序效率。
29. 基本数据类型定义的变量称自动变量,存的是‘字面值’,存在于栈中,可共享(存在即不新建)。
30. 只要是用new()来新建对象的,都会在堆中创建,而且其数据是单独存值的,即使与栈中的数据(值)相同,也不会与栈中的数据共享。
31. 能复用同一个对象处理的尽量复用,不要使劲的在那里new对象,内存吃不消,尤其是for循环等。
32. 改变逻辑的时候考虑全部用到这项功能的地方,分散的地方多了可能会忘记,不要为了填坑而挖了一个坑。
33. 不要在布局文件xml中使用onClick属性,如果你忘了在代码中声明onClick方法就会悲剧。
34. 注意参数的++或者--操作的区别。
35. 服务端可以实现的,就不要放在客户端。
36. 引用第三方库要慎重,避免应用大容量的第三方库,导致客户端包非常大。
37. 重复类似的功能在统一个类中去实现,而不是重复的去new一个相同类的实例,如activity中在一个View.OnClickListener中处理所有的逻辑,接口回调在同一个callback中处理。
38. 多用组合,少用继承。
39. 合理布局,有效运用<include> ,<merge>、<ViewStub>等标签。
40. 尽量采用懒加载的策略,即在需要的时候才创建。
41. 尽量使用HashMap、ArrayList、StringBuilder,除非线程安全需要,否则不推荐使用Hashtable、Vector、StringBuffer。
42. 可以使用局部变量代替的,尽量不去创建全局变量。
43. 一个接口可以解决的事,尽量不去导入一个框架。
44. 控制一个应用中的单列使用场景,防止滥用,单例主要用于控制资源的并发使用、 控制实例的产生, 控制数据的共享。
45. 基本数据类型转为字符串,推荐方式为:基本数据类型.toString()、String.valueOf(数据)次之、数据 + ""(避免)。
47. 使用的UI切图图片资源等如果太大尽量压缩以减少apk体积。
48. 避免常见的内存泄漏:
- 单例模式持有的context是Activity的context,改为能使用Application的Context就不要使用Activity的Content,Application的生命周期伴随着整个进程的周期。
- 非静态内部类以及匿名内部类的静态实例造成内存泄漏
- Handler和Thread使用不当造成的内存泄漏
- 资源未关闭造成的内存泄漏
- 使用了静态的Activity和View造成内存泄漏
- 注册了系统的服务,但onDestory未注销
- 不需要用的监听未移除会发生内存泄露
- 集合中对象没清理造成的内存泄漏
- 大尺寸的图片Bitmap使用造成的内存泄漏
内存泄漏相关文章:避免内存泄漏1,避免内存泄漏2,避免内存泄漏3。
49. 使用工具来分析代码:
- 使用AS自带的Lint来优化代码结构(什么,你不会?右键module、目录或者文件,选择Analyze → Inspect Code),非常有用的一点是它能告诉你API版本兼容的需求。
- 使用FindBug插件来查找bug,AS自行安装。
- 使用AS自带内存调试工具来查找内存泄漏。不会使用的可以看:使用1, 使用2。
养成良好的代码规范和编程习惯不是一朝一夕的事,需要持之以恒,要知道妖精在修炼成精以前都是要坚持修炼的,我们程序猿也是如此,建议每天固定时间或隔几天或固定每周几进行一次Code Review,哪怕只有十分钟半小时,坚持下来也会受益颇多的。
CodeReview作为业界公认的最佳实践,如果每个团队都能运用起来,固然是最好的,但是这项活动否能有效运作往往跟团队状态、技术信仰和领导者诉求等都有莫大关系。技术驱动型团队、公共服务型团队、新人密集型团队等比较容易有效进行Code Review,而业务驱动型团队、创新型团队等很难Code Review进行,此外还跟团队领导者观念以及公司文化有关(做这件事又不能提高我的绩效为什么要做它?bug都改不完功能还没做完为什么要做这个?)。
--------------------------------------------------------------------------------------------------------------------------------------------
“什么狗屁代码,老子看了几个小时也没明白!”
“这么烂的代码,到底是谁写的!”
“This Is Just Like a Shit!”
Bob大叔说:“衡量代码质量的唯一标准是阅读该代码时说脏话的次数”。
嗯,从哲学角度来看,不得不说这句话是很有道理的。。可见对于程序员而言可读性是多么重要的原则。
更多CodeReview方面的介绍请参考:
大家的公司的 Code Review 都是怎么做的?遇到过哪些问题?