阅读更多

1顶
0踩

Web前端

转载新闻 13年的Bug调试经验总结

2016-07-11 17:13 by 副主编 mengyidan1988 评论(0) 有9425人浏览
引用
译文链接:http://www.codeceo.com/article/13-years-bug.html
英文原文:Lessons From 13 Years of Bugs
翻译作者:码农网 – 小峰

在《Learning From Your Bugs》一文中,我写了关于我是如何追踪我所遇到的一些最有趣的bug。最近,我回顾了我所有的194个条目(从13岁开始),看看有什么经验教训是我可以学习的。下面是我总结的最重要的经验教训,包括编码,测试和调试三个方面。



编码

下面这些都是我经历过的会导致难点bug的问题:

1.事件顺序。在处理事件时,提出下列问题会很有成效:事件可以以不同的顺序到达吗?如果我们没有接收到此事件会怎么样?如果此事件接连发生两次会怎么样?哪怕通常不会发生,但系统(或交互系统)其他部分的bug可能会导致事件发生呢。

2.过早。这是第一点“事件顺序”的一个特例,但它确实会引起一些棘手的bug,因此我把它单独拎出来说明。例如,如果信令消息在配置和启动程序完成之前就被过早接收,那么可能就会有很多奇怪的行为发生。另一个例子:连接在被放进空闲列表之前就被标记为down。在调试这类问题时,我们总是假定在空闲列表中的时候连接被设置为down(但当时为什么不把它放到列表外面呢?)。这是我们思考的不足,没有考虑到有时候事情会过早发生。

3.悄无声息的故障。一些最难跟踪的bug有部分是由那些静静失败并扩展而不是抛出错误的代码所导致的。例如,没有检查代码却返回错误的系统调用(如bind)。又如:解析代码在它遇到错误元素的时候只是返回而非抛出错误。在错误状态中持续了一段时间的调用,会使调试变得更难。最好一旦检测到故障就返回错误。

4.If。有若干条件的if语句,if (a 或 b) ,特别是当有链接的时候, if (x) else if (y),都给我引发了很多bug。即使if语句在概念上很简单,但当有多个条件要跟踪的时候依然很容易出错。这些天,我尝试重写代码使之更简单,以避免处理复杂的if语句。

5.Else。有一些bug是因为没有正确考虑到如果条件为false时会发生什么而引起的。几乎在所有的情况下,都应该有一个else部分来应对每一条if语句。此外,如果你在if语句的分支中设置变量,那么或许你在另一个分支中也要设置。与此种情况相关的是标记被设置的情况。只添加用于设置的标记的条件不难,但是很容易忘了添加当标记应该再次重置时的条件。留下一个永远设置的标志可能会导致之后接连不断的bug。

6.改变假设。许多一开始最难预防的bug是因为改变了假设所造成的。例如,在开始时,可能每天只有一个客户事件。于是很多代码是在这样的假设下写下的。但是后来,设计改变了,允许每天有多个客户事件了。发生这种情况时,很难改变新设计影响到的所有情况。找到关于改变的所有显式依赖关系不难,难的是要找到所有隐性依赖于旧的设计的情况。例如,可能会有获取给定某一天所有客户事件的代码。其中的隐含假设是结果集永远不会超过客户的数量。关于这方面的问题我也没有很好的策略方法,如果各位有的话,还请不吝赐教。

7.日志记录。可视化程序做什么至关重要,特别是当逻辑很复杂的时候。确保补充足够多的(但不要太多)日志记录,这样你就可以说明为什么程序要这么做。如果一切正常,那也没关系,但要是有问题发生,你会很庆幸自己添加了这些日志。

测试

作为一个开发人员,直到要测试了我才会去处理功能。至少,这意味着每一行新的或改变了的代码行至少已经被执行过一次。此外,单元测试和功能测试都很不错,但还不够。新的功能也必须进行测试,并在类似于产品的环境中探索。只有这样,我才能说我完成了一个功能。下面是我经历过的bug所教会我的关于测试的一些重要的经验教训:

8.零和null。如果可行的话,确保总是用零和null来测试。对于字符串,这意味着要测试长度为零的字符串以及字符串为null两种情况。又如:测试TCP连接的断开,要在发送数据给它发送之前。不使用这些组合方法测试是导致bug出现的首位原因。

9.添加和删除。通常,新的功能包括能够添加新的配置到系统中——例如,一个用于手机号码转换的新的配置文件。测试它能否添加新的配置文件是很自然的。但是,我发现我们很容易忘记去测试删除配置文件是不是同样ok。

10.错误处理。处理错误的代码往往是难以测试的。最好有能检查错误处理代码的自动测试,但有时这是不可能的。我有时会使用的一招是临时修改代码,使得错误处理代码运行起来。要做到这一点最简单的方法是反转if语句——例如,从if error_count > 0改成error_count == 0。另一个例子是拼错数据库列名,从而导致期望的错误处理代码运行。

11.随机输入。通常,揭露bug测试的一种测试方法是使用随机输入。例如,H.323协议的ASN.1解码使用二进制数据操作。通过发送随机字节去解码,我们发现了解码器中的几个bug。另一个例子是用测试呼叫来生成脚本,此时呼叫持续时间,接听延迟,第一方挂断等等都是随机生成的。这些测试脚本会暴露许多bug,特别是一起发生的事件会产生并拢干扰。

12.检查不应该发生的动作。通常测试包括检查期望动作是不是发生了。但我们很容易忽视相反的情况——忘记检查不应该发生的动作是不是的确没有发生。

13.拥有工具。我创建了自己的小工具,以使得测试更加简单。例如,当我用VoIP SIP协议工作时,我写了一个能够用正是我想要的标题和值回复的小脚本。这个工具使得测试很多边界情况变得容易起来。另一个例子是可以进行API调用的一个命令行工具。通过启动逐渐添加所需小功能,我得到了一些非常有用的工具。自己写工具的好处是,我得到的正是我想要的。

在测试中发现所有的bug,那绝对是不可能的。有一个案例中,我更改了数字相关性的处理,数字由两个部分组成:路由地址前缀(通常是不变的),以及从000到999动态分配的数字。问题在于当找到相关性时,动态分配的数字的第一个数字会在呈现在表格中之前遭到误删。也就是说637变成了37。这意味着,到100之前它都是可以工作的,因此,前面100个电话是正常的,但是接下来的900个都是失败。所以,除非我在重新启动之前能够测试超过100次(事实是我没有),否则我在测试时就不会发现这个问题。

调试

14.讨论。帮助我最多的调试技术是与同事讨论问题。通常情况下,只是和同事说明问题,就会让我意识到问题的症结。此外,即使他们不是很熟悉有问题的代码,他们也往往能提出一些好点子。与同事讨论在处理最难的bug时特别有效。

15.密切关注。通常,如果调试问题花了很长时间,往往是因为我做了错误的假设。例如,我认为问题发生在某一方法中,但事实却是它甚至从来没有到达那个方法。或者,被抛出的异常不是我以为的那个。或者,我认为软件的最新版本上正在运行,但其实是一个旧版本。因此,一定要核实细节,而不是假设。人们更容易看到自己希望看到的东西,而不是事实。

16.最近的变化。当曾经可以正常工作的东西停止工作,那么这通常是因为最近改变的东西所导致的。在一个案例中,最近的改变只是日志记录,但是日志中的错误却导致了一个更大的问题。为了更容易找到这种回归,承认不同的提交会导致不同的变化,以及清楚说明这些更改会有所裨益。

17.相信用户。有时,当用户报告问题的时候,我的本能反应是,“这是不可能的。一定是他们做错了什么事”。但我学会了不再用这种方式去回应。更多的时间,事实往往证明,他们所报告的的确是实际发生的情况。因此,这些天,我开始接受他们所报告的内容的表明价值。当然,我依然会仔细检查一切是否被正确地设置等等。我见过很多这样的情况,让我明白,因为不寻常的配置或意料之外的用法而导致不可思议的事情的发生,而我默认的假设是,他们是正确的,程序是错误的。

18.测试修复。如果bug修复已准备就绪,那就必须进行测试。首先在修复前运行代码,并观察该bug。然后应用修复并重复测试案例。到此为止错误行为应消失。遵循这些步骤可以确保它确实是一个bug,并且此次修复的确可以解决这个问题。简单而有必要。

其他观察结果

在这13年来我一直在跟踪我所遇到的最棘手的bug,很多事情由此而改变。我工作过小的嵌入式系统,大的电信系统以及基于web的系统。我使用过C ++,Ruby,Java和Python。在工作于C++时所遇到的几类bug已经完全消失,像堆栈溢出,内存损坏,字符串问题和某种形式的内存泄漏。

其他问题,如循环错误和边界情况,我看到的要少得多。但是,这并不意味着那里没有bug。这篇文章中的经验教训旨在帮助减少编码,测试和调试三个阶段的bug。如果大家有什么有用的预防和发现bug的技术方法,欢迎不吝指导。
  • 大小: 22.5 KB
1
0
评论 共 0 条 请登录后发表评论

发表评论

您还没有登录,请您登录后再发表评论

相关推荐

  • 13年的 Bug 调试经验总结

    在这13年来我一直在跟踪我所遇到的最棘手的bug,很多事情由此而改变。我工作过小的嵌入式系统,大的电信系统以及基于web的系统。

  • 13 年的 Bug 调试经验总结

    下面是我总结的最重要的经验教训,包括编码,测试和调试三个方面。编码下面这些都是我经历过的会导致难点bug的问题:1.事件顺序。在处理事件时,提出下列问题会很有成效:事件可以以不同的顺序到达吗?如

  • 13 年的Bug 调试经验总结

    13 年的 Bug 调试经验总结 在《Learning From Your Bugs》一文中,我写了关于我是如何追踪我所遇到的一些最有趣的bug。最近,我回顾了我所有的194个条目(从13岁开始),看看有什么经验教训是我可以学习的...

  • Bug 调试经验总结

    下面这些都是我经历过的会导致难点bug的问题: 1.事件顺序。在处理事件时,提出下列问题会很有成效:事件可以以不同的顺序到达吗?如果我们没有接收到此事件会怎么样?如果此事件接连发生两次会怎么样?哪怕通常...

  • 调试bug有奇招,15年的老司机 Bug 调试经验总结

    原文出处:http://www.codeceo.com/article/13-years-bug.html 编码 下面这些都是我经历过的会导致难点bug的问题: 1.事件顺序。在处理事件时,提出下列问题会很有成效:事件可以以不同的顺序到达...

  • 和各种诡异 Bug 打交道 13 年,我总结了 18 个经验

    最近我重新浏览了这所有的 194 个条目(历时 13 年),看看我从这些 bug 中学到了学到了那些重要的经验教训。我分为编码、测试和调试三大类。编码这些都是过去给我带来棘手 bug 的问题:1. 事件顺序当处理事件时,问...

  • 十年嵌入式码农的 Bug 调试经验谈

    这篇文章中的经验教训旨在帮助减少编码,测试和调试三个阶段的bug。 编码 下面这些都是我经历过的会导致难点bug的问题: 1.事件顺序。在处理事件时,提出下列问题会很有成效:事件可以以不同的顺序到达吗?如果...

  • 嵌入式码农的10年Bug调试经验,值得一看

    下面这些都是我经历过的会导致难点bug的问题:   1.事件顺序。在处理事件时,提出下列问题会很有成效:事件可以以不同的顺序到达吗?如果我们没有接收到此事件会怎么样?如果此事件接连发生两次会怎么样?哪怕...

  • 跟各种诡异 Bug 打交道 13 年后的总结

    Bug是程序员一生的“伙伴”,程序员们时刻都在跟bug作斗争,因为bug憔悴,也因为bug兴奋,下面来看看一位跟各种诡异bug打交道13年的老司机说了些什么。

  • C++软件调试与异常排查从入门到精通专栏介绍与文章汇总

    根据近几年排查软件异常的实践与经验,系统地讲解了C++软件异常常见原因与常用排查方法,以图文并茂的方式给出具体的分析实例,带领大家逐步掌握C++软件异常排查的相关技术与要领。

  • 调试segfault 经验总结

    经过后来的实践,总结了定位到行的方法。 之前的方法使用的前提是获得的release版程序的崩溃信息,由于时release版,没有调试信息,所以没法直接使用objdump来显示出源代码行号等信息。不过,我们仍然可以重新编译...

  • MATLAB实现的语音信号加密解密系统设计与应用 - GUI界面交互与相位扰动加密技术

    内容概要:本文详细介绍了基于MATLAB的语音信号加密解密系统的开发过程及其关键技术。系统主要分为三大模块:录音、加密和解密。录音功能利用audiorecorder对象进行音频采集,支持多种采样率设置。加密算法采用了相位扰动方法,通过傅里叶变换将语音信号转换到频域,添加随机相位偏移并用密码作为随机种子确保唯一性和安全性。解密过程则是逆向操作,通过正确的密码恢复原始相位。此外,系统还包括了一个友好的图形用户界面(GUI),方便用户操作和查看波形变化。文中还探讨了一些实际应用中的挑战,如硬件兼容性和误码容忍度等问题。 适用人群:适用于对语音信号处理、信息安全以及MATLAB编程感兴趣的科研人员和技术爱好者。 使用场景及目标:本系统可用于保护隐私通话、防止窃听等场合,旨在提供一种简单易用且高效的语音加密解决方案。它不仅能够满足日常生活中对于私人对话安全性的需求,也为相关领域的研究提供了有价值的参考资料。 其他说明:作者分享了许多开发过程中遇到的问题及解决办法,强调了细节处理的重要性。例如,针对不同设备间的采样率差异进行了适配调整;为了提高用户体验,加入了密码记忆功能和支持中文密码等功能。

  • YTCB2509 非接触式转速测量仪 20250323

    题目:非接触式转速测量仪 主控:STM32 显示屏:Oled 电机驱动:L298 电机(带编码器可测速的三线电机) 按键(增速或者减速等)

  • 基于MATLAB的含齿轮啮合误差激励的轴系动力学建模与Newmark-β法实现

    内容概要:本文详细介绍了如何利用MATLAB实现含齿轮啮合误差激励的轴系动力学模型。首先,文章解释了为什么传统欧拉梁理论在轴系建模时存在局限性,并引入了Timoshenko梁单元来考虑剪切变形和转动惯量。接着,重点讲解了Newmark-β法的具体实现步骤,包括预处理系数矩阵、迭代公式的推导以及如何处理时变刚度和误差激励。此外,还提供了关于稀疏矩阵优化、频谱分析等方面的实用技巧。最后,通过具体案例演示了整个仿真的流程和注意事项。 适合人群:机械工程领域的研究人员和技术人员,尤其是那些从事齿轮传动系统振动分析工作的专业人士。 使用场景及目标:适用于需要精确模拟齿轮传动轴系动态特性的场合,如汽车变速箱、风力发电机等设备的设计与故障诊断。主要目标是提高仿真精度,缩短计算时间,从而更好地指导实际工程应用。 其他说明:文中不仅给出了详细的数学推导和代码实现,还分享了许多宝贵的实践经验,如如何避免常见的数值不稳定性和调试技巧等。这使得读者不仅能学到理论知识,还能掌握解决实际问题的方法。

  • 增材制造中元胞自动机模拟枝晶生长及CET转变的Matlab实现

    内容概要:本文详细介绍了如何使用元胞自动机(Cellular Automaton, CA)和Matlab来模拟增材制造过程中微观组织的生长,尤其是枝晶生长及其从柱状晶到等轴晶的转变(CET)。首先解释了元胞自动机的基本概念,即通过定义网格和状态转移规则来模拟微观结构的变化。接着给出了具体的Matlab代码实现步骤,包括初始化、生长规则制定、枝晶生长模拟以及CET转变的模拟方法。文中还探讨了温度梯度、晶核密度等参数对CET转变的影响,并提供了优化后的高效算法版本。最后强调了此类仿真的重要性和应用价值,如帮助预测和优化增材制造产品的微观结构和性能。 适合人群:从事材料科学、增材制造领域的研究人员和技术人员,以及对元胞自动机和材料微观结构建模感兴趣的学习者。 使用场景及目标:①用于研究和教学,帮助理解和掌握增材制造过程中微观组织演变规律;②辅助工业生产中的工艺参数选择,提高产品质量;③为后续更复杂的多物理场耦合仿真提供基础。 其他说明:随文附带完整的源代码和相关文献资料,便于读者深入学习和扩展研究。

  • 房地产 -阿那亚生活式品牌社群运营 -读懂生活式品牌的社群运营 .pptx

    房地产 -阿那亚生活式品牌社群运营 -读懂生活式品牌的社群运营 .pptx

  • 基于自抗扰控制的预测函数控制(PFC)在永磁同步电机(PMSM)中的高效应用

    内容概要:本文详细介绍了基于自抗扰控制的预测函数控制(PFC)在永磁同步电机(PMSM)中的应用。首先阐述了PFC的基本概念及其相对于其他模型预测控制的优势,特别是其在快速响应和鲁棒性方面的表现。接着,文章深入探讨了三个关键技术:1.5延时补偿、全电压前馈补偿和扩展状态观测器(ESO)。1.5延时补偿通过线性外推解决计算延时问题;全电压前馈补偿利用电压信息提前调整控制输入,增强响应速度;ESO则用于实时观测并补偿系统中的不确定因素。此外,文中还提供了具体的代码示例,展示了这些技术的实际应用效果。最终,实验结果显示,采用PFC结合自抗扰控制的方法可以显著改善PMSM的速度控制性能,特别是在应对负载扰动方面。 适合人群:从事电机控制领域的工程师和技术研究人员,尤其是关注永磁同步电机控制的从业者。 使用场景及目标:适用于需要对永磁同步电机进行精确、快速响应控制的应用场景,如工业机器人、自动化生产线等。主要目标是提高电机控制系统的稳定性、响应速度和抗干扰能力。 其他说明:文章不仅理论讲解详尽,还附有大量实用的代码片段,便于读者理解和实践。同时提醒读者在实际应用中需要注意参数调整和系统噪声的影响。

  • ### 中国企业级SaaS上市公司2023-2024年财务绩效回顾及未来展望、前言

    内容概要:本文聚焦中国企业级SaaS上市公司2023-2024年的财务绩效,通过详尽的数据分析和行业趋势展望,揭示了该领域的发展现状与未来方向。文章指出,尽管收入和毛利持续增长,但整体毛利率偏低,销售费用率高企,研发投入大,盈利艰难,资产周转效率下降,现金流承压等问题普遍存在。针对这些问题,提出了提升客户价值、深耕行业、延伸商业价值、审视并购可能性、盈利模式多样化、抓住AIGC(生成式人工智能)机遇、把握出海机遇以及积极利用资本市场等策略建议。未来,企业级SaaS市场将围绕中小企业需求、细分领域产品爆发式增长及行业生态协同化发展。 适用人群:对中国企业级SaaS市场感兴趣的投资者、企业管理者、行业分析师以及相关从业人员。 使用场景及目标:①帮助投资者评估企业级SaaS上市公司的投资价值;②为企业管理者提供战略规划和运营管理的参考;③为行业分析师提供详实的数据支持和趋势预测;④为从业人员提供职业发展和技能提升的方向。 其他说明:本文基于2024年10月底的财务数据,结合安永的研究分析,提供了对企业级SaaS市场的深入洞察。文中还强调了SaaS企业在数字化转型中的重要作用,并呼吁行业内企业积极应对挑战,把握发展机遇。

  • Comsol仿真技术在聚合物电解质膜燃料电池堆热管理中的应用与优化

    内容概要:本文详细探讨了使用Comsol进行聚合物电解质膜(PEM)燃料电池堆的热管理建模。首先强调了保持燃料电池堆温度均匀性的关键意义,因为温度不均会影响电池性能。接着介绍了由五个电池单元组成的模型结构及其与冷却剂的交互方式。文中具体讲解了多个关键物理量的求解方法,如温度、电极和电解质相电位、反应物质的质量传递以及流体的压力和速度。此外,还讨论了如何通过调整冷却液入口温度、选择合适的湍流模型、优化电化学反应和传质的耦合、合理划分网格以及采用分阶段求解策略来改进仿真效果。最后,作者分享了一些实用的经验和技术细节,例如在冷却液中加入荧光粒子示踪剂进行实验验证,以及针对不同参数做出相应的调整以确保模型的准确性。 适合人群:从事燃料电池研究的技术人员、工程师以及相关领域的科研工作者。 使用场景及目标:适用于需要深入了解和掌握PEM燃料电池堆热管理系统设计与优化的人群。主要目的是帮助他们更好地理解和运用Comsol软件来进行复杂的多物理场耦合仿真,从而提高燃料电池堆的工作效率并延长使用寿命。 其他说明:文章不仅提供了理论知识,还包括了许多具体的实施步骤和技巧,有助于读者快速上手并在实践中不断积累经验。

  • 基于Vue+javaScript实现的电动汽车充电桩管理系统+源码+项目文档(毕业设计&课程设计&项目开发)

    基于Vue+javaScript实现的电动汽车充电桩管理系统+源码+项目文档,适合毕业设计、课程设计、项目开发。项目源码已经过严格测试,可以放心参考并在此基础上延申使用,详情见md文档 基于Vue+javaScript实现的电动汽车充电桩管理系统+源码+项目文档,适合毕业设计、课程设计、项目开发。项目源码已经过严格测试,可以放心参考并在此基础上延申使用,详情见md文档~ 基于Vue+javaScript实现的电动汽车充电桩管理系统+源码+项目文档,适合毕业设计、课程设计、项目开发。项目源码已经过严格测试,可以放心参考并在此基础上延申使用,详情见md文档 基于Vue+javaScript实现的电动汽车充电桩管理系统+源码+项目文档,适合毕业设计、课程设计、项目开发。项目源码已经过严格测试,可以放心参考并在此基础上延申使用,详情见md文档 基于Vue+javaScript实现的电动汽车充电桩管理系统+源码+项目文档,适合毕业设计、课程设计、项目开发。项目源码已经过严格测试,可以放心参考并在此基础上延申使用,详情见md文档

Global site tag (gtag.js) - Google Analytics