应该将调试代码保留在原处,始终保留还是仅在调试时才添加,而在发现错误后才删除?


35

首先,我只在尝试查找错误时才添加调试代码(例如print语句)。找到后,我将删除调试代码(并添加一个专门测试该错误的测试用例)。我觉得它使真实的代码混乱不堪,因此除非进行调试,否则就没有地方了。

你怎么做呢?您是否将调试代码保留在适当的位置,或者在过时删除调试代码(可能难以确定调试代码的时间)?

Answers:


30

调试打印语句应被取出;但是,如果您需要添加它们来调试生产问题,那么可能有必要考虑是否将足够的信息放入日志记录框架中。有关参数,错误条件等的信息可能在以后出现下一个错误时很有用。使用良好的日志框架可以动态调试或跟踪日志消息,这在野外非常有用。


5
+1主要是因为提到有一个适当的调试框架。如果最初就位,并且有各种调试级别,那么生产代码可以希望运行而无需调用昂贵的调试例程,并且开发代码可以在需要任何级别的审查的情况下运行,并希望以所需的任何方式登录。
2011年

1
同意Orbling。另外,对于调试代码,除了信息显示以外,还可能影响性能或其他不适合生产的原因。(例如,对函数结果进行断言,例如检查排序结果),您可以考虑两种构建目标模式。调试模式和释放模式。
Zekta Chan 2011年

16

应该从生产软件中删除专门为调试添加的代码。

这是完全删除还是放入条件编译部分(如C / C ++ / C#),取决于您和您的编码标准。

有许多的原因:

  1. 如果执行此代码或某人可以访问其输出,则可能会带来安全隐患。
  2. 这可能会使应用程序变慢。
  3. 对于其他开发人员来说,六个月后才开始查看代码(或您自己)可能会造成混乱。

+1用于条件编译,但注释块将在不支持它们的语言中工作。您永远不应将其编译为产品发行版,但有时在每次要删除发行版时都将其完全删除是非常低效的。
比尔

1
我曾在始终使用调试选项编译C / C ++代码的环境中工作,以防需要调试生产代码或检查核心转储。有时,这种随时准备调试的命令要求保留调试语句,以便可以使用标志将其打开而无需重新编译代码。如果为Java设置了JVM选项,则Java始终允许进行调试,因此,以后进行调试所需的准备工作相对较少。
Michael Shopsin

16

ChrisFAlaric都有有效分数;为他们+1。我可以确定至少使用5种不同类型的调试代码。

  1. 使用日志在特定时间点转储系统状态。

    void function(...)
    {
        ...dump everything i know about.
    }
    
  2. 使用日志作为执行检查点。

    void function(...)
    {
        ...got here 1
        ...got here 2
    }
    
  3. 实际上强制某个条件为真,但破坏正常行为的代码。例:

    • 假设您有一些有关错误的日志,但是您无法重现该问题。您可以尝试编写代码,以强制某些变量具有与日志中的信息匹配的某些值。
  4. 验证日志记录-我将其分类为详细日志记录,可用于验证不应包含在生产中的软件正确性,例如,验证算法的各个步骤。

  5. 操作记录-请参阅Alaric的帖子。这几乎就是我所说的“操作日志”。

1、2和3应该完全取出。大概是4,我可能会有条件地从代码中进行编译。对于5,Alaric具有能够动态关闭日志的优点。在大多数情况下,这可能会解决ChrisF在第二个要点的观点


1
这是一个很好的总结。但是,如果可以通过将1)… 替换为1.…(以便Markdown格式将其作为列表列出)并将示例代码缩进8个空格(同样使Markdown将其作为示例)来正确格式化,则更好。列表中的代码)。
康拉德·鲁道夫

@Konrad Rudolph:完成。
gablin 2011年

3

这取决于代码在做什么。可以保留一些用于调试的代码,而应将其删除。

一旦代码正常运行,验证方法中参数是否合理的代码并不总是有用的,但通常会确保代码继续正常运行。

有时您会以不同的方式编写代码,以使其更易于调试代码,例如计算值并将其放入局部变量,然后在下一行使用该变量,这使得在单步执行时易于检查计算结果通过代码。您可以重写代码以直接使用计算所得的值,但是使用局部变量的成本非常小(如果有的话),几乎没有理由重写代码。同样,在测试完代码后也有一点要保持不变,在更改代码时始终存在引入错误的风险。

发现错误后,通常可以删除仅为跟踪特定错误而添加的代码。


2

从前,我曾经使用很多调试代码。我几乎完全瞄准了Windows,因此有很多这样的调试字符串输出函数我不记得该如何拼写了,因此可以使用特定程序捕获跟踪。

一些调试代码保留在原处,而某些特定的东西旨在提供调用的嵌套。但是,即使调试字符串在生产系统上大部分不可见,它仍然全部在条件编译下完成。

但是现实是,所有调试代码都需要花很多精力才能以一种理想的方式进行处理-当然要使用调试器。那时,我对Borland C ++调试器没有什么印象。工具虽然在那里,但它们常常会产生误导性的结果,使用非IDE调试器(通常是必需的)意味着记住快捷键,这会分散手头的工作。

我发现最糟糕的调试经验是命令行GDB。

当然,成为每天使用的工具的专家很重要-但是调试并不是每天都要做的事情。如果您经常使用调试器,则可以学习许多命令和/或键盘快捷键,这对我来说似乎有点危险。

但是,当我在Visual Studio 7中工作时,很明显,调试可能非常实用和有效。如果可以在Visual Studio(包括精装版)中进行调试,则调试很容易。毫无疑问,如果您找不到正确的GUI / IDE前端,GDB也是既简单又有效的,尽管我还没有进行搜索。

对于使用gcov进行覆盖率分析的单元测试,还有一些要说的。对库行为的信心越强,调试所需的深度就越小-首先,调试器的使用就越少。而且编写单元测试相当合理,这是您大多数日子应该做的事情。

出乎意料的重要工具= cmake,这是个构建工具,它使我可以轻松地在GCC和VC ++的构建之间进行切换。因此,我可以使用GCC进行单元测试和基于gcov的覆盖,但是可以轻松切换到VC ++以使用调试器。


在多线程应用程序中,即使不是很危险,调试器也可能毫无用处,但是我喜欢您的带有红色标志的评论。
Pemdas 2011年

@Pemdas-尽管多线程显然对调试器不友好,但到目前为止,我还没有遇到过严重的问题。即使这样,我认为正确的工具在原则上可能比调试代码更好。静态分析工具可以发现竞争状况,死锁,两个线程可以同时争用同一内存/资源的状况,等等等等。尽管我确实知道那里有一些聪明的工具,但我不知道这些路线上有什么可用。例如,克莱(Klee)-我听不懂,但基本描述听起来很令人印象深刻。
Steve314 2011年

“从原则上讲,我认为正确的工具可能比调试代码更好的解决方案”。拥有执行某些分析的工具可能会很好,但是我担心开发人员(尤其是新开发人员)将开始过于依赖这些工具,例如需要使用计算器才能确定100%的15%的人。
Pemdas 2011年

过于依赖我还没有研究过的工具似乎不太可能。在您的计算器示例中,是的,但是我仍然会使用OpenOffice Calc,而不是编写自己的简单电子表格。有时需要调试代码(即使使用调试器,例如您自己的异常条件创建案例),但是如果超过某个点,则现有工具将获胜。当从115中减去15%时,我也将使用该计算器-许多人会给出明显的答案(100)是错误的。在多线程中,显然正确的答案有时是错误的,因此臭名昭著。
Steve314 2011年

1

我的看法:调试代码用来杀死所涉及代码中的错误,我通常将其完全删除。我通常只是简单地注释掉用来杀死外部力量导致的错误的调试代码。


-1

如果错误来自单元测试或内部错误,则可以将调试代码完全删除。但是,如果错误来自生产环境,则调试代码最好放在compile标签内。将其放在编译标签中将有助于其他开发人员了解此代码仅用于调试目的。


-1

使用TDD,因此您的测试代码总会有一个甚至可以维护的地方。


这如何回答所提问题?
蚊蚋

因为TDD会导致您“调试”或测试不需要删除的代码。
dukeofgaming

我不后悔。那个怎么样?
蚊蚋
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.