英文原文:Fixing a Bug is Like Catching a Fish
boss:那么,你需要多长时间来修复这个 bug?
没有经验的程序员:给我一个小时?最多两个小时?我能马上搞定它!
有经验的程序员:这么说吧,钓到一条鱼要多久我就要多久?!
要多少时间才能修复 bug,事先是很难知道的,特别是如果你和这些代码还素不相识的话,情况就更加扑朔迷离了。James Shore 在《The Art of Agile 》一书中,明确指出要想修复问题得先知道问题的所在。而我们之所以无法准确估计时间是因为我们不知道需要多久才能发现症结的所在,只有清楚这一点,我们才能合理估计修复 bug 所需要花费的时间。不过,这个时候恐怕黄花菜都凉了。 Steve McConnell 曾说过:
“发现问题—理解问题—这就是程序员 90% 的工作。”
很多 bug 都只需改动某一行代码即可。但是需要投入大量时间的是,后面还得指出怎么样才是正确的——就像我们在钓鱼的时候,得知道往哪里下诱饵,什么时候鱼儿容易上钩等等。话说 bug 有四种类型:第一种易寻易修复,第二种难寻易修复,第三种易寻难修复,第四种难寻难修复。最悲剧的就是最后一型的,不但“寻寻觅觅,凄凄凉凉戚戚”,哪怕终于千辛万苦滴水穿石,也只能在那边不由自主地抓耳挠腮,无奈叹一句“路漫漫其修远兮”。可以这么说,除非是新鲜出炉的代码,不然让你找 bug 就跟瞎子摸象一样——糊里糊涂,不知道归属于哪种 bug 类型。
查找和修复 bug
你知道“查找和修复 bug”意味着什么吗?没错,就是调试!不断的调试,无数次的调试!Paul Butcher 通过大量工作,总结出以下结构化的步骤:
1. 明确目的。仔细查阅异常报告,确定是否是个 bug,找出各种有用的信息发现问题的症结,予以重现。再次检查是否与报告发生重复。如果发生重复,那看看曾经的相关人员是如何处理的。
2. 准备工作——找出正确的代码,用排除法清理工作区域。
3. 匹配测试环境。如果客户正在操作计算机配置,那么此过程可以跳跃。
4. 明确代码的用途,确保现有测试工具一切正常。
5. 好了,现在可以出发钓鱼去咯——重现和诊断错误。如果你不能做到重现,那你就不能证明你已经完成修复工作。
6. 编写测试案例,或者通过现成的测试案例来捕获 bug。
7. 进入修复模式——请务必确保不会影响到其他任何部分。但是,在开展修复工作之前,可能你还要包揽重构工作,因为只有这样,你才能无所顾忌地捣鼓代码。而且事后回归测试,还能确保你不会加入任何新的 bug。
8. 整理代码。通过一步一步重构,让你的代码更易于理解,更安全。
9. 找别人来审查一下,当局者迷旁观者清。
10. 再次检查此修复过程。
11. 试着不从主线出发,以检查这些 bug 是否会影响其他支线。合并这些变化,处理代码中的差异,回顾所有的审查和测试等工作。
12. 思考。好好想一想哪里错了以及为什么错了?为什么你的修复会起效?这种类型的 bug 还会出现在哪里?在《 The Pragmatic Programmer》一书中,Andy Hunt 和 Dave Thomas 也如是指出“如果一个 bug 需要耗费你很多时间,那么一定要好好弄清楚原因”。此外,还需要思考的是,怎么做才能吸取经验教训,将来在类似的问题上不再栽跟头?以及,我们采用的方法、使用的工具是否还有可以改进的地方?以及这些 bug 的影响和严重程度。
找到 bug,还是修复 bug,哪个需要更多时间?
或许建立一个测试环境、重现问题和测试 bug 所需的时间,要远远多于找到 bug 和修复 bug 的时间。不过对于一小部分显而易见的 bug,找到它们很简单——不过修复起来可能就不尽如人意了。
在《Making Software》一书中,有一章主要是探讨“大部分的软件漏洞的来源”,Dewayne Perry 分析认为,相较于修复,发现 bug(包括理解 bug 和重现 bug)所需时间更长。有研究表明,大多数的 bug(差不多有3/4)既易于发现又易于修复:5 天或许更少(这是基于大规模实时系统通过重量级 SDLC、大量审查和测试得出的数据)。但是也有很恶心的 bug,即便你可以轻轻松松揪到它,还是还得“呕心沥血”才能修复好。
发现/修复 修复时间<=5 天 修复时间>5 天 能重现问题 72. 5% 18. 4% 难以重现或根本没法重现 5. 9% 3. 2%所以如果你打赌说你能很快修复 bug,大多数情况下你还真没说错。不过当你打赌输了的时候,那么,嘿嘿,就意味着你有大麻烦了。
所以,下次,boss 再问什么时候能修复 bug,别再傻乎乎地回答“马上就能搞定”了。
译文链接:http://www.codeceo.com/article/fix-bug-like-fish.html
翻译作者:码农网 – 小峰