在开发应用程序的过程中,将不可避免地引入错误(i代码,因此我可能会创建bugs 〜Descartes)。可以出于多种原因引入虫子,例如逻辑错误,对要求的误解,缺乏测试,紧迫的截止日期或类似于违规的人类的简单性。但是,知道错误是不可避免的,我们可以使用工具来武装自己在野外释放之前快速识别和解决软件错误的工具。
许多人认为他们已经知道有关查找和修复错误的所有知识,或者调试可能是事后的想法,因为他们认为该功能开发应该优先。现实情况是,以偶然的,无效的方法进行调试是太普遍了。随意的方法可能导致挫败感和浪费时间,实际上可以阻止您为用户创作新功能。
在这篇文章中,我们将分解您在开发软件应用程序时可以采用的调试以及一种方法。此外,我们将在您可能不知道的调试工具箱中添加更多工具。我们还将回顾一些有趣的错误案例研究,并指出作者如何在其方法中采用一些调试技术。这篇文章对编程概念有所了解。
如果我们接受不可避免地创建软件会导致错误的创建,那么我们必须接受软件开发中所花费的某些时间必须分配以维护和调试现有代码。
调试是定位,识别和修复错误的过程。即使测试可能会揭示错误的存在,但它也不会告诉我们确切的错误是什么或如何修复代码。通常,开发人员将以次优的方式进行调试:在代码库中随机打开文件,以期找出问题的来源;以看似随机的方式更改代码线,并重新启动服务器,希望其更改已解决问题;或更糟糕的是,被瘫痪在以为不应进一步触摸该代码的情况下担心其他意想不到的后果。
拥有出色的软件带来了巨大的责任。这对我们的用户不利于发货,因为这些错误可能导致意外的结果。根据您正在运营的行业,软件错误可能会导致财务损失,声誉损失,用户失去信任或人身伤害,或者他们可以因造成安全漏洞而臭名昭著。
以下著名错误证明了在将错误挤压给用户之前挤压错误的重要性:
下面,我将分解我的个人调试方法。我依靠我在其他工程学科中学到的原则,与其他开发人员配对的多年观察,并利用如何提高故障排除技能的资源。
重要的是要注意,这篇文章假设我们尚未阻止并检测到具有错误处理,测试,刺激,静态类型检查,正确的代码格式和其他辅助工具的某些软件错误。
我喜欢在调试时遵循科学方法:
对于第1步,进行观察,我首先检查是否仍然存在buggy行为,或者实际上是所有错误报告中的错误,或者用户可能是错误的不准确地报告问题。有时,我会选择一个错误票,但是当我去验证错误行为时,该错误已经被其他工作确定了。重要的是要验证行为是否在不必要的解决方案上花费时间之前仍然存在。如果仍然存在越野车行为,我会验证它也发生在我的本地开发环境中。这有助于消除仅由于环境配置差异而导致生产中可能存在的任何细微问题。
我发现大部分工作应在步骤2中完成:收集信息。这是知道您可以使用哪些工具的地方,包括:
作为开发人员,我们很幸运,有多种工具可以帮助我们进行数据收集。辩论者,日志和其他开发工具都应被利用来追踪有关该错误的尽可能多的信息。他们确实可以帮助缩小问题的范围。我会恳请任何阅读此帖子的人更深入地探索这些工具,因为不断进行更新以改善开发人员的体验。关于您可能使用的任何开发工具,有大量资源可用。这些工具将在整个职业生涯中为您提供帮助,因此,学习良好的时间是您的时间非常好!
对于第3步,做出假设,消除您对程序的运作方式的任何假设很重要。提出关于该错误根本原因的假设应涉及清晰的思考。随机猜测这里不会有帮助,因此请务必退后一步,并使用您在上一步中收集的所有信息来做出明智的决定。真正棘手的错误,尤其是那些缺乏错误消息的错误,可能需要通过明智的反复试验来解决。
提出假设后,您可以进入步骤4,测试假设:您可以在怀疑包含该错误的代码库中缩小范围。然后,您可以在可疑的代码区域之前添加调试器语句,以介绍变量和函数如何运行,评论或修改代码的特定部分,或创建解释该行为的单位或集成测试,并重新运行测试套件。
与步骤2(收集信息)一起,我相信步骤5,分析您的测试是否有效,其次是重要的。经过修改的代码库部分后,您应该检查更改。仔细的分析可以帮助您确定该错误是否隔离到代码库的这一部分,还是在代码库其他部分的类似区域中存在错误行为。如果尽管您进行了更改,但仍存在越野车行为,则需要循环返回步骤1并重复此过程。
在各种错误上执行这些步骤后,当您遇到任何新问题时,您将自动开始循环通过这些步骤。这可以帮助您解决报告的错误,但也可以在将其投入到代码库之前,在捕获错误之前有助于捕获错误。
这种方法的好处是,在配对编程时也可以使用它。在问题上有多种眼睛并通过这些步骤进行循环可以帮助您更快地发现问题。我发现,要求对每个人配对阈值的时候是不同的,但是要利用队友和他们的知识很重要。您可以问自己谁最后一次从事此功能,或者谁对此功能了解很多,并且可以提供更多的见解?
除了我喜欢使用的方法外,我还喜欢牢记以下内容:
在此post中,关于碰撞Bandicoot 1中的存储卡错误,作者描述了它们如何缩小问题:
关于您唯一可以做到的想法调试时唯一可以做的事情是划分和征服:继续删除越来越多的错误程序的代码,直到您留下相对较小的东西仍然展示的东西问题。您一直将零件雕刻出去,直到剩下的唯一的东西就是错误的位置。 我反复返回测试程序,试图检测到计时器设置为1KHz时发生的错误的某些模式。最终,我注意到有人在使用PS1控制器时发生错误。既然我很少这样做 - 为什么在测试负载/保存代码时会与控制器一起玩?我没有注意到它。但是有一天,其中一位艺术家正在等我完成测试。它失败了。 “等等,什么?嘿,再做一次!”
关于您唯一可以做到的想法调试时唯一可以做的事情是划分和征服:继续删除越来越多的错误程序的代码,直到您留下相对较小的东西仍然展示的东西问题。您一直将零件雕刻出去,直到剩下的唯一的东西就是错误的位置。
我反复返回测试程序,试图检测到计时器设置为1KHz时发生的错误的某些模式。最终,我注意到有人在使用PS1控制器时发生错误。既然我很少这样做 - 为什么在测试负载/保存代码时会与控制器一起玩?我没有注意到它。但是有一天,其中一位艺术家正在等我完成测试。它失败了。 “等等,什么?嘿,再做一次!”
总而言之,如果您从这篇文章中删除任何东西,那就让我们这样做:调试是一项技能,可以改善。通过使用有条理的结构化方法,您可以改善检测和解决错误的速度。这样做将为您的用户提供更愉快的开发体验和更强大的应用程序。
愉快的编码!