现在是星期五下午 3 点。为什么?因为当事情发生的时候,总是星期五下午 3 点。您收到通知,客户在您的软件中发现了一个错误。在您克服最初的难以置信之后,您联系 DevOps 以了解您的应用程序日志发生了什么情况,因为您记得收到通知说它们正在被移动。
事实证明它们在您无法访问的地方,但它们正在被移动到一个 Web 应用程序——因此您将拥有这个很棒的应用程序来搜索和阅读它们,但当然,它尚未完成。它应该在几天内完成。我知道,完全不现实的情况,对吧?不幸的是,事实并非如此;似乎日志或日志消息经常在错误的时间丢失。在我们追踪错误之前,请发布一个公共服务公告:定期检查您的日志,以确保它们在您认为它们在的位置,并记录您认为它们应该记录的内容。当您不注意时,这些事情竟然会发生变化,这真是令人惊讶。
好的,所以您找到了日志或尝试了调用,并且确实,客户发现了一个错误。也许您甚至认为您知道错误在哪里。
您立即打开您认为可能是问题所在的文件,并开始四处查看。
1. 暂时不要修改您的代码
继续查看它,甚至可能提出一个假设。但是在您开始在代码中乱搞之前,请进行导致错误的调用,并将其转换为测试。这将是一个集成测试,因为尽管您可能有所怀疑,但您还不知道问题究竟出在哪里。
确保此测试失败。这很重要,因为有时您进行的测试不会模仿损坏的调用;如果您使用的是 Web 或其他可能混淆测试的框架,则尤其如此。许多内容可能存储在变量中,但不幸的是,仅通过查看测试,您并不总是能清楚地知道您在测试中进行的调用。我不会说我创建了一个在尝试模仿损坏的调用时通过的测试,但是,好吧,我做了,而且我认为这并不是特别不寻常。从我的错误中学习。
2. 编写一个失败的测试
现在您有了一个失败的测试,或者可能是一个带有错误的测试,现在是时候进行故障排除了。但在您这样做之前,让我们回顾一下堆栈,因为这使故障排除更容易。
堆栈由您已启动但未完成的所有任务组成。因此,如果您正在烤蛋糕并将面粉添加到面糊中,那么您的堆栈将是
- 制作蛋糕
- 制作面糊
- 添加面粉
您已经开始制作蛋糕,您已经开始制作面糊,并且您正在添加面粉。在列表中没有涂油锅,因为您已经完成了该步骤,并且在列表中没有制作糖霜,因为您尚未开始该步骤。
如果您对堆栈感到模糊,我强烈建议您在 Python Tutor 上玩一下,在那里您可以观看堆栈,因为您执行代码行。
现在,如果您的 Python 程序出现问题,解释器会非常有帮助地为您打印出堆栈。这意味着程序在意识到出现问题的那一刻正在执行的操作位于底部。
3. 始终首先检查堆栈底部
不仅可以在堆栈底部看到发生了哪个错误,而且通常堆栈的最后一行是您可以找到问题的地方。如果底部没有帮助,并且您的代码已经有一段时间没有进行 linting,那么运行 linting 工具会非常有用。我推荐 pylint 或 flake8。通常,它会直接指向我一直忽略的错误所在。
如果错误似乎很模糊,那么您的下一步可能只是在 Google 上搜索它。如果您不包含仅与您的代码相关的信息,例如变量、文件等的名称,您将更有运气。如果您使用的是 Python 3(您应该使用),则在搜索中包含 3 会很有帮助;否则,Python 2 解决方案往往会占据顶部。
曾几何时,开发人员不得不在没有搜索引擎的情况下进行故障排除。那是一段黑暗的时期。充分利用所有可用的工具。
不幸的是,有时问题发生得更早,并且仅在堆栈底部执行的行期间才变得明显。想想看,当蛋糕没有发起来时,忘记添加泡打粉会变得多么明显。
现在是时候查看堆栈了。问题很可能出在您的代码中,而不是 Python 核心甚至第三方软件包中,因此首先扫描堆栈以查找您的代码中的行。此外,在您自己的代码中设置断点通常要容易得多。将断点放在代码中堆栈中稍高的位置,并环顾四周,看看事情是否看起来应该如此。
“但是 Maria,”我听到你说,“如果我有堆栈跟踪,这一切都很有帮助,但我只是有一个失败的测试。我从哪里开始?”
Pdb,Python 调试器。
在您的代码中找到一个您知道此调用应该命中的位置。您应该能够找到至少一个位置。在那里插入一个 pdb 断点。
题外话
为什么不是 print 语句?我曾经依赖 print 语句。它们有时仍然很方便。但是一旦我开始使用复杂的代码库,尤其是那些进行网络调用的代码库,print 就变得太慢了。我最终到处都是 print 语句,我失去了对它们在哪里以及为什么在那里的跟踪,而且它变得很复杂。但是主要使用 pdb 有一个更重要的原因。假设您放入一个 print 语句并发现有些问题——并且一定在更早的时候就出错了。但是查看您放入 print 语句的函数,您不知道您是如何到达那里的。查看代码是了解您要去哪里的一种好方法,但它对于了解您去过哪里来说很糟糕。是的,我确实 grep 了我的代码库,查找函数在何处被调用,但这可能会很乏味,并且对于流行的函数来说,它并没有缩小范围。Pdb 可能非常有用。
您听从我的建议,放入一个 pdb 断点并运行您的测试。它呼啸而过并再次失败,根本没有中断。将您的断点留在其中,并运行测试套件中已有的一个与损坏的测试非常相似的测试。如果您有一个像样的测试套件,您应该能够找到一个命中您认为失败的测试应该命中的相同代码的测试。运行该测试,当它到达您的断点时,执行 w
并查看堆栈。如果您通过查看堆栈不知道另一个调用可能在哪里出错,那么在堆栈中向上走一半,找到一些属于您的代码,并在该文件中放置一个断点,在堆栈跟踪中的行上方一行。使用新测试再次尝试。不断来回,向上移动堆栈以找出您的调用在哪里偏离轨道。如果您一直到跟踪顶部都没有命中断点,那么恭喜您,您找到了问题:您的应用程序拼写错误。这里没有经验,不,一点也没有。
4. 改变事物
如果您仍然感到迷茫,请尝试进行一个新的测试,您可以在其中稍微改变一些东西。您可以让新测试工作吗?有什么不同?有什么相同之处?尝试改变其他东西。一旦您有了测试,并且可能还有其他测试,就可以安全地开始更改代码中的内容,以查看是否可以缩小问题的范围。请记住从一个新的提交开始进行故障排除,这样您就可以轻松地撤消没有帮助的更改。(这是对版本控制的引用,如果您没有使用版本控制,它将改变您的生活。好吧,也许它只会使编码更容易。请参阅“版本控制可视化指南”,以获得一个很好的介绍。)
5. 休息一下
认真地说,当它不再感觉像是一个有趣的挑战或游戏,而开始变得非常令人沮丧时,您最好的行动方案是远离问题。休息一下。我强烈建议去散步并尝试思考其他事情。
6. 写下所有内容
当您回来时,如果您没有突然受到启发去尝试某些事情,请写下您拥有的有关问题的任何信息。这应该包括
- 确切的导致问题的调用
- 确切发生了什么,包括任何错误消息或相关的日志消息
- 您期望发生的具体情况
- 您到目前为止为查找问题所做的工作,以及您在故障排除时发现的任何线索
有时这会包含大量信息,但请相信我,试图从某人那里零星地挖掘信息真的很烦人。尽量简洁,但要完整。
7. 寻求帮助
我经常发现,仅仅写下所有信息就会引发关于我尚未尝试过的事情的想法。当然,有时,我会在点击提交按钮后立即意识到问题所在。无论如何,如果您在写下所有内容后仍然没有想到任何事情,请尝试向某人发送电子邮件。首先,尝试联系您的同事或参与您项目的其他人,然后继续联系项目电子邮件列表。不要害怕寻求帮助。大多数人都很友善和乐于助人,我发现这在 Python 社区中尤其如此。
Maria McKinley 将在 Hunting the Bugs 在 PyCascades 2019 上演讲,时间是 2 月 23-24 日,地点在西雅图。
评论已关闭。