几种常见的Bug预防方法

我在自己日常的开发工作中时常遇到很多Bug, 这些Bug非常多样, 表面看来似乎各有成因. 我曾经试着记录各种Bug, 试图在以后避免遇到相同Bug, 但是, 这种方法非常表面, 我昨天遇到这个Bug, 今天可能会避免这个Bug, 但后天就会忘了可能性, 于是, 又重犯了相同的错误. 至于记录, 那么多Bug记录, 不可能有时间每天先预习一遍所有发生的Bug. 坦白讲, 试图让所有Bug都不会发生是不现实的. 

但是, 在这个过程中, 我还是总结出来了一个经验, 那就是将Bug分类, 并针对这些不同分类的Bug, 进行预防工作, 而非Bug发生后的治理工作. 结果相当不错, 我的Bug发生数量明显在减少. 我把我总结出来的几点经验提炼出来, 可供大家参考. 我会列举各种我遇到的Bug类型, 然后将我自己的预防方法写入其中. 

一. 数据抽象错误

所谓开发, 是将现实的产品需求变化成抽象的数据表达, 那么, 表达的方式其实是多样的, 因为没有统一的表达模式, 于是, 经常会在开发过程中造成表达方式的错乱, 导致Bug产生. 数据结构的设计其实是非常重要的过程, 我个人认为, 实际的开发过程前, 必须将所有能涉及到的数据结构, 都加以整理, 一旦发现数据矛盾, 初期就能调整结构来实现逻辑统一, 在开发工作之前, 数据抽象的错误就会大大减少. 但这增加了一个额外的工作, 那就是开发工作执行之前多了一步数据整理的工作. 但好处也很明显, 那就是程序的数据抽象比较稳定, 减少Bug并且为后续开发做了一个指导性的数据定义. 

二. 算法逻辑错误

实际的开发过程中, 有时候会遇到一些相对比较复杂的算法逻辑, 面对这种逻辑, 常常遇到情况是一边开发, 一边调整算法, 结果代码完成之后, 代码本身已经非常不可控了. 遇到这种情况, 我试图去预防的做法是做一个算法设计的逻辑草稿, 然后将这个草稿记录下来, 通常是记录在Evernote里面, 并且定标题, 如: Ref-1234, 同时, 在代码中加上一个注释, 附上这个标题Ref-1234. 以后调整代码的时候, 我随时可以到Evernote里面(你也可以记录到别的地方)看到当初设计这个算法的思路, 而不是单凭代码去理解之前的算法, 这样, 后面思考算法的方法和以前思考的方法保持一致, 从而减少反复调整代码过程中导致算法错误的发生. 

三. 定义错误

我们的代码中, 会有很多变量或常量的定义, 这些定义, 有它本身的意义, 但是, 我们经常会用混这些变量, 比如我们设计一个代码是a = b + 1, 实际上, 我们会不小心写成a = a + 1, 代码没有任何报错, 但实际上却发生了某种不可理喻的错误. 面对这种问题, 规范代码命名方式是最好的办法. 表达式变成了 Current = Prev + 1, 那么, 如果我们错写成了Current = Current + 1, 肉眼发现这个错误的可能性要比发现a = a + 1要更大. 事实上, 统一规范的命名方式, 可以预防很多错误的发生. 

四. 参数值错误

在开发中, 预料不到的数据总是会经常发生的, 我们不能指望所有的意外都能被预料到, 于是, 经常性的, 参数本身就会有错误带入. 一旦带入了错误的参数, 后面所有代码步骤都会变得不可控了. 为了预防这种错误, 我们应该经常性的使用assert, 通过assert的使用, 将参数值的安全性提升一个层次. 在bug发生之前, 我们的程序就已经知道错误发生在什么地方了. 

五. 流程错误

为了处理一个复杂的业务, 我们时常要设计一个比较多层次的流程, 理想中, 流程是线性的, A过程完了, 去处理B过程, 然后C过程.... 一切都非常完整. 但实际上, 它们是交错的, 这里有空间和时间上的交错, 空间上的交错, 最典型的例子就是递归模式, 而时间上的交错, 比如多线程处理, 具体空间和时间的交错不多举例, 很多时候, 都是在开发的时候才发现交错的发生, 也就是一边开发, 一边扩展流程, 结果变得一团糟. 为了应付这种状况, 个人认为最好的做法就是层级化逻辑, 尽可能让逻辑线性化, 这个我们可以通过函数的内容来调整. 实在不能做到的完全线性化的逻辑, 就在代码中加一句注释, 说明此函数可能会与哪个函数发生交错, 从而减少调整代码过程中, 因为调整某个函数, 导致另外一个函数不可工作. 

六. 结构性错误

每一个不同的代码段, 可能都有它自己的结构逻辑, 尤其是引入一些第三方库的时候, 比如: 一些库将触发行为放到回调函数或者闭包中, 一些库则需要定义某种stub形式, 而一些库则可能会发出一个消息, 还有一些库需要特定的init操作. 这就导致了各种结构都有不同, 不熟悉此库的人, 可能会错误的使用了错误的形式, 也许, 表面上可能会正常运行, 但其实它会带来了某种不可控的错误. 这时候, 开发者得先熟悉这套库, 才能预防这种错误的发生, 但我们开发者常常是拿到库, 一边开发一边学习的, 导致这样的结构性错误发生概率很高. 为了预防这种错误的发生, 我们无论拿到什么样的库, 最好的做法是先去观摩这个库的demo, 然后尝试写一篇这个库的使用方法的文章, 不用很复杂, 就是很入门的那种, 在写的过程中, 就可以大致的让自己了解一些这个库的具体化使用方法. 如果是在一个小规模的团队里面, 可以尝试举行一个分享会, 让开发者做一次讲授, 说明这个库的具体使用方法, 通过教授他人, 也让自己熟悉这个库的具体用法. 一旦熟悉, 这种结构性错误发生概率就会大幅度减少. 

Bug类型太多了, 不可能一一穷举, 细化下去有很多可能性, 这里只是提供几种比较常见的, 并且提出自己的预防方法. 我个人有一个看法, 那就是Bug本身完全不存在那是不可能, 但是, 通过预防方法让Bug大幅度减少, 是可以做到的. 上述文章纯属个人经验, 希望对别人有所借鉴. 

你可能感兴趣的:(几种常见的Bug预防方法)