如何一致地组织代码进行调试?

时间:2008-11-23 21:44:49

标签: debugging logging oop coding-style

在需要调试的大型项目(如每个项目)中工作时,您会发现在IDE的内置调试器之前有多少人喜欢“printf”。我的意思是

  • 有时您需要将变量值呈现给屏幕(特别是用于交互式调试)。
  • 有时将其记录在文件中
  • 有时您必须将可见性(将其公开)更改为另一个类才能访问它(例如记录器或渲染器)。
  • 有些时候你需要在成员中保存以前的值,只是为了与调试期间的新对比
  • ...

当一个项目变得庞大而且很多人都在使用它时,所有这些特定于调试的代码都会变得混乱而难以与普通代码区分开来。对于那些必须更新/更改别人的代码或准备发布的人来说,这可能是疯狂的。

你是如何解决这个问题的?

拥有命名标准总是好的,我想调试编码标准应该非常有用(比如使用_DBG sufix标记每个调试变量)。但我也猜测命名是不够的。也许可以将它集中到友好的跟踪器类中,或者创建一个强大的宏基础,以便将其全部删除。我不知道。

如果要求您为项目中的所有其他人编写调试编码文档,您会接受哪些设计技巧,模式和标准?

我不是在谈论工具,库或特定于IDE的命令,而是在讨论OO设计决策。

感谢。

10 个答案:

答案 0 :(得分:1)

不要提交调试代码,只需调试工具。

Loggin OTOH在执行处理程序等方面具有天然的地位。此外,一些常用的API中的一些良好的日志记录可以很好地进行调试。

像一个日志语句一样,记录从系统执行的所有SQL。

答案 1 :(得分:0)

我的投票将与您所描述的友好跟踪课程相符。这个类将保持所有这些集中化,甚至可能允许您动态更改调试/日志记录策略。

我会避免像Macros这样的东西,因为那是一个编译技巧,而不是真正的OO。通过抽象调试/日志记录的概念,您有机会使用它做很多事情,包括在需要时将其设置为无操作。

答案 2 :(得分:0)

记录还是调试?我相信,经过精心设计和经过适当单元测试的应用程序不需要永久性地进行调试。另一方面,登录在查找错误和审计程序操作方面非常有用。我可以在logging.apache.org指出您可以使用的具体实现,或者用于合理设计日志记录基础结构的模板,而不是涵盖您可以在其他地方获得的大量信息。

答案 3 :(得分:0)

我认为避免直接使用System.outs / printfs并使用(甚至是自定义)日志记录类尤为重要。这至少为您提供了一个针对所有记录的集中式kill-switch(减去Java中的调用成本)。

让日志类具有info / warn / error / caveat等

也很有用

我会小心错误级别,用户ID,元数据等,因为人们并不总是添加它们。

此外,我见过的最常见问题之一是人们在调试某些内容时会在代码中放入临时printfs,然后忘记他们放置它们的位置。我使用的工具跟踪我所做的一切,因此我可以快速识别自抽象检查点以来的所有最近编辑并删除它们。但是,在大多数情况下,您可能希望对可以检入源控件的调试代码提出特殊规则。

答案 4 :(得分:0)

在VB6中你有

Debug.Print

将输出发送到IDE中的窗口。这对小型项目来说是可以承受的。 VB6也有

#If <some var set in the project properties>
'debugging code
#End If

我有一个日志记录类,我在顶部用

声明
Dim Trc as Std.Traces

并在各个地方使用(通常在#If / #End If块内)

Trc.Tracing = True
Trc.Tracefile = "c:\temp\app.log"
Trc.Trace 'with no argument stores date stamp
Trc.Trace "Var=" & var

是的它确实变得混乱,是的,我希望有更好的方法。

答案 5 :(得分:0)

我们经常开始使用我们编写跟踪消息的静态类。它是非常基本的,仍然需要执行方法的调用,但它符合我们的目的。

在.NET世界中,已经存在大量可用的内置跟踪信息,因此我们无需担心调用哪些方法或执行时间。这些更适用于执行代码时发生的特定事件。

如果您的语言不支持,通过其跟踪结构,消息分类,它应该是您添加到跟踪代码中的内容。能够识别不同重要性和/或功能区域的效果是一个很好的开始。

答案 6 :(得分:0)

请避免通过修改代码来检测代码。学习使用调试器。简化日志记录和错误处理。看看Aspect Oriented Programming

答案 7 :(得分:0)

调试/记录代码确实是侵入性的。在我们的C ++项目中,我们将常见的调试/日志代码包装在宏中 - 非常类似于断言。我经常发现日志记录在较低级别的组件中最有用,因此它不必到处都是。

在其他答案中有很多人同意和不同意:)拥有调试/日志记录代码可以成为解决问题的非常有价值的工具。在Windows中,有许多技术 - 两个主要的技术是:

  • 广泛使用checked(DBG)构建断言对DBG构建进行大量测试。
  • 在我们称之为“fre”或“零售”的版本中使用ETW。

Checked构建(大多数人称之为DEBUG构建)对我们来说也非常有帮助。我们在'fre'和'chk'构建上运行我们所有的测试(在x86和AMD64上,所有的serever东西也在Itanium上运行......)。有些人甚至在托管版本上自我托管(dogfood)。这样做有两件事

  1. 找到许多其他方法无法找到的错误。
  2. 快速消除嘈杂或不真实的断言。
  3. 在Windows中,我们广泛使用Event Tracing for Windows(ETW)。 ETW是一种有效的静态日志记录机制。 NT内核和许多组件都配备齐全。 ETW有很多优点:

    • 可以在运行时动态启用/禁用任何ETW事件提供程序 - 无需重新启动或重新启动进程。大多数ETW提供商提供对个别事件或事件组的精细控制。
    • 来自任何提供程序(最重要的是内核)的事件可以合并为单个跟踪,以便所有事件都可以关联。
    • 合并后的跟踪可以在框中复制并完全处理 - 带符号。
    • NT内核样本pofile中断可以生成一个ETW事件 - 这是一个非常轻量级的样本分析器,可以随时使用
    • 在Vista和Windows Server 2008上,记录事件是无锁且完全支持多核的 - 每个处理器上的线程可以独立记录事件,而不需要在它们之间进行同步。

    这对我们来说非常有价值,并且可以用于您的Windows代码 - 任何组件都可以使用ETW - 包括用户模式,驱动程序和其他内核组件。

    我们经常做的一件事是写一个流式ETW消费者。我没有将printfs放在代码中,而是将ETW事件放在有趣的地方。当我的组件运行时,我可以随时运行我的ETW观察器 - 观察者接收事件并显示它们,对它们进行控制,或者与它们做其他有趣的事情。

    我非常恭敬地不同意tvanfosson。即使是最好的代码也可以从良好实现的日志记非常好的静态运行时日志记录可以直接找到许多问题 - 没有它,你对组件中发生的事情没有任何可视性。您可以查看输入,输出和猜测 - 它是关于它的。

    他们在这里的关键是“很好地表达”这个词。仪器必须在正确的位置。像其他任何事情一样,这需要一些思考和计划。如果它不在有用/有用的地方,那么它将无法帮助您在开发,测试或部署方案中发现问题。你也可能有太多的仪表导致打开问题 - 甚至关闭!

    当然,不同的软件产品或组件会有不同的需求。有些事情可能需要很少的工具。但是,广泛解复或关键的组件可以从weill egenered instrumeantion中受益匪浅。

    这是你的一个场景(请注意,这很可能不适用于你...... :))。假设您在公司的每个桌面上都部署了一个业务线应用程序 - 数百或数千个用户。当有人患有pbolem时你会怎么做?你哟停在他们的办公室和连接调试器?如果是这样,你怎么知道他们有什么版本?你在哪里得到正确的符号?你如何在他们的系统上获得debuger?如果每隔几小时或几天只发生一次怎么办?您是否要让系统在调试器连接的情况下运行?

    你可以想象 - 在这种情况下连接调试器是破坏性的。

    如果您的组件配有ETW,那么您可以要求您的用户只需打开跟踪;继续做他/她的工作;然后在问题发生时点击“WTF”按钮。更好的是:您的应用程序可能能够自我记录 - 在运行时检测问题并打开自动魔术记录。它甚至可以在出现问题时向您发送ETW文件。

    这些只是简单的例子 - 日志记录可以通过许多不同的方式处理。我在这里的重点推荐是考虑如何在开发时,测试时和部署后帮助您查找,调试和修复组件中的问题。

答案 8 :(得分:0)

在我参与的每个项目中,我被同样的问题所困扰,所以现在我有这个习惯,从一开始就涉及广泛使用日志库(无论语言/平台提供什么)。任何Log4X port都适合我。

答案 9 :(得分:0)

为自己构建一些适当的调试工具非常有价值。例如,在3D环境中,您可以选择显示八叉树,或渲染计划的AI路径,或绘制通常不可见的航点。您可能还需要一些屏幕显示来帮助进行分析:当前帧速率,屏幕上多边形的数量,纹理内存使用情况等等。

虽然这需要花费一些时间和精力,但从长远来看,它可以为您节省大量时间和挫折。