【问题标题】:How to consistently organize code for debugging?如何一致地组织调试代码?
【发布时间】:2008-11-23 21:44:48
【问题描述】:

在需要调试的大型项目(如每个项目)中工作时,您会意识到在 IDE 的内置调试器之前人们对“printf”的喜爱程度。我的意思是

  • 有时您需要将变量值呈现到屏幕上(专门用于交互式调试)。
  • 有时将它们记录在文件中
  • 有时您必须将可见性(将它们设为公开)更改为另一个类才能访问它(例如记录器或渲染器)。
  • 有时您需要将以前的值保存在成员中,以便在调试期间与新值进行对比
  • ...

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

你是怎么解决这个问题的?

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

如果您被要求编写一份调试编码文档供项目中的所有其他人遵循,您会采用哪些设计技术、模式和标准?

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

谢谢。

【问题讨论】:

    标签: debugging logging oop coding-style


    【解决方案1】:

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

    Loggin OTOH 在执行处理例程等中占有一席之地。此外,一些常用 API 中的一些放置良好的日志记录语句也有助于调试。

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

    【讨论】:

      【解决方案2】:

      我的投票是你所说的友好的跟踪器类。此类将保持所有这些集中,甚至可能允许您动态更改调试/日志记录策略。

      我会避免使用宏之类的东西,因为那是编译器技巧,而不是真正的 OO。通过抽象调试/日志记录的概念,您有机会用它做很多事情,包括在需要时使其成为空操作。

      【讨论】:

        【解决方案3】:

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

        【讨论】:

          【解决方案4】:

          我认为避免直接使用 System.outs / printfs 而是使用(甚至是自定义)日志记录类尤为重要。这至少为您提供了所有日志记录的集中终止开关(减去 Java 中的调用成本)。

          让该日志类具有 info/warn/error/caveat 等也很有用。

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

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

          【讨论】:

            【解决方案5】:

            在 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
            

            是的,它确实会变得一团糟,是的,我希望有更好的方法。

            【讨论】:

              【解决方案6】:

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

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

              如果您的语言不支持通过其跟踪结构对消息进行分类,则应该将其添加到跟踪代码中。能够识别不同级别的重要性和/或功能领域的大意是一个很好的开始。

              【讨论】:

                【解决方案7】:

                只需避免通过修改代码来检测代码。学习使用调试器。使日志记录和错误处理变得容易。看看Aspect Oriented Programming

                【讨论】:

                  【解决方案8】:

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

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

                  • 广泛使用已检查 (DBG) 构建断言并且对 DBG 构建进行大量测试。
                  • 在我们所说的“fre”或“retail”构建中使用 ETW。

                  检查过的构建(大多数人称之为调试构建)对我们也很有帮助。我们在 'fre' 和 'chk' 版本上运行所有测试(同样在 x86 和 AMD64 上,所有服务器的东西也在 Itanium 上运行......)。有些人甚至在已检查的版本上自行托管(dogfood)。这有两件事

                  1. 发现了许多其他情况下无法发现的错误。
                  2. 快速消除嘈杂或不必要的断言。

                  在 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。即使是最好的代码也可以从良好实现的日志记录中受益。良好实施的静态运行时日志记录可以直接发现许多问题 - 没有它,您对组件中发生的事情的可见性为零。您可以查看输入、输出和猜测——仅此而已。

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

                  当然,不同的软件产品或组件会有不同的需求。有些事情可能需要很少的工具。但是,一个广泛分散或关键的组件可以极大地受益于精心设计的仪器。

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

                  您可以想象 - 在这种情况下连接调试器会造成破坏。

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

                  这些只是简单的示例 - 可以通过多种不同方式处理日志记录。我在这里的主要建议是考虑日志记录如何能够帮助您在开发时、测试时以及部署后发现、调试和修复组件中的问题。

                  【讨论】:

                    【解决方案9】:

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

                    【讨论】:

                      【解决方案10】:

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

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

                      【讨论】:

                        猜你喜欢
                        • 2011-08-08
                        • 1970-01-01
                        • 2019-03-16
                        • 2022-10-25
                        • 1970-01-01
                        • 1970-01-01
                        • 2023-03-07
                        • 1970-01-01
                        • 2018-10-12
                        相关资源
                        最近更新 更多