一个关于如何高效调试软件的指南,强调采取 detective mindset、熟练掌握工具、善用 print 函数、团队协作共享调试经验以及利用 rubber duck debugging 等方法来提高调试效率。今日前端早读课文章由 @Juhis 分享,@飘飘编译。
译文从这开始~~
像侦探一样思考
一个优秀的调试者,应该像侦探一样去面对问题。优秀的侦探不会凭空猜测或做出假设,而是一步步追踪线索,仔细检查证据,并通过逻辑推理得出结论。
我经常看到无论是初级开发者还是资深工程师,面对问题时要么死盯着代码希望奇迹出现,要么凭经验跳到结论,觉得自己知道问题在哪。结果就是浪费好几个小时,最后发现自己完全在错误的方向上兜圈子。

💡 提示 1:像一个对这段代码一无所知的人那样,按部就班、逐步排查。
- 确认你正在查看的代码确实被执行了。一个简单的方法是在你检查的每个函数开头加一条
print
(或 console.log)语句,确认代码是否运行。
- 重现 bug。你必须知道怎么触发问题,否则你也无法确认问题是否已解决。
- 检查变量状态:打印变量的值,或者使用调试工具一步步查看发生了什么。
我发现,每当我在代码库中 “移动” 思考时,反复执行这三个步骤,几乎总能找到 bug 的根源。
对于前端开发者来说,很多 bug 来自异步操作,比如:
-
Promise 未正确返回;
- await 被遗漏;
- UI 更新顺序混乱。
此时可以用 Chrome DevTools 的异步堆栈跟踪来帮助我们厘清问题:
- 在 DevTools 的 Source 面板中打开 Call Stack;
- 勾选 “Enable async stack traces”;
- 设置断点,观察异步逻辑是如何一步步触发的。
这比单纯依靠 “猜测 Promise 哪里没返回” 更有效。
投资时间学习你的工具
软件开发行业的工具五花八门,而且大多数工具都是免费的或开源的,几乎没有什么金钱成本。但你需要花时间去学习和掌握它们。
我认为调试是一种双重技能:一方面是前面讲到的思维方式和流程,另一方面就是强大的工具,只有两者结合,才能高效地发现并解决问题。
在日常工作中,我们很容易停留在自己熟悉的那一套工具里,不去了解别的选择,不去查看更新日志,也不知道其他人都在用什么工具解决类似的问题。
💡提示 2:熟练掌握你的语言中的打印、日志、调试器和代码编辑器。这样你就能专注于解决问题,而不是浪费精力在 “怎么用工具” 上。
对于前端开发者来说,除了 console.log,还有许多更高效的调试手段:
📍 断点调试(Breakpoints)
- 行断点 - 定位特定语句;
- 条件断点 - 只在变量满足条件时中断;
- DOM 断点 - 监听元素变化;
- XHR 断点 - 请求发出时暂停。
在 Chrome DevTools 的 Source 面板中,这些断点设置都非常直观。
⏱ 性能调试(Performance)
- 用 Performance 面板录制页面行为;
- 分析 JS 执行时间、Layout 重排;
- 找出动画卡顿、长任务等瓶颈。
适用于页面流畅度优化和交互延迟排查。
🌐 网络调试(Network)
- 查看请求是否发出、返回是否正常;
- 检查 status code、header 和响应数据;
- 发现跨域问题、缓存设置错误等问题。
例如你遇到 “登录请求发了但页面没跳转”,可以通过 Network 面板确认请求返回是否正常,再去检查 JS 逻辑是否响应了返回结果。
在 Python 中,调试工具有 built-in debugger、PuDB、web-pdb、birdseye 等。在前端,除了 DevTools,也可以结合 VS Code 的 Debug 面板进行跨项目调试。
不断探索这些工具,并根据自己的项目特点选择最顺手的一种,是非常值得投入时间的事情。
打印是最好的调试起点

我在各个地方写文章或演讲时,关于调试我最常遇到的一个反馈就是:很多人对使用打印语句(print)调试存在偏见。
有不少人告诉我,他们的同事说 “打印是不好的做法”,但在我讲完之后,也有人跑来和我说 “太高兴有人告诉我,打印其实不是错的”。
打印是最好的调试工具,因为它几乎没有门槛。你不需要安装或配置任何东西,写一句打印语句只要几秒钟,也很容易在输出中找到结果。而且如果问题本身不复杂,这绝对是最快的方式。
💡提示 3:不要吝啬使用 print!
你越愿意用打印,调试时就越容易上手,而不是陷入死盯代码或胡乱猜测的误区。当然,打印不是最强大的调试手段,也不是最复杂的工具,有时候它不够用 —— 这时候你可以升级到更强的调试器。但打印是你调试之旅最好的起点。
与同事分享经验,共同成长
Jenn Creighton 在她的演讲《Now And Then: Debugging Async JS》中说得很好:
“最好的调试工具,是你对某个东西的理解。”
她提到,长期使用某种技术、某种方法或某个代码库后,会积累很多经验。当你再遇到问题时,大脑会下意识地想起以前的经历,帮你更快判断该先验证哪些假设。
这种经验,很多时候是个人积累的。但其实,它完全可以共享出来。就像我鼓励大家分享工具使用心得一样,我也鼓励你把调试 bug 的经验分享给项目组或团队成员。
💡提示 4:记录下你的调试经历,偶尔组织一次午餐分享会或周五学习时间,讲讲你遇到的 bug 和解决过程。
这些故事不需要是什么重大事故,也不用是 “英雄行为”,而是日常遇到的普通问题。如果我从五位同事那里听到与 “时区问题” 相关的调试经历,当我真的遇到时区 bug 的时候,自然就能更有准备。
你可以尝试以下方式进行知识共享:
- 在团队的 Wiki、Notion、Confluence 上建立调试经验库;
- 每周组织一次 “Bug Friday” 或 “午餐分享”,讲讲你遇到的 bug;
- 总结典型坑,比如跨域失败、异步更新顺序、时区相关错误等。
📄 调试经验记录模板参考:
【问题描述】登录接口返回 200 但页面无跳转
【触发方式】登录后点击按钮,开发环境正常,线上异常
【定位过程】
- 检查 Network,请求返回正常
- 发现 login 函数中 Promise 没有 await
- 修复后跳转恢复正常
【复盘总结】
需加强对异步流程的规范管理,避免状态未更新时提前进行跳转逻辑
跟橡皮鸭说话
如果你真的尝试了所有办法还是卡住了,那就请出橡皮鸭吧。橡皮鸭调试(Rubber duck debugging)虽然在行业里有点像是个玩笑,但它其实真的是一种非常有效的方法。

简单来说,方法如下:
- 拿一只橡皮鸭(没有鸭也可以用别的玩具动物,实在不行就拉同事来)
- 把你的问题完整地说出来;
- 告诉它你已经尝试过哪些方法、为什么没成功
- 向它寻求建议
我的经验是:往往在鸭子还没 “回答” 之前,你自己就已经想出解决办法了。
💡提示 5:多跟鸭子说话,或者写下来你的想法,帮助理清思路、发现隐藏的假设漏洞。
这是因为我们大脑在自己思考时很容易 “骗自己”。当你自己和自己对话时,大脑会跳过一些细节。你可能觉得 “我已经试过了”,但其实你跳过了某些步骤,因为它 “看起来太明显”。当你必须用语言讲出来,就会强迫自己梳理所有细节。这时候,缺失的步骤就很容易暴露出来了。
找到这些 “漏掉的步骤”,通常就能帮助你发现问题所在,至少也能帮你推进一步。
鸭子议会:向自然取经

我以前住在柏林时,附近一棵树下住着一群野鸭。我称它们为 “Rummelsburg 鸭子议会”。当我自己手边的三只橡皮鸭不够用了,我会去散步顺便 “向议会请教”。
这当然是一种幽默表达,但它背后的原则是真实有效的:调试的本质就是不断验证假设,不断缩小问题范围。
🦆!
最后总结
调试不仅仅是修复 bug,更是一项核心的开发技能。通过本文你应该能意识到:
- 思维方式 > 工具;
- 简单方法(如打印)也很有价值;
- 工具熟练度和团队交流能极大提升调试效率;
- 问题不可怕,找到它的方法才重要。
关于本文
译者:@飘飘
作者:@Juhis
原文:flaky.build/debug-like-…