调测之前我们能做些什么?
——代码走查实践体会与总结
手机事业部软件一部    蒋荣
  要:今年事业部正在大力推广软件的代码走查活动,因为代码走查是成本相对比较低的一种发现缺陷的手段。但是即使是这种简单的活动,似乎在项目中推广起来还是举步维艰。这里面包括项目压力、观念、方法等诸多原因。本人在做代码走查方面方法改进和推广的工作,几个月下来,收集了一些值得总结的问题和方法,特总结于此,希望能给同行一些指引。
代码走查的重要性很多人可能耳朵都听出老茧了,本文不想涉及过多的理论化的口号,也不想引用一些大家都不知道是否真实的业界的统计数据,主要是本人的一些亲历体会和认为可以推荐的一些方法共享给大家。期望据此展开这方面的方法和经验的讨论,而不是仍然停留在做与不做的阶段进行无休止的徘徊和争论。
关键词:代码走查  调测  调试  测试  缺陷
写程序“三分编,七分调”?
我刚毕业开始做软件开发的时候,所在的不正规的软件部门没有正规的测试手段。对故障以及故障会意味着什么也没有什么深刻的体会,反正只要能写出来完成差不多的功能就行。开发人员代码写完了大概跑一跑,崔得急的话可能马上就拿到现场去试着用,有时候还得在现场直接改代码。后来在修改过程中逐渐发现,很多时候花很少时间就已经完成编码的模块,但从开始调试到最终基本稳定要花几倍于编码的时间,而大部分情况都是在处理一些不大不小的小故障,这其中定位故障几乎花了80%的时间。在纳闷中我问我的师傅,师傅告诉我写程序就是这样,所谓“三分编七分调”,以后你就习惯了。于是我如获至宝似的获得了一个真理,在调试解决故障上花时间似乎是必然付出的代价,也没想去什么捷径。
这种懵懂的过程一直持续了很久,到后来逐渐有所改变。因为经过一段时间的磨练,自己也积累了一些所谓的经验的小窍门,我发现有时候当有些故障出现的时候,凭一些经验即使不用调试代码,直接阅读代码居然能大概定位到一些问题,这样给自己节约了不少的时间,因为毕竟调试和跟踪总是很耽搁时间的。再后来我也开始当师傅了,新来的兄弟似乎在重复着我原来的过程,有时候他们遇到故障的时候,我便提出来让他们尝试别先急着调试跟踪,先分析一下现象后大概阅读一下有关的代码,就算是猜吧!运气好的话也许不用调试就到问题了呢?虽然不保证肯定能行,但是花一点时间试一试,万一搞定了不是很节约时间吗?有
很多次居然可以奏效。到那个时候我对我师傅的话开始有点犯疑,因为我发现在调试之前,似乎还是有其他办法可以试一试的,而他居然从来没有给我提起过。
我一直有个习惯,假如我在自己肩膀上发现了一条虫,除了飞快的拍掉它后我还会把自己全身都来个大搜索,因为我担心身上其他地方还有,我母亲说这个习惯是因为我从小就胆小,但是我辩解说既然肩膀上有,那其他地方肯定不排除啊,呵呵。我不知道自己这个习惯的来源,有趣的是这个习惯居然体现到了我的平日的编码习惯中。只要发现了一种典型的错误做法,我会不自觉的检查整个模块是否有同样的错误。这个习惯我一直沿用至今,他至少提醒我错误一旦被发现,同样的错误不要在一个模块中重犯。直到后来我才明白,原来我所体会的这种习惯有一个更正规的名字,叫做代码的“专项走查”。
后来有缘进入了ZTE,对代码安全性和正确性的要求更高了,才知道代码走查是软件开发过程中非常重要的环节。但是很遗憾,我当时所在的ZTE部门在这个方面仍然不是做的很好,大家面对强大的项目压力和现场故障,所能做的都是不断的测试和调试,阅读代码只是根据个人定位故障的习惯随意采用而已,并没有提升到一个很严格的研发过程中来。
但是有几次故障定位的经历使我印象特别深刻。其中一个是我在培训时候给大家讲过,当时
我们的一个语音服务器在辽宁的一个地方出现了故障,现象非常严重。由于是在线系统不能停,我和几个开发人员每天都是半夜开始加班编写调试模块跟踪现象,累了几天晚上,仍然毫无头绪。
忙乱过后我们静下心来做了仔细分析:(1)这个平台在国内外几十个点都在稳定运行;(2)辽宁这个平台话务量特别大;(3)辽宁这个平台刚开始一直没有问题因此有一个累计过程;(4)重新启动后故障依旧证明故障出现在具有记忆存储体的处理逻辑中。经过分析我们发现,由于我们这个平台唯一的存储体就是采用一种hash算法的内存数据库,这个数据库纪录了语音的索引并定期保存到磁盘印象文件。我们把重点放在这个内存数据库模块上,由于这个模块比较独立,于是我发动所有开发人员对这部分代码进行地毯式阅读,尤其关注引起语音索引混乱的数据问题。最后,一位开发人员在代码中到了原因,是一个纪录语音复用个数的数据定义太小,当转发次数超过64K后发生归0溢出,造成语音定位混乱。
问题好像就这样解决了,但其实还并没有完。发现这个现象后,我们立即怀疑是否还有其他地方涉及这个参数的地方定义是否也有类似的问题?于是我们继续阅读了相关几个模块的代码,发现在程序的启动模块中由于需要对数据库进行数据整理,与此相关变量同样定义小了,
也就是如果我们只修改前面提到那个地方暂时解决了问题,但当系统由于某种原因发生双机倒换而重新启动的时候,那个问题又会冒出来。当时我们冒了一身冷汗,每个人都觉得很庆幸,至此修改完后问题彻底得到了解决。
经过一些教训后我总结出几个结论:
国外网站源码
只要程序是人写的,肯定就有缺陷。
调试代码环境要求高,有些时候根本不允许调试(比如现场)。
阅读代码没有任何环境要求,只要有源代码,随时可以阅读。
调试代码每次只能定位到一个缺陷。
阅读代码可能到一批类似的缺陷。
带着问题有针对性的阅读代码可以提高成功率。
基于上面的结论我们可以总结出这样一个原则:当故障出现后,定位故障除了采用跟踪调试
的手段,有时候直接阅读代码也许是不错的选择,并且一旦发现一个故障,通过阅读代码有针对性的扫描整个模块相类似的错误通常可以到更多的错误。当然,谁也没有否定调试跟踪的重要性,我只是在想,假如有10个故障依次需要调试跟踪,其中能有5个故障可以尝试通过阅读代码而定位,是否总体上可以节约一些时间?
为何都钟情于调试和测试?
前面啰嗦了那么多,无非就是想说明有时候通过阅读代码定位故障在成本上有时候很划算。但是我还是觉得有点不满意,因为定位故障虽然多了这样一种选择,但是毕竟是故障已经发生了,我们是根据故障现象有针对性的去阅读代码。为什么我们不在故障发生前来阅读代码呢?
大部分程序员(包括我自己在内)编码完成后第一件想做的事情就是先“编译”,编译如果出了一些错误和告警便一个个原因并修改;编译通过后就尽量能整个程序连接在一起“运行”,运行出了错呢?开始仔仔细细的逐个跟踪原因,最后一个个原因到后基本运行通过了。
上面是正常开发的一般做法。那么当发现故障后我们是怎么做的呢?我们首先想到的是复现故障现象,然后分析大概位置,最后通过增加一些跟踪信息等手段去逐步顺藤摸瓜,只要现象容易浮现,一般还是能定位到原因。
我们多数情况下都是这样做的。写完代码后我们很少主动的去阅读和检查代码,即使有时候阅读代码,也是当故障出现后为了解决故障被动的针对性的阅读代码,就像前面我举的例子一样。我一直在考虑,我们宁愿花大量的时间一个一个的调试排除故障,却不愿牺牲哪怕一次故障调测的时间来做一次广普性的代码检查。
同样是排除故障,一个是通过发现故障后“调测”跟踪,一个是通过“阅读”代码广谱查。我常常把这两种方式做一个比喻:前者正如某个人生病了上医院治病;后者正如某个人主动的到医院进行健康检查。大家能得出什么结论吗?至少我觉得以下几点可以达成共识:
生病就医的言下之意是一种被动就医,已经生病已经付出了代价。
健康检查的言下之意是一种主动行为,可提前预防。
生病就医太有针对性,花很大的成本最后就治愈了一种病,综合成本高。
健康检查是广谱性的体检,花一定成本一次可能查出多种病状,综合成本低。
生病就医发现的病症大部分已经是晚期,一般都很严重了,医治成本和代价都很高。
健康检查发现的病症大部分都是早期,一般有治愈希望大,医治成本和代价都较低。
生病就医的最佳结果只能是治愈。
健康体检的最佳结果是健康,因为可主动指导和改善生活习惯,减少病状发生。
很遗憾我们大部分人对健康体检的常用托辞是“我工作很忙”。有趣的是这种说法和软件开发中“我项目压力大、时间紧”的说法多么的相似,只不过所有项目到最后都在忙着故障,而再也没有谁去关注如何预防故障的发生。因为当故障已经出现的时候,解决故障变为第一要素,却没有人考虑过这是一个周而复始的循环,是否有人考虑过能否减少这种事情发生的次数。
当然,谁也不会否认,当一个人生了重病后是肯定要医治的。问题的关键是我们不能总是经常性的等生病后往医院跑。耽搁一点正常的工作时间,或者牺牲或延长一次生病就医的时间做一次健康检查,用于指导改善你的生活习惯,不是更好吗?
我相信大部分开发人员如今对“代码走查”这种预防性活动还是有很正确的认识,问题是为什么在强大的项目压力下在“故障调试”、“新功能开发”和“代码走查”之间总是把前者放在最重要的位置,而把“代码走查”放在可有可无的次要位置呢?我总结了几个原因:
没有可供检验的结果:“新功能开发”和“故障调试”都是不可逃避的,因为二者都有明确的最终结果作为目标检验标准;“代码走查”没有明确的最终结果,做了没有?做得怎么样?没有标准就没有监督和审核的标尺,项目很紧的情况下,也就变得可有可无。
没有可控制的中间过程:“新功能开发”总是要编写代码,“故障解决”总是要跟踪调试;但“代码走查”的过程没有固定的模式,读程序快慢与否、认真与否全部没法掌控,既然过程不受控,自然就容易马马虎虎。
没有固定统一的方法:在没有故障提示情况下,盲目的流水帐似的阅读代码,最后变成不同人按自己的方法随意的走马观花似的大概略读一下代码,时间长了觉得没有效果,也就疲了,最后不了了之。
效果影响信心:在代码走查中某些模块中没有发现什么缺陷,由此对自己的阅读代码查
缺陷的能力产生潜意识的怀疑,从而认为在其他模块中发现问题的可能性为零,最终放弃这种低成本的查缺陷的机会。
完美主义:用完美主义的眼光来挑剔代码走查,认为既然强调“代码走查”的重要性,那么应该可以发现绝大多数缺陷并解决之,否则我宁愿不做。
没有目标:在问题没有暴露前问题,不知道该如何。什么问题都想,东一榔头西一棒,最后晕头转向,多次失败的情况下,最终放弃。
枯燥乏味:“新功能开发”是一个创造性的活动,“故障解决”带有强烈的目的性,唯独阅读代码是被动的在一大堆符号中寻缺陷,在没有明确目标的情况下,确实很乏味,甚至最后都忘记了自己的最终目的。
2小时做一个尝试
我时常在想,在我们编码之后调试之前,牺牲一次故障调试的时间,就算是尝试,给自己的代码做一次代码走查,哪怕一个缺陷没有到,这个应该不算是多大的冒险吧?

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。