在发布产品中打击调试代码

时间:2011-02-23 17:35:19

标签: debugging release startup

我在一个非常小的初创公司开发工厂(3位开发人员)工作,我经常被从我正在努力修复任务关键错误或实施“绝对关键”软件功能 - 我的错误列表重新几乎每天都优先考虑,我很少知道从现在开始几个小时内什么是“重要的”。

正因为如此,我发现我越来越警惕添加可能被我们的QA部门取消检查的代码(读:人)。

当我实现一个新函数时,不知道我是否会随时调用它,我有时会尝试在顶部编写一个return语句,以确保代码永远不会在发布版本上执行

语句的问题如:

public void NewFunction()
{
    return; // Put break point so that I can use the debugger to step to meat:

    meat:
    // ... More code
}

即使在调试模式下,Visual Studio也足够聪明,知道肉:永远不会执行,所以你不能使用“set next statement”命令来实现:在#if!DEBUG等编译器指令中包装代码也是如此。

相反,我写的是:

public void NewFunction()
{
    if("a"[0]=='a')
        return; // put break point here

    meat:
    // ... More code
}

因此,如果此代码意外地进入发布版本,则不会造成任何损害,但由于直到运行时才对其进行评估,因此我可以使用调试器来处理问题:没有问题。

我真的不喜欢让事情未完成,但在关键时刻,我们往往没有时间搁置变更集或正确处理事情。目前不需要通过API访问上述功能概述等未完成的功能,因此我不认为将它们留在软件中有任何直接的危害(但是在线下,它们可能导致几个wtf时刻)维护 - 就像“wtf是这个函数在这里没有做任何事情?”因为我不记得我从现在起6个月后做了什么。)

考虑到我(遗憾地)半定期地做这样的事情,这个问题是否有标准做法?作为一个更大的问题,是否有一些实践有助于打击软件版本中的调试代码?

4 个答案:

答案 0 :(得分:2)

有些事情对我很突出:

  • “我真的不想留下未完成的东西,”
  • “我有时会尝试在顶部编写一个return语句,以确保代码永远不会在发布版本上执行。”
  • “以便如果此代码意外滑入发行版”

我会查看一些敏捷方法和实践。它旨在考虑发布中的快速移动目标。

您应该执行以下操作:

  • 确保所有新代码都有单元测试备份其功能。
  • 为您更改的代码编写单元测试,以确保您更改的内容不会破坏现有功能。
  • 使用Cruise Control或类似产品执行连续构建。这个以及测试会在出现故障时立即通知您。
  • 按功能/任务开始分支,以便不会“意外”地插入代码。在主线上处理所有代码,即使从一个优先级任务移动到另一个优先级任务也会导致这些单据。
  • 产品应始终有效。在给定产品中已完成的X个特征的任何时间点,它都应该有效。不要半实现一个功能。将其分解为可以说工作的较小功能和任务。如果客户永远不会使用它们并不重要。这可以防止其他开发人员使用的未完成的功能并中断。
  • 修复损坏的窗户。不要让非常糟糕的设计或错误继续存在。它只会在以后加剧这个问题。

通过坚持任务/功能分支,您不必像在问题中那样创建将要签入的中间代码。这不应该发生。如果切换将在另一个分支中的任务。这样做可以使您的流程最小化,并且您的分支毫不费力。那么这些事情将成为第二天性。

答案 1 :(得分:1)

分布式版本控制系统使分支和合并成为一种快照。使用像Mercurial这样的工具(我的个人偏好),您甚至不需要远程存储库 - 您只需在本地系统上就地创建存储库,然后在本地驱动器上的其他地方克隆存储库。因此,您可以轻松保留代码的“发布”版本,同时快速将代码更改迁移到“调试”分支和从“调试”分支迁移。

答案 2 :(得分:1)

假设您的代码在C#中,您可以使用[Conditional]属性在Release配置中排除某些方法调用:

[Conditional("DEBUG")]
public void NewFunction (object something)
{
    // do something
}

这相当于包装方法本身及其对#if DEBUG / #endif子句的所有调用。

当未定义NewFunction符号时,编译器将排除对DEBUG的任何调用。控制它的最简单方法是通过Visual Studio中的解决方案和项目配置。在Debug配置中,定义了DEBUG符号,而不是Relase configuraiton。

请注意,只能排除void次调用,因为代码不依赖于这些方法的返回值。

然而,这被设计用于跟踪,记录等。我不太明白你打算如何保留一些未完成的方法但仍然在调试版本中使用它们。如果他们不工作,或者如果他们这样做,为什么不将他们包括在发布中,这是什么意思呢?

答案 3 :(得分:0)

我处于同样的境地。我有时会把#IF DEBUG放到新函数的调用上。或#IF DEBUG围绕函数的全部内容。

我做的另一件事是将TODO:单元测试评论放在函数上,以便在发布时我可以搜索那些并知道是否存在问题。