代码评审—每个开发都应该有自己的CheckList

        在入职公司以来,大部分时间都是在维护手Q小程序模块相关的代码,包含日常的新需求开发和bug修复工作,这里会不可避免的涉及对别人代码的评审和被人对自己提交的代码的评审,为了提高自身代码的质量,也同时减少别人MR自己代码时可能会反复提及的一些代码缺陷评审建议,结合自身的实际情况,汇总了入职以来别人对我提交的代码有效代码评审建议,感谢对我提出有效代码评审的同学,也希望自己的代码质量可以不断提升,后续会持续更新最新的My CheckList(严格来说应该是自己代码缺陷list才对)。

日志类相关:

1、打印日志时,考虑是否会触发高频日志问题。

2、有些必须的日志,又容易触发高频日志,可以考虑使用染色日志或者对日志做限频处理。

3、在一些关键代码实现逻辑,例如:某个变量突然为null了,返回的int值为-1等情况,要记得添加日志,方便后续定位问题。

4、  注意去除高频日志时,别去除关键性的日志,要了解日志前后逻辑,是否可以去除。

5、  卫语句记得需要添加E级别错误日志信息,方便函数触发时,定位问题。

6、  try catch触发异常时,记得添加E级别错误日志信息,并把exception错误带到日志中。

7、  try catch模块应该尽量范围小一点,且必须添加异常日志信息。

空指针类型相关:

1、变量通过引用赋值进函数后,再对外部变量做修改时,赋值进去的变量不会改变。

2、在一些对象的使用时,注意要先做判空判断,例如:if(null != bundle)、if(null != dialog && !dialog.isShow())、if(null != activity && !activity.finish()),

判断一下activity的合法性和有效性,是否finish等。

3、在使用单例类时,如果单例类里面包含界面控件相关变量或者Acitivity变量时,要注意使用弱引用,避免内存泄露问题。

4、处理一些空指针异常时,也要考虑异常时,为空的兜底处理逻辑。

9、  使用静态内部类+弱引用避免内存泄露时,注意内部获取弱引用对象时,做判空处理。

10、调用接口获取数组对象时,如果不确定是否会返回空值,需要做判空和数组是否为空操作。

11、在各个类型转换的地方,函数前可以添加卫语句,判断对象是否为空,以及是否为该转换的类型。

12、对回调函数返回的数组index获取数组数据时,需要判断数组是否为null与空,也需要判断index是否在数组的大小范围内(大于等于0、小于等于size -1)

内存泄露与内存溢出相关:

1、所有的add、register等事件,都要记得添加对应remove、unregister事件。

2、在创建图片、大数据流等相关大对象时,需要做try{}catch防护,防止触发OOM。

生命周期释放相关:

1、重新启动小程序时,注意数据的清除,websocket断开等操作。

2、小程序的插件(plugin)都有生命周期,销毁时,记得做清除、remove、反注册等操作。

多线程安全问题相关:

1、注意在创建单例类时,可以直接实现静态内部类的方式,满足延迟初始化和线程安全的情况,如果单例构造函数有参数,则直接用双重所方式实现。

2、  做类似ThreadManager.getUIHandler().post()操作时,可能会触发线程切换操作时,注意添加空指针保护。

3、  注意异步回调的二次判空逻辑。

4、  根据原子性、可见性、有效性,了解concurrentHashMap与

Collections.synchronizedList、CopyOnWriteArrayList的区别,多线程遍历集合时,其他线程执行修改操作,Collections.synchronized为什么会有concurrentmodificationexception异常。

5、  concurrentHashMap的key和value不能为null,否则多线程操作时有二义性。

5.1、迭代器不同:Collections.synchronizedMap 中的迭代器是同步的,即在迭代期间其他线程不能修改 Map 中的内容,而 ConcurrentHashMap 中的迭代器是弱一致性的,即在迭代期间其他线程可以修改 Map 中的内容,但是不保证迭代器能够访问到最新的修改。

5.2、空值不同:ConcurrentHashMap 不允许存储空值,而 Collections.synchronizedMap 可以存储空值。

6、如果不确定函数是否在主线程运行,又需要保证函数在主线程运行,可以通过

   if (Looper.getMainLooper() == Looper.myLooper()) { 

        } else {

            ThreadManagerV2.getUIHandlerV2().post {

                     }}

7、  各个回调函数返回时,如果对回调函数的处理需要在主线程,也需要判断返回的回调函数是否执行在主线程。

8、  通过弱引用修复内存泄露时,所有使用该弱引用的对象,都需要做判空处理,例子:if(null != mActivity && null != mActivity.get())。

9、  Toast也需要在主线程触发执行。

性能相关:

1、注意性能问题,尽量减少函数逻辑的重复执行次数,如果需要外部变量做数据存储,宁愿多创建存储对象,也不要重复执行函数逻辑,案例:拖动小程序时,部分函数会重复执行,会触发一些不必要操作重复执行(空间换时间的概念)

主题适配与国际化适配相关:

1、  对控件和界面的背景或颜色修改,要时刻考虑适配QUI。

2、  使用token时,设置背景色时,只能使用background=”drawable/qui_..bg”,不能使用color=”color/qui_…..”

3、  字符串都放到xml,否则后续无法做国际化。

其他综合相关:

1、面对实现复杂的函数,建议把各个功能抽离出来。

2、实现功能或修复bug时,修改的逻辑范围要尽量在最小的范围内,不然容易导致修复一个问题,导致另外新的问题出现,sdk代码尤其需要注意一些公共代码部分,调用链路会很多。

3、去除无用的成员变量。

4、常量不应该放到抽象类中,应该放在抽象类的实现类里。

5、使用SystemClock.uptimeMillis()替代System.currentTimeMillis(),避免用户调整系统事件导致的异常。

6、小程序中使用到plugin插件接口时,对需要外发的异常信息常量,需要和前端同学同步异常信息数据,并同步到线上文档中。

7、  Activity做类型转换时,有可能部分Activity基类不是BaseActivity,导致异常,可衍生到fragment等其他类。

8、  Long.valueOf 与 Long.parseLong转换问题比较,原理:在字符串转换为long类型的数据时,如果只需要转换为基础类型,用Long.parseLong性能较好,如果需要获得Long对象,并且数值在-128到127之间,Long.valueOf性能比较好。

9、  调用时序导致的潜在bug问题。

10、小程序插件发生异常时,需要执行failed相关函数,触发通知前端页面相关异常消息,方便前端定位异常原因。

11、  小程序proxy要延迟初始化,并做判空处理。

12、  在清除旧代码前,注意要判断是否保留try{ }catch。

13、  在修改函数代码时,注意这种有关联的函数前后关系:player.pause(),player.isPlaying();

14、  避免页面穿透问题,触发不同层级控件响应,可以直接把当前最顶布局的根布局设置点击或触摸事件。

15、  各个回调函数返回的对象或者数组,也要通过卫语句,判断相关对象或者数组是否可用,再执行正常操作。

16、判断两个数组数据是否相同,需要通过:if (handlerItem.getFilter().size() == handlerFilterSize && handlerItem.getFilter().containsAll(handler.getFilter()) && handler.getFilter().containsAll(handlerItem.getFilter()))

欢迎大家留言补充自己的checklist的链接、文档等,愿世界再无BUG哈。

© 版权声明

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...