用结构化思维解一切BUG(2):实践原则
背景
本文是系列文章《用结构化思维解一切BUG》的第二篇。本系列文章主要介绍一种「无需掌握技术细节,只需结构化思维和常识即可解一切BUG的方法」。
在前序文章《用结构化思维解一切BUG(1):核心思路》中,我介绍了用结构化思维解BUG的核心思路。即,基于结构化的「假设树」,通过重复多次执行「做实验→造现象→缩范围」动作序列,逐级下钻,缩小问题范围,直到找到问题根因。
但本方法是一个理论和实践相结合的方法,仅靠核心思路,无法完整表达。您真正使用时,还需一系列实践原则来指导方向,才能高效执行。
我把这些实践原则总结成「程序断案三字经」,5 条 30 个字:
- 先诊断,后开药。
- 信机器,慎信人。
- 做试验,缩范围。
- 找不同,看变化。
- 先脆弱,后稳定。
下文详述。
1. 先诊断,后开药
切勿在没有充分的证据时,投入大量人力去修改 BUG。如果现有的现象不足以充分支撑结论,则应该做「小成本」的试验去制造更多现象,以支撑结论。
我看过很多程序员,只了解了基本的现象,就开始靠直觉和经验来推断:「这里最有可能是这里的问题,咱们引入另一个新的工具库可以解决这个问题,我们改改试试」。当大家大动干戈地修改完后,发现问题并没有解决。然后马上改变主意:「刚刚的推断不对,我认为可以再改下这里试试」。几轮下来,极大的影响团队士气不说,更加影响业务的正常运转。
所以,这种在进行严谨的诊断之前就盲目开药的行为,是应该尽力避免的。
2. 信机器,慎信人
这里有两层意思:
一、机器不说谎。
机器没有「真」随机,就算随机数也是伪随机,更不用说你观测到的 BUG 现象了。你观测到的随机BUG,一定不是随机的,一定有确定稳定的根因,只是你暂时没有发现。
另外,机器不会错报任何一个现象。如果您找到的根因,解释了 10 个现象中的 9 个现象,只差 1 个解释不了,那么请相信,您还没有找到根因。
二、人会说谎。
你要相信自己「观察」到的现象,而不是别人「描述」的现象。这不是说您的同事或客户会故意骗人,而是人类大脑有自身缺陷。面对不重要的事情时,人脑经常容易遗忘;当面对信息缺失时,人脑又会自己进行无中生有的脑补。比如,有一次,我问一个运维工程师,这次发布跟上次的发布有什么区别时,他说完全没有。但最终证明,在本次发布时,他新建了一个新的文件夹来存放应用的运行包,而这个文件夹是以 root 的角色创建的。他完全忘记了这件事,而这件事就是应用无法启动的根因。
所以,我们对别人描述的现象,要自己判断其真实性,必要时做试验验证。举个例子,如果有人说,他昨天早上 9 点多登录应用失败,并且报错“Invalid Password”。你应该相信的是,他真的登录失败了;你应该保持怀疑的是,登录的时间和报错的信息,这些信息最好去后台日志去验证一下。
3. 做试验,缩范围
在「假设树」中下钻的过程中,如果当前已知现象没有提供充分的证据,来帮我们进一步缩小范围,则我们需要主动做试验,来创造更多现象,以支撑我们缩小范围。
并且,试验要有针对性,针对目标的就是「假设树」中当前阶段的「可能原因列表」。你设计的「试验」,是需要能排除一个或多个可能的原因。
4. 找不同,看变化
这条原则是对上一条原则「做实验,缩范围」的补充说明。
即,在做实验时,一次验证一个原因,控制单一变量,尽量排除其他干扰。然后,寻找单一变化因子下的现象变化。
举个真实的例子,曾经有一个登录问题,我的直觉判断是浏览器版本问题。我设计的试验是:
- 让现在没有 BUG 的用户升级 Chrome 浏览器到有 BUG 的用户一样的版本,看是否出现 BUG。
- 并且,我让两个用户都打开隐私窗口,以排除 Cookie 可能造成的干扰。
- 同时,我让两个用户都更换浏览器到 Edge、Firefox 和 Safari,做了同样的试验。
我得到的现象是:Edge 和 Chrome 升级后都会报错,其它两个浏览器都不报错。
得到的结论是:此 BUG 必然跟 Chrome 最新内核的更新有关,因为 Chrome 和 Edge 都是同一个内核。
5. 先脆弱,后稳定
现代应用有非常多模块,不同的模块有不同的“置信度”或“可靠度”。要从更脆弱的、更有可能出错的地方入手。就像警察断案,先找有犯罪前科的,工作不稳定的,是一个道理。有些人对自己的代码过于自信,经常从 MySQL、Nginx 这样的模块入手去查找问题。不是说这两个组件绝对不会出问题,而是说 100 次有 99 次都会失败,严重影响效率。
一般置信度从高到低的排列如下:
- 操作系统。
- 行业通用组件。这类系统经过大量验证,比如 MySQL、Nginx、Memcached、RabitMQ 等。
- 组织内通用组件。比如被企业内多个项目使用过的 SSO 模块。
- 自己写的最上层的业务代码。
除了代码提供者这个维度以外,还有一个更新时间维度。越是有新的更新的代码,越没有经过时间验证的代码,越有可能有问题。
总结
至此,《用结构化思维解一切BUG》的方法的理论部分已经讲完。
为了更好的帮助大家掌握此方法,我准备了多个实际案例,将在后续系列文章中细致讲解,请关注我的公众号接收更新。
关于作者
您好,朋友。我现就职于西门子工业软件,担任高级咨询顾问。成功领导 10 多个世界 500 强企业的数字化转型项目,跨越政府、零售、金融、汽车制造、生物医药等多个行业,创造巨大商业价值。
如有任何与「数字化转型」有关的问题,欢迎用以下方式与我交流:
添加我的个人微信「zjh1943」。添加时请注明姓名、行业、交流的问题。
关注我的微信公众号「知明所以」。
关注我的知乎专栏:https://www.zhihu.com/people/zhu-jin-heng 。
用结构化思维解一切BUG(2):实践原则的更多相关文章
- 工作中的Buff加成-结构化思考力:第一章:认识结构化思维及其作用
一:引言 为了更好的说明结构思考力,我们先来做几个小测试. PS:如果你能做到,请留言,因为我要和你交好友,因为你是人才啊,可以挖一挖,挖到我的公司中. 第一个测试:请在三秒内记住下列数字.数字顺序不 ...
- 有效的结构化思维训练,MECE分析法
MECE原则,表达精准分类与全面性的有效利器 结构化思维的本质就是逻辑,其目的在于对问题的思考更完整.更有条理,它帮助我们一个一个找到线头,理清思路,探求事物之间的相互联系.MECE分析法是一种结构化 ...
- 你真的了解字典(Dictionary)吗? C# Memory Cache 踩坑记录 .net 泛型 结构化CSS设计思维 WinForm POST上传与后台接收 高效实用的.NET开源项目 .net 笔试面试总结(3) .net 笔试面试总结(2) 依赖注入 C# RSA 加密 C#与Java AES 加密解密
你真的了解字典(Dictionary)吗? 从一道亲身经历的面试题说起 半年前,我参加我现在所在公司的面试,面试官给了一道题,说有一个Y形的链表,知道起始节点,找出交叉节点.为了便于描述,我把上面 ...
- 结构化CSS设计思维
LESS.SASS等预处理器给CSS开发带来了语法的灵活和便利,其本身却没有给我们带来结构化设计思维.很少有人讨论CSS的架构设计,而很多框架本身,如Bootstrap确实有架构设计思维作为根基. 要 ...
- 详解Google-ProtoBuf中结构化数据的编码
本文的主要内容是google protobuf中序列化数据时用到的编码规则,但是,介绍具体的编码规则之前,我觉得有必要先简单介绍一下google protobuf.因此,本文首先会介绍一些google ...
- NumPy之:结构化数组详解
目录 简介 结构化数组中的字段field 结构化数据类型 创建结构化数据类型 从元组创建 从逗号分割的dtype创建 从字典创建 操作结构化数据类型 Offsets 和Alignment Field ...
- Bigtable:一个分布式的结构化数据存储系统
Bigtable:一个分布式的结构化数据存储系统 摘要 Bigtable是一个管理结构化数据的分布式存储系统,它被设计用来处理海量数据:分布在数千台通用服务器上的PB级的数据.Google的很多项目将 ...
- 视频结构化 AI 推理流程
「视频结构化」是一种 AI 落地的工程化实现,目的是把 AI 模型推理流程能够一般化.它输入视频,输出结构化数据,将结果给到业务系统去形成某些行业的解决方案. 换个角度,如果你想用摄像头来实现某些智能 ...
- Shell 语法之结构化命令(流程控制)
许多程序在脚本命令之间需要某种逻辑流控制,允许脚本根据变量值的条件或者其他命令的结果路过一些命令或者循环执行这些命令.这些命令通常被称为结构化命令.和其他高级程序设计语言一样,shell提供了用来控制 ...
- 第25章 SEH结构化异常处理_未处理异常及向量化异常
25.1 UnhandledExceptionFilter函数详解 25.1.1 BaseProcessStart伪代码(Kernel32内部) void BaseProcessStart(PVOID ...
随机推荐
- Java面试题全集(二)
1. ⾸先CopyOnWriteArrayList内部也是⽤过数组来实现的,在向CopyOnWriteArrayList添加元素时,会复制⼀个新的数组,写操作在新数组上进⾏,读操作在原数组上进⾏ 2. ...
- Linux 标准目录结构 FHS ——原文链接https://www.cnblogs.com/woider/p/6618295.html
因为利用 Linux 来开发产品或 distribution 的团队实在太多了,如果每个人都用自己的想法来配置文件放置的目录,那么将可能造成很多管理上的困扰.所以,后来就有了 Filesystem H ...
- Builder 生成器模式简介与 C# 示例【创建型2】【设计模式来了_2】
〇.简介 1.什么是生成器模式? 一句话解释: 在构造一个复杂的对象(参数多且有可空类型)时,通过一个统一的构造链路,可选择的配置所需属性值,灵活实现可复用的构造过程. 生成器模式的重心,在于分离 ...
- 在Volo.Abp微服务中使用SignalR
假设需要通过SignalR发送消息通知,并在前端接收消息通知的功能 创建SignalR服务 在项目中引用 abp add-package Volo.Abp.AspNetCore.SignalR 在Mo ...
- 2023-08-06:小青蛙住在一条河边, 它想到河对岸的学校去学习 小青蛙打算经过河里 的石头跳到对岸 河里的石头排成了一条直线, 小青蛙每次跳跃必须落在一块石头或者岸上 给定一个长度为n的数组ar
2023-08-06:小青蛙住在一条河边, 它想到河对岸的学校去学习 小青蛙打算经过河里 的石头跳到对岸 河里的石头排成了一条直线, 小青蛙每次跳跃必须落在一块石头或者岸上 给定一个长度为n的数组ar ...
- Python实现输入三个整数x,y,z,请把这三个数由小到大输出;
num1=input('请输入第一个数,x:') num2=input('请输入第二个数,y:') num3=input('请输入第三个数,z:') if num1>num2: # if 语句判 ...
- 淘宝详情api接口的应用
淘宝详情API接口是一个基于HTTP协议的接口服务,可用于获取淘宝商品的具体信息.下面将介绍如何调用淘宝详情API接口获取淘宝商品数据的步骤. 1.注册账号并创建应用 首先,我们需要进行账号注册.实名 ...
- 【译】.NET 8 拦截器(interceptor)
通常情况下,出于多种原因,我不会说我喜欢写关于预览功能的文章.我的大多数帖子旨在帮助人们解决他们可能遇到的问题,而不是找个肥皂盒或打广告.但是我认为我应该介绍这个 .NET 预览特性,因为它是我在 . ...
- Servlet 上
Servlet 1.什么是Servlet Servlet即Server Applet是运行在Web服务器端的小程序 2.创建Servlet的三种方式 注意:从Tomcat10.0以后,我们统一用 ja ...
- SQL Server实例间同步登录用户
SQL Server实例间同步登录用户 问题痛点:由于AlwaysOn和数据库镜像无法同步数据库外实例对象,例如 登录用户.作业.链接服务器等,导致主库切换之后,应用连接不上数据库或者作业不存在导致每 ...