如果我们有好的开发者、好的单元测试和好的代码审查者,我们就无需调试器






4.60/5 (9投票s)
我部分同意基本观点,但在需要处理单元测试未能捕获的、并且好的开发者和代码审查者也无法理解发生什么的问题时,这个观点就失效了。
引言
这篇文章主要讲如何编写不会失败的代码。但是,如果代码确实失败了,那么能够以可接受的方式弄清楚问题所在是必须的。
这篇文章的标题是我在谷歌听到的,对我来说,它代表了这家公司很多问题所在。具体来说,我们当时正在试图弄清楚发生了什么,因为我们只收到了一些“崩溃”的日志,没有额外的额外信息。当我问我们是否有实际的调试工具时,他们告诉我,如果代码编写得好,由优秀的开发者编写,文档齐全,审查充分,并且有好的单元测试,那么我们就无需调试器。然而,这个回答完全忽略了真正的问题:我们有一个没人知道的 bug,而所有这些“好的东西”并没有阻止它的发生。
调试器,我们为什么需要它们?
所以,这篇简短的文章就是关于我们为什么需要调试器的。
调试器在理解代码执行过程中发生了什么方面非常棒。它们的名字可能暗示它们“只是用来找 bug”的,但它们的作用远不止于此。通过逐行调试,甚至稍微修改变量来看会发生什么,你可以学到很多关于一个应用程序(或一个函数)正在做什么的知识。
无论如何,我认为它们是查找“意外问题”的必备工具。并不是说不可能用其他技术来查找 bug(事实上,这正是我当时在谷歌工作时需要做的事情)……然而,一个调试器可能会将一整天添加日志、审查日志、修改代码、重新运行一切的过程,缩短为 5 分钟的单步跟踪、查看变量状态、也许修改其中一些变量、找到 bug。
因此,调试器是轻松查找实际问题的绝佳方式。
什么是实际问题?
当谈论编程时,我所说的实际问题是指“未见或未检测到的 bug”。我的意思是,在开发过程中,一切似乎都很好。然而,在“现实世界”(也就是说,当产品发布给公众时),出现了一些 bug。这是最糟糕(也有些普遍)的情况:当产品发布给世界时,我们不再只有少数几个开发者在测试他们能想到的所有可能性。我们可能会有全世界的人在使用应用程序,并进行各种计划外和/或意想不到的操作。
好的开发者如何提供帮助?
所以,回到这篇文章的标题,好的开发者有助于避免任何需要调试的情况。从这个意义上说,“如果我们有好的开发者就不需要调试器”这个观点是正确的。只要开发者 **永远** 不犯错,我们 **永远** 都不会需要调试任何东西。但是,如果我们确实犯了错误,我们该怎么办?
我甚至有一个故事,我曾和一位朋友谈论过优秀的编程,他告诉我,在‘一个完美的世界里’,所有的代码都会有好的单元测试。对此我回答说,在这样一个完美的世界里,任何开发者都不会犯错,也就不需要单元测试了。
即使我有点自相矛盾,但整个想法是:如果你 100% 确定你的代码永远不会导致错误(并且你的信念确实是正确的),那么也许好的单元测试没有帮助。一切已经完美了。但是,如果单元测试未能避免问题,至少让你的代码‘对调试器友好’……我希望你的项目能处理调试器。
调试器,哪些是好的?
我无法针对所有语言和所有情况真正回答这个问题,但对我来说,一个好的调试器需要
- 允许我在任何地方设置断点(而好的代码一次/一行只做一件事,所以我可以在真正想要的地方设置断点)……也就是说,避免像
a(b(), c(), d(e(), f()));
这样的调用 - 允许我查看所有变量(包括返回值,在方法返回之前);
- 允许我更改变量值,以便我可以尝试不同的情况;
- 允许进行基本的单步执行、单步进入、单步退出操作。
嗯……可能还有很多其他需要考虑的事情,但这些是我真正使用并对我帮助很大的东西。而且,不,单元测试从未帮助我解决过新的 bug。它们在避免旧 bug 再次出现(并且如果计划得好,可能永远不会出现)方面非常棒,但它们无助于解决现有 bug。
对于那些被避免的现有 bug 呢?
哦……我的文字可能太刺耳了。单元测试确实可以避免实际 bug 的出现,我并不是说我们不需要它们。我只是说单元测试是关于“已知(可能)会发生”的 bug,即使可以处理不同的情况(通过更好的开发者),它们很少能解决“现有 bug”或完全“意外的 bug”……这才是调试器(或者在某些情况下,当某些东西已经“不妙”时进行大规模重构)的用武之地。
没有调试器?
如果你遇到这种情况,我感到很抱歉。尝试在你的代码中插入“debug”语句,“puts()”、“Console.WriteLine()”和类似的代码。我希望你能得到一个好的调试器,但如果没有,你就需要采取“老派”(或者说‘几乎没资源’)的方法了。
历史
- 2020 年 1 月 5 日:初版