1.2 缺陷尽量少
优质的软件应该只有极少的缺陷。缺陷意味着客户满意度降低和修复成本增加,并且远远不限于此。特别是在今天这种竞争剧烈的业务环境中,如果缺陷太多,修复缺陷不仅需要花费金钱,还会耽误宝贵的时间,继而影响业务竞争,这可能造成潜在的商业损失。
1.2.1 关于软件缺陷的两个事实
关于软件缺陷的第一个事实是:缺陷不可能完全避免。要做到低缺陷率非常不容易,但这并不意味着无法减少缺陷带来的损失。这是关于软件缺陷的第二个事实:缺陷带来的影响和发现缺陷的时机密切相关。要规避缺陷造成的影响,最重要的原则是尽量早地发现缺陷。
缺陷不可能完全避免
缺陷不可能完全避免意味着对待缺陷的正确态度:谨慎而专业。
常常把“我的代码没有缺陷,不需要测试”挂在嘴边的程序员,非但大概率不是高手,其编写的代码也往往会在后续测试阶段错误频出。
真正的软件工程师懂得尊重软件的复杂性,在编程时“如履薄冰”,时刻把产出高质量的代码放在思考的第一优先级。不过,“如履薄冰”和“战战兢兢”完全是两码事。正是因为“如履薄冰”,才会非常审慎地对待自己接收到的需求、自己编写的代码、团队的产出。例如,专业的软件工程师会非常重视自动化测试,而且会做到测试先行(详见7.5节)。通过使用恰当的工具和思考方法,软件设计质量可以得到大幅提升。
专业的软件工程师,可以完美地融合专业能力、信心、勇气和谨慎为一体,产出低缺陷率的代码。
尽量早地发现缺陷
缺陷并不可怕,真正可怕的是没有能力及时发现缺陷。优秀的软件工程师都知道:软件是非常复杂的,人类思维又是有局限的。苛求代码在刚被写出来的一瞬间就一定是对的完全不现实。因此,我们要做的不是要规避缺陷,而是要通过加快反馈,在缺陷造成实质性影响之前,就把它消灭于无形。
当我们说缺陷率的时候,更多是在讨论那些没有被及时发现的缺陷,特别是出现在后期,如系统测试、用户接收测试、正式发布这些阶段的缺陷。而对那些刚有出现苗头、就立即被修复的缺陷,如软件工程师在编码过程中发现的刚刚犯下的错误,往往没有什么人会关心。只关注那些延迟发现的缺陷是非常合理的策略,其背后的理论基础是缺陷成本递增原理。
图1.2是McConnell在其经典著作《代码大全》[2]中给出的缺陷成本递增曲线。我们可以发现,无论是哪个阶段注入的缺陷,只要我们能在当前阶段立即发现,缺陷成本都是非常低的。发现阶段越往后移,问题的复现、定位越困难,影响面也越宽,缺陷导致的成本就越高。
图1.2 缺陷成本递增曲线
1.2.2 解决问题的方向
虽然不能完全避免缺陷,但是提前发现缺陷可以大幅降低它带来的不良影响。基于这样的事实,我们就可以得到如下的应对策略。
缩短缺陷的发现周期。
降低缺陷的发现成本和修复成本。
缩小缺陷的影响面。
缩短缺陷的发现周期
保证缺陷能被及时发现的关键点在于缩短问题的反馈周期。本书7.2节会介绍测试前置的策略,即“I模型”。测试前置保障了需求以及外部接口描述和理解的清晰,并且通过测试先行,可以及时发现缺陷,在源头上降低发生功能性缺陷的可能性。
降低缺陷的发现成本和修复成本
发现、调查和修复缺陷往往会消耗较高的成本。如果能降低缺陷在各个环节的成本,缺陷带来的影响也就相应地减小了。全面的自动化测试、更小的迭代是降低发现、调查和修复缺陷成本的有效方法。自动化测试是贯穿本书多个章节的核心内容,而通过让设计持续演进(第11章)和持续集成(11.5节),可以把发现和修复缺陷的周期降到小时,甚至分钟这种级别。
缩小缺陷的影响面
在大型商场等公共场所中都设置有防火墙,它可以在一个区域着火的时候紧急阻断火势,避免影响其他区域。软件设计也一样:有没有什么办法能及时阻断缺陷问题的传播?通过把软件划分为更合理的设计单元,定义清楚设计单元之间的依赖、接口和契约,并采取契约式设计等手段,就可以起到防火墙的效果,从而降低缺陷带来的影响。