用结构化思维解一切BUG(3):实际案例

背景

本文是系列文章《用结构化思维解一切BUG》的第 3 篇,也是最高潮篇!本系列文章主要介绍一种「无需掌握技术细节,只需结构化思维和常识即可解一切BUG的方法」。

在前序文章《用结构化思维解一切BUG(1):核心思路》中,我介绍了本方法的核心思路,即,基于结构化的「假设树」,通过重复多次执行「做试验→造现象→缩范围」动作序列,逐级下钻,缩小问题范围,直到找到问题根因

在前序文章《用结构化思维解一切BUG(2):实践原则》中,我介绍了本方法的实践原则,「程序断案三字经」,总结为 5 条 30 个字:

  1. 先诊断,后开药。
  2. 信机器,慎信人。
  3. 做试验,缩范围。
  4. 找不同,看变化。
  5. 先脆弱,后稳定。

本文我将带大家进入真实BUG场景,在场景中介绍「假设树」如何生长、如何执行「做试验→造现象→缩范围」小闭环、如何运用实践原则。同时,您也从中感受到该方法的强大!

_提醒:_本文中,假设树的生长图和试验记录表格是重点,建议点击图片全屏预览,如用手机建议横屏观看。

案例背景

这个客户是创立了 20 年的国际贸易和海外工业制造公司,目前在筹备上市。为应对上市要求,需要搭建自己的质量管理系统。

这个应用由一个「导航应用」和多个「子应用」构成。导航应用中有多个子应用的链接。当用户登录导航应用后,点击任何一个子应用的链接,即可快速进入这些子应用,无需再次登录。请记住这里的「导航应用」和「子应用」,后文会多次提到。

有一天,客户反馈,部分用户有「跳转到子应用后无法自动登录」的问题。

显然,这仅有的信息,我无法做出任何有效判断。

大多数业务用户,甚至是程序员,在反馈问题时都缺乏必要细节。作为问题解决者,我的第一个任务就是,问对问题,得到我想要的信息。我一般会用 5W2H 的方法来问问题(请注意后续问题的中括号标注),以全面了解信息。

提醒:如果您是程序员,强烈建议刻意培养自己「提出一个好技术问题」的能力,因为好的问题才有更大几率被快速回答。具体请参考我的另一篇文章《如何提出一个好的技术问题?》。

明确问题

首先,我需要明确问题[What]。即,问 3 个问题:

  1. 希望的现象是什么?[To-Be]
  2. 实际的现象是什么?[As-Is]
  3. 哪个点不满足希望?[Gap]

在本场景中,三个问题的答案为:

  1. 希望用户可以免登录地进入子应用。
  2. 实际现象是,用点击子应用链接后,应用自动在新标签页打开一个登录页面。且这个登录界面就算输入正确密码和账号,也无法登录。
  3. 无法正常访问子应用。

缩小范围

根据上一篇文章的「假设树」方法,我们第一层需判断此问题是前端问题还是后端问题。

为了方便引用,我们把发生 BUG 和不发生 BUG 的用户分为两组,发生 BUG 的用户成为 N (Negative)组,未发生 BUG 的用户成为 P (Positive)组。

于是,我问了如下问题:

这个诊断过程,我践行了如下原则:

  1. 「先诊断,后开药」。在没有弄清楚问题根因之前,不做任何正式的修改建议。
  2. 「找不同,看变化」。尽量从现有现象中,找到大家的不同点,看有什么变化,变化就是线索。

有了这些信息,我靠直觉猜测,大概率是前端问题,且是浏览器问题。因为,从后端来看,我很难想到这两组用户在代码和数据上有显著的不同特征。具体来说:

  1. 后端代码,两组用户肯定是一样的。
  2. 后端数据,发生了 BUG 的用户没有任何明显相似点,发生 BUG 的用户与没发生 BUG 的用户也没有任何明显不同点。

直觉很有价值,可以更快找到正确路径。但直觉未经过严格证明,不能把它直接当做结论,还需要做试验证实。

另外,不用担心自己直觉不准,它并不会影响最终结果,因为它只是猜测。只要你按照「假设树」的路径逐个遍历,总会到达终点,只是要多做几次试验罢了。

🌲🌲🌲回顾假设树-Step1🌲🌲🌲

本阶段「假设树」没有任何确定性的进展,只能依靠直觉先做假设。具体进展如下(本文所有假设树示意图中,蓝色字体表示是假设,红色字体表示是已证实的结论):

设计试验

为了验证上述的猜想,我陆续做了如下试验:

在这个过程中,我践行了如下原则:

  1. 「做试验,缩范围」。通过不同的对比实验,来验证自己的猜想,缩小问题范围。

  2. 「找不同,看变化」。在 1 和 2 两步,我尽量控制单一变量,排除掉其他因素干扰,来看有什么变化。

  3. 「信机器,慎信人」。我相信,BUG 没有真随机,任何 BUG 都有其底层规律,一定有某个地方的不同导致了 BUG。并且,我得到初步结论后,再次与所有观测到的现象做意义印证,看是否能解释观测到的全部现象。

回顾这组试验,「假设树」前进了两步:

🌲🌲🌲回顾假设树-Step2🌲🌲🌲

Step2 中,我们虽然判断大概率是浏览器原因,但不能 100% 确定,因为没有排除后端原因。所以,我们只能沿着假设的方向进一步探索。如下图所示:

🌲🌲🌲回顾假设树-Step3🌲🌲🌲

Step3 中,我们确定了此问题是 Chrome 浏览器版本所致,则整条路径的所有原因都可以确认了。即,可以确认是前端原因,且是浏览器原因。同时,可以排除后端原因。如下图所示:

初步结论

从上述一系列实验中,我们得到初步结论:本 BUG 跟浏览器版本密切相关

接下来,我给了客户两个修改建议,并嘱咐,如果还未找到根因再来找我。

  1. 查阅 Chrome 的近期更新日志,试图从中找到跟本 BUG 相关的更新条目。
  2. 仔细阅读跟自动登录相关的「前端」代码(只有大约 30 行),检查哪些代码最有可能伴随浏览器版本升级而发生变化。

请注意,这两个建议,都是低成本修改建议,主要目的是做试验,参考「先诊断,后开药」的原则。

第二次设计试验

第二天,反馈来了:

  1. Chrome 每个版本的更新日志内容太多了,有上千条,一条条去查找不现实。(我错误地估计了 Chrome 的更新量)
  2. 看了登录相关的前端代码,尝试了所有可能伴随浏览器升级而发生不一样行为的地方,结果都一样。

这说明,我们虽然缩小范围到了那 30 行代码的范围,但还是达不到让执行者能修改的地步,还需要进一步缩小范围,找到根因。

于是,我让客户讲解这 30 行代码做了什么。通过讲解,我了解到这 30 行代码主要是发送异步请求完成子应用的自动登录,然后跳转到子应用的 home 页面。

根据 Web 应用的常识,我知道,登录不成功,要么是登录请求执行失败,要么是 Cookie 里 SessionID 未写入成功。为了验证上述猜想,我又设计了如下试验:

基本确定完根因后,我又拿这个根因,跟前面所有的现象作比对,发现全部能解释。

🌲🌲🌲回顾假设树-Step4🌲🌲🌲

回顾这组试验,「假设树」继续生长,最终找到根因是链接未加密。如下图所示:

最终结论

最终发现根因是:

  1. Chrome 新版本写入 Cookie 的规则发生变化,加密请求创建的 cookie 不能被非加密请求改写。
  2. 导航应用与子应用的 schema 不一致,一个是 http,一个是 https。

最终的修改建议是:

为每个子应用配置加密访问证书,并更改环境配置中子应用的域名的 schema 为 https。

客户更改完后,BUG 完美修复!

本案例总结

这个案例,我们精准还原了解决一个 BUG 的完整过程。过程中,我们不停地调整「假设树」,不停地「做实验→造现象→缩范围」,最终到达终点,找到根因。

除了前述 5 个原则以外,我还想说一点精神层面的事。任何一个 BUG 的解决过程都是崎岖坎坷的,特别是当你面对一组现象,完全找不到任何联系的时候,任何人都会心情低落。但越是这样,越要沉着冷静。不要想一步登天,直接找到根因;而是要从「假设树」根部逐步往下钻,一层一层抽丝剥茧。每一层下钻,每一次试验,你都会得到新反馈,用来排除其它假设。这些反馈是支撑你继续往下钻的动力。所谓「慢慢来,比较快」,就是这个意思。

全系列文章总结

至此,《用结构化思维解一切BUG》的方法的核心思想、实践原则和实践案例都已经讲完。后续,我会不定期更新更多实际案例,以帮助您加深理解。

如果您完整读完本系列的三篇文章(《用结构化思维解一切BUG(1):核心思路》、《用结构化思维解一切BUG(2):实践原则》和本文),并基本理解所有段落,那么恭喜您,您的解 BUG 功力已经显著提高!如果您还愿意在实际工作中践行那么几次,您一定会成为顶级解 BUG 高手!

最后,重温下本系列文章最开头的那句话:

面对万“卷”世界,有人选择拼命学习新技术,解决眼前的、点状问题;有人提升思维层级,解决未来的、面状问题。您选择什么?

关于作者

您好,朋友。我现就职于西门子工业软件,担任高级咨询顾问。成功领导 10 多个世界 500 强企业的数字化转型项目,跨越政府、零售、金融、汽车制造、生物医药等多个行业,创造巨大商业价值。

如有任何与「数字化转型」有关的问题,欢迎用以下方式与我交流:

  1. 添加我的个人微信「zjh1943」。添加时请注明姓名、行业、交流的问题。
  2. 关注我的微信公众号「知明所以」。
  3. 关注我的知乎专栏:https://www.zhihu.com/people/zhu-jin-heng

热门相关:间谍的战争   我的极品美女总裁   间谍的战争   神话版三国   逃妻鲜嫩嫩:霸道老公,吻够没