• 笔记|软件调试的技巧


    这篇文章是《调试九法:软硬件错误的排查之道》的阅读笔记。这本书的主旨,是介绍如何修复bug:找出bug发生的原因、并给出修复方案。

    调试bug的九个规则列举如下,建议将这个清单打印出来,摆放在工作时候能看到的地方。

    调试规则

    接下来一次看下每个规则的核心理念,从名字上来看,每个规则看起来都比较明显(PS:由于翻译的问题,有些词可能没那么容易理解),但是理解这些规则和应用这些规则中间还是差了很多距离的。

    规则1:理解系统

    你必须掌握系统的工作原理以及它是如何设计的,在某些情况下还要知道为什么这样设计。如果你没有理解系统中的某个部分,那么这通常是出问题的地方。(这不仅仅是墨菲定律的问题,如果你不能理解你所设计的系统,你的工作可能会变得一团糟)。

    如何理解系统呢?

    • 阅读手册
    • 逐字逐句阅读手册,仔细理解每个细节
    • 知道什么是正常的,知道什么是正常的可以帮助你注意到什么是不正常的
    • 知道工作流程,要理解业务,要讲系统的工作过程对应到具体要解决的现实问题
    • 选择合适的工具,选择合适的辅助(监控、插桩)工具可以帮你理解系统
    • 查阅细节,经验有时候会骗人,记忆有时候会出错

    规则2:制造失败

    这一点比较容易理解,就是问题复现,在日常工作中,你在排查一个问题的过程中,最重要的一步就是复现问题——能复现的问题都能解决。

    这里有几个要点需要注意:

    • 引发失败,而不要模拟失败,不要尝试用不同的方式去模拟问题,而要模拟和构建引发bug发生的条件
    • debug的动作,不要影响错误的发生方式,可以影响错误的发生频率
    • 从头开始,需要有一个正常的状态到不正常的状态的过程,从开始正常的状态开始观察,直到问题发生;
    • 终极方案,控制变量法,将可能引发错误的因素依次排除;排除所有可能的原因后,剩下那个答案,无论多么不可思议,都是事实。

    规则3:不要想,而要看

    亲眼看到底层的失败是非常重要的,如果你猜测失败是如何发生的,那常常会修复一些根本不是bug的问题。

    在软件世界里,观察意味着设置断点、添加调试语句、监视程序值以及检查内存;在医学领域,需要测试血样和进行X光透视。

    对细节的观察应该到什么程度合适呢?简单的答案是:一直观察,直到把问题的原因锁定在几种可能之内。

    在系统设计的时候,就要考虑到将来调试、排查问题的情况,将日志视为系统设计的一部分—打印一些关键日志,或者设计一些打开日志的开关,以便在生产环境针对某个case进行调试。

    日常生活中有很多插桩的case:

    • 体温计测量体温
    • 自行车轮胎漏气时,都是将轮胎打满气,然后放在水里检查哪里漏气
    • 天然气中加入了臭鸡蛋的气味

    规则4:分而治之

    反复将问题分成好的一半和坏的一半,然后缩小搜索范围,然后进一步研究有问题的那一半链路。

    规则5:一次只改一个地方

    初中就学过的控制变量法。
    在修改bug时候,如果某个改动没有修复bug,就应该立即把它改回来。

    规则6: 保持审计跟踪

    记下你的每步操作、顺序和结果;
    魔鬼藏在细节中;
    将一些事情关联起来思考;
    好记性不如烂笔头;

    规则7:检查插头

    一些显而易见的假设可能是错误的;是不是运行了正确的代码?是不是打了正确的包?插头是不是掉了?从一些最基本的问题开始确认,很多时候问题就出在这里。对自己使用的工具进行测试,因为工具也是一种软件,难保不会出问题。

    规则8:获得全新观点

    “要想重新理清一个案子的头绪,最好的方法就是把它讲给别人听。” ——福尔摩斯,《银色马》

    向别人解释问题的过程,会让你对问题进行重新的梳理和理解,这时候可能发现之前没有发现的问题。

    bug发生了,以除掉bug为自豪,而不是非得以自己除掉bug才自豪。

    不管你是跟什么人求助,或者需要别人什么样的帮助(征求意见、获取专业知识、听取经验),在向别人描述问题的时候,一定要记住一件事——报告症状、而不是讲你的理论;另外,有些症状你可能不是十分确定,也可以描述出来。

    规则9:如果你不修复bug,它将依然存在

    “当危险已经离你很近时,拒绝承认它并不是勇敢的表现,而是愚蠢。” ——福尔摩斯,《最后一案》

    如果你不修复bug,它不会自动消失。按照前面的规则解决问题后,要进行一次回归验证,确保已经修复问题,并且没有引入新的问题。

    我的感想

    这本书里的很多案例都是是硬件相关的,对于软件开发工程师来说不太熟悉,不过在阅读的过程中,建议可以想想自己在工作中排查问题的场景,是不是按照一定的章法去排查的?有没有从最基本的假设开始确认?有没有查阅文档?有没有关注本次变更的内容?有没有按照二分法进行排除?

    作为软件开发工程师,在实际工作中很少有机会从0开始构建一个系统,更常见的情况是接手维护一个已经运行了几年、经历了几代的系统。写代码只是工作中的一部分,还有很多其他的事情需要做:修复bug、需求评审、系分评审、项目排期等等。

    修复bug(解决问题)的能力,是软件工程师的核心竞争力之一。在最开始的工作中,有时候会羡慕老司机的“直觉”——看到一个错误日志,就大概知道是哪里有问题,后来自己查问题查得多了之后,自己也get到了这种“直觉”,也理解了——这不是直觉,这是已经被实践验证过很多次的经验,即使这样,我也会告诫自己——不能完全依赖这种经验,经验有助于缩小待验证的范围,还是需要事实(重现问题)去证实前面的猜测。


    本号专注于后端技术、JVM问题排查和优化、Java面试题、个人成长和自我管理等主题,为读者提供一线开发者的工作和成长经验,期待你能在这里有所收获。javaadu

  • 相关阅读:
    android 多线程
    Uva 10881 Piotr’s Ants 蚂蚁
    LA 3708 Graveyard 墓地雕塑 NEERC 2006
    UVa 11300 Spreading the Wealth 分金币
    UVa 11729 Commando War 突击战
    UVa 11292 The Dragon of Loowater 勇者斗恶龙
    HDU 4162 Shape Number
    HDU 1869 六度分离
    HDU 1041 Computer Transformation
    利用可变参数函数清空多个数组
  • 原文地址:https://www.cnblogs.com/javaadu/p/11148145.html
Copyright © 2020-2023  润新知