一个独立开发者为什么应该使用测试驱动开发(TDD)?

36

我是一名有丰富经验的合同程序员。通常情况下,客户会雇用我单独完成一个软件项目,几乎每次都是从头开始。这意味着几乎每次都需要重新开始。我可以引用我开发的库以便快速启动项目,但这通常是可选的。(并取决于合同中获得正确的知识产权条款)许多时候我可以指定或设计硬件平台...所以这里我们谈论的是真正的自由。

我认为在某些代码方面构建自动测试非常有用:具有复杂功能的库、核心功能被高频使用等等。基本上,随着代码价值通过大量使用逐渐提高,我可以看到自动测试该代码将变得越来越有价值,以便确保不会出现错误。

然而,在我的情况下,我很难理性地证明除此之外还有更多的必要。如果事实证明某些东西有用,我会采纳它们,但我不会盲目跟从任何事物。

我发现我在“维护”中做的许多事情实际上都是小型设计更改。在这种情况下,测试并不能节省我的时间,反而会使我更加繁琐。高度迭代的设计方法对我非常有效,我无法看到更广泛测试可以节省多少时间。

对于个人爱好项目,更难以证明...通常只是周末或一个月左右的时间制作。边缘情况下的错误很少有影响,一切都是关于玩耍。

阅读像这样的问题,其中票数最高的回答似乎表明在那位发布者的经验/意见中,如果你没有超过5个人(即使假定具备某种TDD水平),TDD实际上会浪费时间。但是,这似乎涵盖了初始开发时间,而不是维护阶段。TDD在整个项目生命周期中的效果尚不清楚。

我认为TDD(测试驱动开发)对于改善整个行业产品质量的有益目标来说是一个不错的步骤。但单纯的理想主义已经不能激励我了。

我确实认为在大型团队或包含至少一个不可靠程序员的任何规模的团队中,采用TDD都是一个不错的方法。这不是我的问题。

那么一个有着良好记录的独立开发者为什么要采用TDD呢?

我很乐意听到有关TDD的任何度量(无论是否正式),重点放在独立开发者或非常小的团队上。

如果没有这样的数据,你的个人经验的轶事也是不错的选择。请避免在没有经验支持的情况下陈述观点。让我们不要把这变成一场意识形态战争。同时跳过更好的就业选择的争论,这只是一个效率问题。

21个回答

20

我不会盲目地追随任何东西。

这是正确的态度。我一直在使用TDD,但我并不像有些人那样严格遵守。

在我看来,支持TDD的最好论点是当您最终进入重构和维护阶段时,您可以运行一组测试。如果这是您使用TDD的唯一原因,那么您可以随时编写测试,而不是盲目地遵循方法论。

我使用TDD的另一个原因是编写测试让我从前期开始思考我的API。在写代码之前,我被迫考虑如何使用类。将我的头脑置于项目的高层次上对我很有帮助。还有其他方法可以做到这一点,如果您已经发现了其他方法(有很多),则我认为应继续使用适合您的方法。


5
采用测试驱动开发(TDD)还可以使您的代码更易于测试和模块化。我发现,当我转向采用TDD时,我的代码总体上变得更良好地构建,仅仅因为我需要考虑如何测试一个代码片段,而不只是考虑它如何解决所需完成的任务。 - ctacke
1
我倾向于像疯子一样进行重构,而且我的库相当大...所以这可能是我最好的理由。我将尝试为几个库编写测试,并看看效果如何。 - darron

15

我认为在独自编写代码时,这种技术更加有用。因为没有人可以和你交流想法,也没有人可以进行同行评审,所以你需要一些保证你的代码质量的措施。测试驱动开发(TDD)/行为驱动开发(BDD)将为您提供此保证。不过,TDD 有点具有争议性,其他人可能完全不同意我的观点。

编辑:我想补充的是,如果做得好,你实际上可以同时编写软件规范和测试。这是 BDD 的一个很好的副作用。如果你能独立地高效地编写出坚实的代码与规范,那么你会像一个超级开发者一样表现出色。


这基本上是我的感觉。它有点帮助你确信自己不是个彻头彻尾的白痴...虽然没有什么能保证...;-) - Max Schmeling

11

好的,轮到我了……对于非试验性/实验性/原型代码,我会使用测试驱动开发(TDD),因为:

  • 三思而后行:这让我在开始编写代码之前考虑我想做什么。我想要完成什么任务?“如果我假设已经有这个部分,那么我期望它如何工作?”鼓励对象接口设计。
  • 更容易修改:我可以信心十足地进行修改。“当我更改了第5步时,我没有破坏第1-10步的内容。”回归测试是即时的。
  • 更好的设计浮现出来:我发现不必进行设计活动就能浮现出更好的设计。测试优先+重构导致耦合松散、类和方法最小化,没有过度工程化,没有YAGNI代码。这些类具有更好的公共接口、小的方法,更易读。这是一种禅境体验……你只有“悟”之后才能意识到自己拥有了它。
  • 调试器不再是我的拐杖:我知道我的程序做什么,无需花费数小时逐步调试自己的代码。如今,如果我花费超过10分钟与调试器一起工作,内心就会感到不安。
  • 帮助我准时回家:自从使用TDD以来,我注意到我的代码中错误的数量显著减少,即使断言只是一个控制台跟踪而不是像xUnit类型AT(注:指自动化测试)那样的断言。
  • 提高生产力/流程:它有助于我确定下一个离散的微小步骤,使我朝着完成目标不断前进……让雪球滚动。TDD帮助我更快地进入状态(或者XP人称之为流),我能够在单位时间内完成更多质量的工作。红-绿-重构循环变成了一种永动机。
  • 我可以轻松证明我的代码是有效的
  • 熟能生巧 我发现自己在掌握更多TDD经验后,能更快地学习和发现问题。也许这是一种不和谐感觉,但我感觉TDD使我成为了一个更好的程序员,即使我不总是先写测试。发现重构机会已经变得很自然...
  • 如果我想到更多,我会进行更新...这是我在沉思的最后两分钟里想出来的。


    6

    3

    我在TDD方面最好的经验是与pyftpdlib项目有关。大部分开发工作由原作者完成,我做了一些小贡献,但基本上是一个单人项目。该项目的测试套件非常全面,测试FTPd库的所有主要功能。在检查更改或发布新版本之前,所有测试都会进行检查,当添加新功能时,测试套件也总是会更新。

    由于这种方法,这是我曾经参与过的唯一一个没有在新版本发布后出现严重错误、检入更改导致主要功能崩溃等问题的项目。代码非常稳定,我一直对项目的生命周期中开放的缺陷报告数量印象深刻。我(和原作者)将这一成功归因于全面的测试套件以及随时测试每个主要代码路径的能力。

    从逻辑角度来看,你编写的任何代码都必须经过测试,如果没有TDD,那么您将手动进行测试。与pyftpdlib相反,根据缺陷数量和主要问题频率,最糟糕的代码是/曾是仅由开发人员和QA手动测试新功能的代码。由于时间紧迫或遗漏而无法进行测试。老的代码路径被遗忘,即使是最老的稳定功能也会出现故障,主要版本发布后重要功能无法正常工作。手动测试对于验证和一些随机化测试至关重要,但根据我的经验,我认为必须同时具备手动测试和精心构建的单元测试框架。两种方法之间的覆盖范围差距更小,您的问题可能性只能减少。


    抱歉让一个10年前的帖子复活,但最近的一个回答让我很生气,所以我想在这里加上我的想法。我确实喜欢这个答案,但我想举个例子。TDD并不一定会使像FTP守护进程这样的安全关键项目更加安全。你可以通过测试来定义你想要完成的目标,并实现所有需要完成这些测试的东西... 但你必须知道要测试缓冲区溢出或者可能发生的一些高级侧信道攻击,以避免这些问题。 - darron
    在安全关键的模块中,TDD 很可能无法帮助大多数可能出错的事情。TDD 确定能做到的是,它会给一些软件开发人员一种错误的印象,即他们没有任何问题。如果理性使用,了解它能做什么和不能做什么,我认为它在特定情况下(而不是大多数情况下)有所帮助。 - darron

    2
    不管你是唯一的开发者还是团队中的一员,都需要从应用程序的角度考虑问题。所有应用程序都需要正常运行、进行维护和尽可能减少错误。当然,在某些情况下,TDD方法可能不适合你,比如截止日期迫近,没有时间进行单元测试。无论如何,TDD不依赖于个人或团队环境,而是取决于整个应用程序。

    2
    我虽然经验不多,但见过鉴别度极高的测试方法。
    有一份工作中,没有自动化测试,“测试”只是随意在应用程序里试用各种想到的东西,以查看是否会出错。可以想象,烂代码很容易就能进入我们的生产服务器。
    而在我现在的工作中,有很多自动化测试和完整的 CI 系统。现在,当代码被损坏时,问题会立刻显现。并且,随着我的工作,测试真正记录了我的代码中哪些特性正在运行以及哪些还没有。这让我非常自信,可以添加新特性,同时知道如果我破坏了现有特性,它不会被忽视。
    因此,对我来说,这并不取决于团队的规模,而取决于应用程序的大小。您能追踪应用程序的每个部分吗?每个需求?你需要运行的每个测试都是什么?如果没有测试来证明它,那么说应用程序“有效”是什么意思呢?
    以上是我的 $0.02。

    2
    测试让你有信心进行重构,确保不会破坏系统。首先编写测试使得测试定义了系统的工作行为。任何未被测试定义的行为都是副产品,因此在重构时可以更改。编写测试还可以驱动良好的设计方向。为了支持可测试性,您需要解耦类、使用接口并遵循良好的模式(例如控制反转),以使代码易于测试。如果您事后编写测试,则无法确定是否已覆盖了系统中预期的所有行为。您还会发现,由于设计可能没有考虑测试,某些事情很难测试,并且倾向于省略测试或跳过测试。
    我通常独立工作,并且大多数情况下都使用TDD——我不使用TDD的情况只是我没有遵循自己的实践或尚未找到适合我的方法来进行TDD,例如涉及Web界面的情况。

    2
    TDD 让我更清晰地在脑海中定义问题。这有助于我专注于实现所需的功能,而不是其他任何东西。它还帮助我创建更好的 API,因为我在编写代码本身之前先编写了一个“客户端”。我还可以进行重构,而不必担心破坏任何东西。

    1
    TDD并不是关于测试,而是关于编写代码。因此,即使对于单个开发人员,它也提供了许多好处。对于许多开发人员来说,这是一种思维转变,可以编写更健壮的代码。例如,在没有TDD的情况下编写代码后,你有多少次会想“现在这段代码可能会失败?”对于许多开发人员来说,这个问题的答案是没有。对于TDD从业者来说,它会将思维方式转变为执行诸如在执行某些操作之前检查对象或字符串是否为空之类的操作,因为你正在编写专门用于此目的(破坏代码)的测试。
    另一个主要原因是变化。每当你与客户打交道时,他们似乎永远无法做出决定。唯一的常数就是变化。TDD作为“安全网”有助于找到所有其他可能会出错的地方。即使在小项目上,这也可以避免你在调试器中浪费宝贵的时间。
    我可以继续说下去,但我认为说TDD更多的是关于编写代码而不是其他任何事情,应该足以证明它作为单个开发人员使用的合理性。

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接