调试的艺术
作为一名开发人员,你的日常职责很大一部分将涉及处理 bug,找到问题,重现问题,并修复问题。
从头开始编写代码要容易得多,而查看旧代码、理解它并对其进行改进则更具挑战性。
我们有教程教我们语言最佳实践、如何使用设计模式、如何处理代码异味、编写精简、可维护的代码;然而,我们职责的这一关键方面却常常被忽视。
本文的目的不是告诉你如何修复漏洞,而是描述你需要经历的查找和诊断问题的过程。
没错,有时候你写的代码本身就会导致某个 bug!是时候调查一下到底出了什么问题!如果你是代码的作者,那就简单多了,因为你知道该从哪里入手。
但如果你没有呢?!
提示:你需要像侦探一样思考。
如何知道从哪里开始?
没错,这确实很难!有人提出问题或发送屏幕截图,然后你的收件箱里就出现了堆栈跟踪信息!这一切到底意味着什么?你如何利用这些信息来确定问题的根源?
让我们来看看我会采取哪些步骤。
步骤 1:重现问题
首先,你需要重现这个错误。很多记录下来的错误都是由于配置错误、网络问题或浏览器相关问题引起的,所以这是调试过程中不可或缺的一部分。
提示:开始之前,请获取所有需要的配置信息以及重现步骤!
试图在不重现错误的情况下修复问题是徒劳的。除非你能亲眼看到它不起作用,否则你永远不会知道你所做的更改是否真的能解决问题!
步骤二:找到入口
利用你掌握的信息,想办法进入代码内部。
问题:表单错误
假设你有一张表单的截图,上面显示了一条错误信息。你如何利用这条信息找到你需要的信息?
在调查问题时,您需要从两个方面进行调查。问题是否出在客户端, 例如 JavaScript、CSS 或 HTML 中;或者问题是否出在服务器端,即后端代码,也就是您的数据/数据库和基础设施所在的位置。
步骤三:排除各种可能性
如果你玩过“猜猜我是谁”的游戏,你就会明白我的意思了。你已经有了嫌疑人,现在是时候缩小范围了!
提示:关键在于采取系统性的方法。
在这里,我们可能需要从客户端入手,因为那是我们的入口点,也是我们可以检查错误发生方式的地方。我们需要验证表单是在浏览器内部进行检查,还是将一些信息发送给了另一端的服务器!
这时,开发者工具就派上用场了,很多人都知道它就是神奇的F12键!通过它,你可以查看和访问页面上的DOM、底层HTML和JavaScript。
如果你之前从未使用过开发者工具,这里有两个很棒的入门视频,可以带你了解它的功能。即使你已经熟悉它,我也强烈推荐你观看第一个短视频,它会快速回顾你可能错过的 12 个技巧。
提示:记下可疑标签的ID和CssClass 名称,并找到它们所在的文件。
这种方法能让你了解发生了什么,并确定下一步的关注重点。通过检查标签和元素,提取ID和CSS 类名,你可以深入源代码,精确定位问题所在。
通用客户端游戏策略
- 检查控制台是否有错误
- 检查页面,找到与该问题关联的处理程序。
- 添加断点,以便查看传递的参数,并查看调用堆栈(以防这些值来自其他地方)。
- 在源代码中搜索标签或处理程序,以便修改相关文件。添加日志行以提高可见性。
- 测试你的更改。
- 重复以上步骤直至完成。
提示:如果使用 Typescript 或您的 JS 文件已打包,请添加debugger;行,以便浏览器在代码执行时自动中断,这是查找这些文件合并位置的好方法。
第四步:输入错误数据或输出错误数据。
问题:数据显示错误
如果你的问题出在数据上而不是验证上,你需要弄清楚是数据保存错误还是显示错误。
例如,如果你的页面上有一个标签,本应显示你的姓名,但却显示了你的年龄。
你需要找出是否使用了错误的字段/值来显示标签,或者值已正确检索但保存不正确。
这类问题可能更难定位,因为你不知道数据来自哪里。与第一个例子类似,找到入口点, 然后沿着代码一直追踪到数据加载的位置。 现在你可以检查源头的数据是否错误了!
提示:这可能是应用程序生命周期钩子,例如页面加载或初始化。
后端游戏计划
- 找出数据是从哪里检索的,调用了哪个表、存储过程或函数来显示该值。
- 使用唯一标识符查询数据库,以筛选结果。
- 根据结果,你将有两种可能的选择。
- 如果问题源于其他地方;当数据保存时。
- 或者在展示时。
- 如果显示,则返回客户端游戏计划;否则……
- 找出所有可能将数据插入该表/存储的路径,并缩小范围,找出导致问题的路径。
问题:堆栈跟踪
堆栈跟踪
有时你会看到一大段文字,也就是所谓的堆栈跟踪。堆栈跟踪看起来很吓人,乍一看就像一道滔天巨浪。但别担心,里面有很多关于你不关心、甚至可能从未听说过的库和二进制文件的信息。99% 的情况下,这些都不会是问题所在,所以找到与你的代码对应的行即可!
如果你收到了堆栈跟踪信息,那你就处于非常有利的位置。它告诉你发生了错误,以及出错的具体位置。这大大简化了你的工作。查找被调用的方法名、涉及的文件以及行号,即可找到问题的根源。然后,根据具体问题,按照上面列出的相应步骤进行操作。
提示:找到你的代码第一次被调用的地方,然后从那里开始。
这里深入剖析了堆栈跟踪的复杂细节,以及如何找到与你相关的部分!https://alligator.io/js/stack-trace/
毫无进展?
如果您已经:
- 是否重现了该错误?
- 使用谷歌搜索排除任何任意问题?
- 找到你认为导致问题的源代码了吗?
- 添加调试点、打印语句和 console.log行来验证你的假设?
- 我做了一些修改,但这个bug仍然存在吗?
- 你是不是多次用头撞桌子?
好了,看来是时候找人帮忙了。如果你花了一个小时左右的时间仍然毫无进展,那就找个人一起讨论一下问题,有时候仅仅是讨论就能给你带来新的线索或新的研究方向。
艺术源于练习
正如你所见,找到问题的根本原因并非易事,存在许多潜在的路径,而且常常会遇到许多误导信息或死胡同。找到解决每个问题的最佳方法是一项宝贵的技能。随着时间的推移,你会凭直觉知道从哪里开始搜索,从而节省时间。话虽如此,在查看代码时,假设通常不是好事,最好是看看实际发生了什么,而不是你认为发生了什么!
我想知道你有没有什么建议可以给其他开发者?
或者说,在着手解决提出的问题时,你可能会犯的最大错误是什么?
你会编写单元测试来覆盖遇到的每一个bug吗?
延伸阅读
- https://simpleprogrammer.com/effective-debugging/
- https://www.codementor.io/mattgoldspink/how-to-debug-code-efficiently-and-effectively-du107u9jh
- https://hackernoon.com/how-to-debug-any-problem-ac6f8a867fae
- https://alligator.io/js/stack-trace/



