如何提高调试现有代码的能力


Answers:


32

不要承担任何责任

常常说“哦,我知道这段代码在做什么,很好”。不要那样做 测试每个假设,并仔细完成所有步骤。


2
+1。绝对。准备对您以为知道的一些东西会在您身上耍把戏感到惊讶。
2010年

为我工作:)
setzamora

3
调试其他人的代码是浪费大量时间,是生产力的杀手,但是事实就是如此。只有在其他人离开时,才真正有必要修复其他人的错误。我讨厌的东西讨厌的东西是由高级编码器客观地整理一些糟糕的代码,然后不得不问一个问题以便及时取得进展,并举办有关提高我学习现有代码库技能的讲座。与研究母亲本性不同,解决人为因素带来的麻烦并不容易。至少我得到了答案。相反的情况不会发生,因为我会更好,并且会留下更少的错误。
工作

1
@工作:...好吗?您是说要保留此评论吗?:)
亚当·李尔

这个!如果您正在调试一个奇怪的问题并且代码看起来还不错,那么盲目地信任代码中的任何一点是很愚蠢的。
2013年

7

逐步测试

首先深入代码中,然后从最小的模块逐步向上进行测试,这样,您就不必费力就能找出问题的根源所在。

这也意味着自从您逐步移动以来,它一次只影响较少的代码。因为有时我遇到了一些问题,这些问题中我修复了某些问题,并导致破坏了许多其他内容。我为此感到称赞,因为当我四处乱逛时,他教我这一点。


4

分而治之是一个好方法。尝试找出存在此问题的一些可见输入(用户输入/网络事件...)和输出(日志,向用户输出,出站网络消息...)。尝试将打印内容放置在较大的块或它们之间的重要位置,并缩小代码中错误的位置。

在对版本控制代码进行回归的情况下,分而治之也可以很好地工作。找到两个版本-一个可以按预期工作,另一个通过回归。缩小差距,直到您留下一堆潜在的可疑物品。


4

而不是二进制错误印章,而是以以下形式编写测试:

  • 鉴于...
  • 什么时候...
  • 期望...

验证您对应用程序功能的实际了解与假设的真实情况。

大多数IDE使得提取方法和生成xUnit测试存根变得容易。利用它。

为什么不进行调试?因为完成后,您可能将不得不撤消大部分工作并删除大量的调试信息。在编写测试时,调试将有助于预防和检测将来的错误。


2

继续调试。如果您进行大量调试,则会有所改进。


绝对调试本身就是艺术,尤其是调试其他人的代码。
Gratzy

2

正如其他人所说的-不要承担任何责任。如果您已编写其代码,则尤其如此。在调试其他代码时,您很可能会放慢速度,因为这些代码对您来说是新的,或者您不信任编码器。调试自己的代码时,很容易以为您没有正确编写代码,请放慢速度!

对于实际的调试过程:

  • 编写单元测试(如果尚不存在)。
  • 如果尚不存在,请添加适当的日志记录。
  • 然后使用调试。

与先使用调试器相比,添加单元测试和记录日志效率更高。您还将获得单元测试的更多优势,以帮助避免引入将来的错误,而日志记录将有助于将来调试会话。


1

在浏览一小段代码之前,请查看您是否可以准确确定结果。面对任何不采取任何措施(我赞成,顺便说一句)的做法,这种做法确实会飞起来,但是随着您积累经验,它可以帮助缩小查找范围。

这听起来很琐碎,但要了解调试器的细微差别并了解热键。有时,调试器的运行速度可能会很慢,以至于您单步执行时会感到疑惑。如果您可以跟上机器的进度并且不停地乱逛,那将会有所帮助。

如果您可以在调试时修改代码:

  • 考虑声明前后条件。有时您可以跨步执行,而不是编写代码。
  • 对于具有复杂表达式的if语句,请考虑一些问题(有些人对此不满意,但对我有用)

喜欢:

bool isLessThan5 = a < 5;
bool isGreaterThan10 = a > 10;
if ( isLessThan5 || isGreaterThan10 )
{
   // more code here
}

代替:

if ( a < 5 || a > 10 )
{
   // more code here
}

对于这种情况,无论出于何种原因您都无法调试所有内容,请与同事一起学习“橡皮鸭式”。有时,解释的行为会引起人们的注意。(好的,也许这不是问题主题,但我认为它已经足够值得提及)


1
子条件的命名还需要更多步骤,即当您找到条件的用途时,名称的重构。可能if (tooCloseToHydrant || overTheBrink) { 后来才知道更多。

1

基于过去22年中大部分时间用于维护他人编写的代码的两件事。

了解您倾向于编写的各种错误。

例如,我是一个非常细致的编码器,因此一旦我的代码编译完毕,它通常就不会出现一些小错误。因此,我的错误通常是诸如线程死锁之类的复杂事物。另一方面,我有一个朋友,他主要编写一些琐碎的错误-在C ++的循环末尾使用分号,因此下一行仅执行一次,这种事情。

不要以为别人会写和你一样的错误。

我不知道我浪费了很多时间抽出大型调试枪,假设一个错误是我那种非常微妙的怪异事物,只是让我的朋友看着我的肩膀走了,“你注意到了吗?分号?” 经过多年的努力,当我着眼于其他人的代码时,我首先尝试了一些琐碎,低落的成果。


您是否重新格式化代码以查看是否有任何变化?

@Thorbjørn:如果我拥有代码的所有权,有时我会这样做以提高可读性,但找不到错别字。有趣的主意!
鲍勃·墨菲

您不必提交它,只需看看会发生什么。我强烈建议执行,需要的代码重新格式化政体-最好是自动地-在托运时。

@Thorbjørn:我很乐意这样做。您建议将什么作为代码“修饰符”?我主要在Linux和Mac上工作。
鲍勃·墨菲

我在两个地方都使用Eclipse,并且Java编辑器有一个所谓的Save操作,您可以在其中指定每次保存文件时应执行的操作。这里的选项之一是格式化源。我们是一个小团队,所以我没有对此进行更多调查。经验更丰富的团队允许在源代码管理系统中进行预提交挂钩,从而允许在格式错误的情况下拒绝源提交。非常有效率。

1

了解您的工具。例如,Visual Studio的调试器具有一个称为TracePoints的强大功能,它类似于断点,但不是停止代码而是将trace语句插入调试输出中。

强烈建议您阅读书籍或参加有关如何使用调试器的课程。我上了几节课,读了约翰·罗宾斯(John Robbins)的几本书,这对我作为调试器的有效性产生了很大的影响。


0

从功能上理解代码正在尝试执行的操作。如果您不了解完整情况(此代码必须通过所有测试用例),则很难在不引入新错误的情况下正确调试


0

编写自动化的单元测试以及其他类型的集成和功能测试。

您拥有的自动化测试越多,花费在调试器上的时间就越少。

另外,好的设计-SOLID原则。如果您正在编写小型的,重点突出的类,并且倾向于继承而不是继承,消除重复等,那么您的代码将始终易于调试。

我发现设计良好的代码会产生一组错误的错误,这些错误的代码设计得不好。一般来说,设计良好的代码会产生易于查找,复制和修复的错误。

例外(总是有一个例外)是多线程代码:-)


0

如果您已将其范围缩小到一个较小的区域,但仍无法发现错误,请尝试调试器的“查看代码+程序集”选项。知道足够多的ASM可以说“这里应该有一个分支”或“为什么只复制低位单词?” 通常会查明编码错误。


0

查阅Andreas Zeller 撰写的非常有价值的书《为什么程序失败:系统调试指南》。它将向您介绍许多技术,理论和工具,其中一些处于研究的前沿。

该书的幻灯片可在线获得,但我发现该书本身更易于阅读。

这本书将帮助您入门,并使您对调试进行更科学的思考,但是它不能替代实践。您可能需要进行10年的编写和调试工作,然后才能看到性能上的数量级提高。我仍然记得在Sun见到我时曾大吃一惊,看到高级程序员已经为Unix编程了30年,他们在几分钟之内就发现了晦涩的多线程或并行错误。经验很重要!


他们的自动化软件看起来非常有趣。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.