在"编程实践"的第5章中,Brian Kernighan和Rob Pike写道:
作为个人选择,除了获得堆栈跟踪或变量或两个变量的值之外,我们倾向于不使用调试器.
虽然我没有关于该主题的经验数据,但我怀疑许多程序员可能会在他们的环境中有一个可用的"调试器"中"活".但我也怀疑有许多高效的程序员,像Kernighan和Pike一样,避免将调试器作为第一道防线并依赖其他技术.
所以,我想问一下stackoverflow社区:
如果您是那种将"调试器"工具视为最后手段(不是获得初始堆栈跟踪)的程序员,那么您首先使用其他技术的原因是什么?
每个答案一(1)个理由请更容易投票!
我还建议这个规则回答:"我不知道如何使用调试器"不是一个有效的答案.那只是无知.在做出选择之前,您应该了解您的替代方案!
不通过代码使用调试器到F10/F11可以使您成为更好的开发人员.
在我的第一份工作期间,我在Linux中进行了大量编程,其中Visual Studio调试器不可用.因为调试很难,我已经学会了如何分析我的代码并真正理解它是如何工作的.由于这个原因,我成了一个更好的开发者.
现在我只是在我查完代码并搜索"通常的嫌疑人"之后才使用调试器,如果我不理解我的代码如何工作而没有调试它,那么我重构它.
使用调试器作为最后手段的原因是什么?
因为通常使用其他技术而不是使用调试器,我可以更快地找到错误.
我认为Kernighan试图说明有意识的分析.在不了解森林的情况下,不要在树上潜水.也就是说,有是其他原因喜欢不同的工具比调试器,作为助手你的头脑.
我最喜欢的(如果这是正确的话)例子是内存错误.在像C或C++这样的语言中,滥用内存系统(双重删除,通过死指针访问对象,运行数组的末尾)可能会破坏程序,使问题不会在原始数据附近出现.原因.
这些语言中的适当方法是使用消除这些错误的实践,但如果失败,工具也是有价值的.当我遇到类似错误的经历让我怀疑"这感觉就像是一个记忆错误"时,在我想到"调试器" 之前,我会找到valgrind.
现在我们可以开始论证自动内存工具和边界检查库是调试器!; ^)〜
我更喜欢使用TDD并添加一个破坏代码的测试.然后很容易看出错误发生的位置,并在没有调试器的情况下修复它,现在我有一个可以防止该错误的测试.
不同工具的不同工具.就像你不会将Perl用于所有内容一样,你不会为每个bug使用调试器.有时使用调试器符合问题,有时则不适用.
以我们其中一个产品中出现的错误为例.它正在拉动最后一个窗口,使焦点在打印方法后重新聚焦.附加调试器后无法重新启动,但可能会在何时重新启动.最终通过良好的老式Console.Write()
陈述解决了这个问题.
在我看来,必须转到调试器可能是一个更深层次问题的迹象.
在启动调试器之前,我会提出针对更深层次问题的问题,例如:
哪个测试失败了?如果答案是"没有测试",那么没有对失败条件进行测试是首先要解决的更深层次的问题.
异常有哪些信息?(这假设一个有例外的环境).如果答案是"没有异常",或者异常没有太多上下文,那么扫描吞下异常的地方,或者向异常添加更多上下文是首先要解决的更深层次的问题.
构建该部分系统会产生什么警告?如果您没有使用现代工具构建和分析系统以查找常见错误,并在运行时出现错误进行更正,那么您需要先解决更深层次的问题.
我们是否足够了解问题领域以推断可能发生的事情?如果答案是"我们不清楚这一点",那么与主题专家的讨论是有道理的,这些专家可以使一个系统的目的更加清晰.如果没有明确了解的要求,可能会出现更多错误.
做这些事情通常会导致至少一个错误修复,如果不是几个.这些方法具有非常有价值的副作用,强迫程序员思考问题,整个问题,而不仅仅是"错误发生的地方".
当然有些情况下,单行上发生错误,如不检查空指针/引用等,但现代IDE和工具有助于消除的错误类型不是那些"简单"错误吗?只需运行lint/static-analysis工具并注意警告 - 您将不再获得这些类型的错误.那么你就会遇到需要人类思维推理的设计错误之类的东西 - 调试器如何解决这个问题呢?
转储到文件的打印语句可以在文本上操作.grep,sort,sed和awk可以帮助解决复杂的调试问题.如果有必要,还可以编写一个小程序来解析转储的文本.