35 对问题各个击破
1. 问题是什么?
软件发布后,测试或运行过程中,出现了bug,如何解决这个bug ?
2. 最笨的方法
“逐行检查代码库中的代码确实很令人空间。但是要调试一个明显的错误,只有去查看整个系统的代码,而且要全部过一遍。毕竟你不知道问题可能发生在什么地方,这样做是找到它的唯一方式。”
这个办法是书中此章”恶魔天使“所说的办法,它确实是个办法,不过对于软件工程师来说,确实是一个魔鬼,意味着我要分析,调试整个系统的数据流,控制流,以找到问题发生的根本原因。这个过程花费的精力,时间将是一个什么级别?这个过程中,要承受多少领导,客户的压力?个中滋味,体验过,就终身难忘。
3. 有没有更好的办法
有没有其他更好的办法,去解决软件bug呢?不用再去分析整个系统的设计,软件工程师都知道追踪整个系统的数据流,控制流意味着什么。
3.1 Bug不决,问同事
Bug发生后,最简单的办法还是去问同事,或者公司内部的问题记录,或者自己的问题解决记录。看看以前有没有相似的问题发生过,如果你够幸运,或者公司内部有积累,碰到了问题解决日志。那你就可以参考之前的问题解决log,来解决这个问题。当然,如果幸运者不是你,你就要开始下面孤独的调试之路了。
3.2 创造环境,分离问题
在解决问题时,要将问题域与其周边隔离开,特别是在大型应用中。
- 单元测试
适用场景:有单元测试用例,可以直接测试各个软件单元。
单元测试带来的积极效应之一,是它会强迫形成代码的分层。要保证代码可测试,就必须把它从周边代码中解脱出来,如果代码依赖其他模块,就应该使用mock对象,来把它从其他模块分离开。这样做代码更加健壮,且在发生问题时,更容易定位。
- 原型系统
适用场景:无法分离问题代码模块,重新再实现一个小型原型,展示一个类似症状。
使用原型帮助工程师对问题理解的更清晰。而且,如果工程师无法在原型中再现问题的话,原型也会告诉他们可以工作的代码的示例,有助于分离和隔绝问题
识别复杂问题的第一步:是将它们分离开来。如果可以隔离出发生问题的模块,应该容易修复发生问题的代码。
既然不可能在半空中试图修复飞机引擎,为什么还要试图在整个应用中,诊断其中某个组成部分的复杂问题呢?当引擎从飞机中取出来,而且放在工作台上之后,就更容易修复了。
最好可以把关注的代码提取出来,而且创造一个可以让其工作的测试环境。
用原型进行分离
3.3 各个击破
对问题各个击破,这样做有很多好处:通过将问题与应用其他部分分隔离开,可以将关注点直接放在与问题相关的议题上;可以通过多种改变,来接近问题发生的核心——你不可能针对正在运行的系统来这样做。可以更快地发现问题的根源所在,因为只与所需最小数量的相关代码发生关系。
3.4 这个策略还可以在什么时候用?
隔离问题不应该只在交付软件之后才着手。在构建系统原型,调试和测试时,各个击破的战略都可以起到帮助作用。
4. 需要注意什么呢?
-
如果将代码从其运行环境中分离后,问题消失不见了,这有助于隔离问题
-
另一方面,如果将代码从其运行环境中分离后,问题还在,这也有助于隔离问题。
-
二分查找,定位问题。将问题空间分为两半,看看哪一半出现问题。再将包含问题的一半进行二分,并不断重复这个过程。
-
在向问题发起攻击之前,先查查你的问题解决日志。
注:文中斜体内容为引用书中原文