35

我是一名经验丰富的合同程序员。我习惯于被客户雇佣,自己去做一个或另一种形式的软件项目,通常是白手起家。这意味着几乎每次都是白纸黑字。我可以引入我开发的库来快速入门,但它们始终是可选的。(并且取决于在合同中获得正确的 IP 条款)很多时候我可以指定甚至设计硬件平台......所以我们在这里谈论的是严肃的自由。

我可以看到为某些代码构建自动化测试的用途:具有不仅仅是琐碎功能的库、具有大量引用的核心功能等。基本上,随着一段代码的价值通过大量使用而上升,我可以看到它自动测试该代码会越来越有价值,这样我就知道我不会破坏它。

然而,在我的情况下,我发现很难合理化除此之外的任何事情。我会采用被证明有用的东西,但我不会盲目地遵循任何东西。

我发现我在“维护”中所做的许多事情实际上都是很小的设计更改。在这种情况下,测试不会为我节省任何东西,现在它们也必须改变。高度迭代、存根优先的设计方法对我来说非常有效。我看不到通过更广泛的测试实际上为自己节省了那么多时间。

爱好项目更难证明......它们通常是从周末到一个月的任何东西。边缘情况的错误很少有关系,这都是关于玩一些东西。

阅读诸如this one之类的问题,投票最多的回复似乎是说,在该发布者的经验/意见中,如果您的人数少于5人,TDD实际上会浪费时间(即使假设具有一定水平的TDD能力/经验)。但是,这似乎涵盖了初始开发时间,而不是维护时间。目前尚不清楚 TDD 如何在项目的整个生命周期中叠加。

我认为 TDD 可能是朝着提高整个行业产品质量这一有价值目标迈出的重要一步。不过,理想主义本身不再能有效地激励我。

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

为什么拥有良好记录的唯一开发人员会采用 TDD?

我很想听听关于 TDD 的任何类型的指标(正式或非正式)......专注于单独的开发人员或非常小的团队。

如果做不到这一点,你个人经历的轶事也会很好。:)

请避免在没有经验的情况下发表意见来支持它。让我们不要把这变成一场意识形态战争。还有跳过更多就业选择的论点。 这只是一个效率问题。

4

21 回答 21

19

我不会盲目地追随任何事情。

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

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

我使用 TDD 的另一个原因是编写测试让我提前考虑我的 API。在编写课程之前,我不得不考虑如何使用课程。让我的头脑进入这个高层次的项目对我有用。还有其他方法可以做到这一点,如果你找到了其他方法(有很多)来做同样的事情,那么我会说继续做对你有用的事情。

于 2008-10-01T14:07:05.207 回答
14

我发现它在单飞时更有用。周围没有人可以提出想法,也没有人可以进行同行评审,你需要一些保证你的代码是可靠的。TDD/BDD 将为您提供这种保证。不过,TDD 有点相反。其他人可能完全不同意我所说的。

编辑:我可以补充一点,如果做得好,您实际上可以在编写测试的同时为您的软件生成规范。这是 BDD 的一个很大的副作用。如果您自己编写可靠的代码和规范,您可以让自己看起来像超级开发人员。

于 2008-10-01T14:00:21.650 回答
12

好吧,轮到我了……我什至会自己做 TDD(对于非尖峰/实验/原型代码),因为

  • 三思而后行:迫使我在开始编写代码之前思考我想要完成的工作。我想在这里完成什么......“如果我假设我已经拥有了这件作品......我希望它如何工作?” 鼓励对象的界面设计。
  • 更容易更改:我可以放心地进行修改。“当我更改第 5 步时,我没有在第 1-10 步中破坏任何东西。” 回归测试是即时的
  • 更好的设计出现:我发现更好的设计正在出现,而无需我在设计活动上投入精力。测试优先 + 重构导致松散耦合、使用最少方法的最少类.. 没有过度工程.. 没有 YAGNI 代码。这些类具有更好的公共接口、小方法并且更具可读性。这是一种禅宗的事情......你只有在“得到它”时才会注意到你得到了它。
  • 调试器不再是我的拐杖:我知道我的程序做了什么......而无需花费数小时逐步完成我自己的代码。如今,如果我在调试器上花费超过 10 分钟.. 心理警报开始响起。
  • 帮助我按时回家我注意到自 TDD 以来我的代码中的错误数量显着减少.. 即使断言类似于控制台跟踪而不是 xUnit 类型的 AT。
  • 生产力/流程:它帮助我确定下一个离散的婴儿步骤,它将带我完成……让雪球滚滚。TDD 帮助我更快地进入节奏(或 XPers 所说的流程)。我在单位时间内完成了比以前更多的高质量工作。红绿重构循环变成了……一种永动机。
  • 我可以证明我的代码只需按一下按钮即可工作
  • 熟能生巧,我发现自己学习和发现龙的速度更快……有了更多的 TDD 时间。也许是不和谐......但我觉得即使我不先去测试,TDD 也让我成为了一个更好的程序员。发现重构机会已成为第二天性……

如果我想到任何更多,我会更新..这是我在最后 2 分钟的反思中想到的。

于 2008-11-12T17:03:56.940 回答
6

我也是一名合同程序员。这是我喜欢单元测试的 12 个原因

于 2008-11-12T16:35:34.143 回答
3

我对 TDD 的最佳体验集中在pyftpdlib项目上。大部分的开发都是由原作者完成的,我也做了一些小的贡献,但它本质上是一个单独的项目。该项目的测试套件非常全面,并测试了 FTPd 库的所有主要功能。在签入更改或发布版本之前,会检查所有测试,当添加新功能时,测试套件也会始终更新。

由于采用了这种方法,这是我从事过的唯一一个项目,在新版本发布后没有出现惊人的错误,签入的更改破坏了主要功能等。代码非常可靠,我在项目的生命周期中,很少有人打开错误报告给他留下了深刻的印象。我(和原作者)将这一成功很大程度上归功于全面的测试套件和随意测试每个主要代码路径的能力。

从逻辑的角度来看,您编写的任何代码都必须经过测试,如果没有 TDD,那么您将自己手动测试它。在 pyftpdlib 的另一面,按错误数量和主要问题频率计算的最差代码是仅由开发人员和 QA 手动测试新功能的代码。由于时间紧迫或落入裂缝,事情没有得到测试。旧的代码路径被遗忘,即使是最古老的稳定功能最终也会崩溃,主要版本最终会导致重要功能无法正常工作。等等。手动测试对于验证和测试的一些随机化至关重要,但根据我的经验,我会说同时拥有手动测试和精心构建的单元测试框架是必不可少的。在这两种方法之间,覆盖范围的差距更小,

于 2008-10-01T14:27:18.217 回答
2

您是否是唯一的开发人员并不重要。您必须从应用程序的角度考虑它。所有应用程序都需要正常工作,所有应用程序都需要维护,所有应用程序都需要减少错误。当然,在某些情况下,TDD 方法可能不适合您。这是截止日期很快临近并且没有时间执行单元测试的时候。

无论如何,TDD 不依赖于单人或团队环境。这取决于整个应用程序。

于 2008-10-01T14:01:19.387 回答
2

我没有大量的经验,但我有过看到鲜明对比的测试方法的经验。

在一项工作中,没有自动化测试。“测试”包括在应用程序中四处寻找,尝试任何出现在你脑海中的东西,看看它是否坏了。不用说,完全损坏的代码很容易到达我们的生产服务器。

在我目前的工作中,有很多自动化测试和完整的 CI 系统。现在,当代码被破坏时,它立即显而易见。不仅如此,当我工作时,测试确实记录了我的代码中哪些功能正在运行,哪些还没有。它让我对能够添加新功能充满信心,因为我知道如果我破坏现有功能,它不会被忽视。

所以,对我来说,这不仅仅取决于团队的规模,而是取决于应用程序的规模。您可以跟踪应用程序的每个部分吗?每个要求?您需要运行每个测试以确保应用程序正常工作?如果您没有测试来证明,那么说应用程序正在“工作”是什么意思?

只是我的 0.02 美元。

于 2008-10-01T14:06:26.907 回答
2

测试使您可以放心地重构,因为您不会破坏系统。首先编写测试允许测试定义系统的工作行为。任何未由测试定义的行为都被定义为副产品,并且在重构时允许更改。首先编写测试也可以推动设计朝着好的方向发展。为了支持可测试性,您发现您需要解耦类、使用接口并遵循良好的模式(例如控制反转)以使您的代码易于测试。如果您在之后编写测试,则无法确定您已经涵盖了测试中系统预期的所有行为。您还会发现,由于设计原因,有些东西很难测试——因为它很可能是在没有考虑测试的情况下开发的——并且很容易忽略或省略测试。

我通常独自工作,主要是做 TDD——在我不遵守实践或还没有找到适合我做 TDD 的好方法的情况下,例如使用 Web 界面.

于 2008-10-01T14:11:33.557 回答
1

TDD 不是关于测试,而是关于编写代码。因此,它甚至为单个开发人员提供了很多好处。对于许多开发人员来说,编写更健壮的代码是一种思维转变。例如,您多久会想到“现在这段代码怎么会失败?” 在没有 TDD 的情况下编写代码之后?对于许多开发人员来说,这个问题的答案是否定的。对于 TDD 从业者来说,它会将思维方式转变为在对对象或字符串进行操作之前检查对象或字符串是否为空,因为您正在编写专门执行此操作的测试(破坏代码)。

另一个主要原因是变化。每当您与客户打交道时,他们似乎永远无法下定决心。唯一不变的就是变化。TDD 作为“安全网”有助于找到所有其他可能破坏的区域。即使在小型项目中,这也可以防止您在调试器中浪费宝贵的时间。

我可以继续说下去,但我认为说 TDD 更多的是关于编写代码而不是任何东西,这足以证明它作为单独的开发人员使用是合理的。

于 2008-10-01T14:10:26.227 回答
1

我倾向于同意您关于“一个开发人员”或“爱好”项目的 TDD 开销的观点的有效性,而不是证明这些费用是合理的。

但是,您必须考虑大多数最佳实践如果在很长一段时间内始终如一地应用,它们都是相关且有用的。

例如,从长远来看,TDD 可以节省您的测试/错误修复时间,而不是在您创建第一个单元测试后的 5 分钟内。

您是一名合同程序员,这意味着您将在当前项目完成后离开并切换到其他项目,很可能是在另一家公司。您当前的客户必须维护和支持您的应用程序。如果你不给支持团队留下一个好的框架来工作,他们就会被卡住。TDD 将有助于项目的可持续性。它将增加代码库的稳定性,因此经验较少的其他人将无法在尝试更改它时造成太大的损害。

这同样适用于爱好项目。你可能已经厌倦了,想把它传给别人。你可能会在商业上取得成功(想想 Craiglist),并且除了你之外还有 5 个人在工作。

对适当流程的投资总是有回报的,即使它只是获得了经验。但大多数时候你会感激当你开始一个新项目时你决定把它做好

做某事时必须考虑其他人。你必须提前思考,为增长做计划,为可持续发展做计划。

如果您不想这样做 - 坚持牛仔编码,这种方式要简单得多。

PS 同样的事情也适用于其他做法:

  • 如果你不评论你的代码并且你有理想的记忆,你会没事的,但其他人阅读你的代码不会。
  • 如果您不记录与客户的讨论,其他人将不会知道您做出的关键决定

等等无止境

于 2008-10-01T14:11:24.183 回答
1

如果没有一组合理的单元测试,我不再重构任何东西。

我不会先进行单元测试,然后再进行代码测试。我做 CALTAL -- Code A LIttle, Test A Little -- 开发。通常,代码先执行,但并非总是如此。

当我发现我必须重构时,我会确保我已经进行了足够的测试,然后我完全相信我不必保留整个旧架构变成新架构计划在我的脑海里。我只需要让测试再次通过。

我重构了重要的部分。让现有的测试套件通过。

然后我意识到我忘记了一些东西,我又回到了 CALTAL 开发新东西上。

然后我看到了我忘记删除的东西——但它们真的到处都没有使用吗?删除它们,看看测试中失败的地方。

就在昨天——通过一次大的重构——我意识到我仍然没有完全正确的设计。但是测试仍然必须通过,所以在我完成第一次重构之前,我可以自由地重构我的重构。(哇!)这一切都很好,因为我有一组测试来验证更改。

对于单飞 TDD 是我的副驾驶。

于 2008-10-01T14:11:39.580 回答
1

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

于 2008-11-12T20:01:18.500 回答
0

我将很快回答这个问题,希望你会开始看到一些推理,即使你仍然不同意。:)

如果你有幸参与了一个长期运行的项目,那么有时你会想要,例如,先编写数据层,然后可能是业务层,然后再向上移动。如果您的客户随后进行了需要对数据层进行返工的需求更改,则数据层上的一组单元测试将确保您的方法不会以不良方式失败(假设您更新测试以反映新需求)。但是,您也可能会从业务层调用数据层方法,并且可能在多个地方调用。

假设您对业务层中的一个方法进行了 3 次调用,但您只修改了 2 次。在第三种方法中,您可能仍会从数据层取回看似有效的数据,但可能会破坏您的一些假设几个月前编码。此级别(及更高级别)的单元测试应该旨在发现被破坏的假设,并且在失败时它们应该向您强调有一段代码需要重新访问。

我希望这个非常简单的示例足以让您更多地考虑 TDD,并且它可能会产生火花,让您考虑使用它。当然,如果您仍然没有看到重点,并且您对自己跟踪数千行代码的能力充满信心,那么我没有地方告诉您应该开始 TDD。

于 2008-10-01T14:06:32.743 回答
0

首先编写测试的关键在于它强制执行您正在制定的需求和设计决策。当我修改代码时,我想确保这些代码仍然被强制执行,并且很容易“破坏”某些东西而不会出现编译器或运行时错误。

我有一个测试优先的方法,因为我想对我的代码有高度的信心。当然,测试必须是好的测试,否则它们不会强制执行任何操作。

我有一些相当大的代码库可供我使用,并且有很多不平凡的事情正在发生。很容易做出改变,当 X 不应该发生时,X 突然发生。我的测试多次使我免于犯可能被人类测试人员忽视的严重(但微妙的)错误。

当测试确实失败时,他们有机会查看它们和生产代码并确保它是正确的。有时设计更改和测试需要修改。有时我会写出通过 100 次测试中的 99 次的东西。没有通过的那 1 个测试就像一个同事审查我的代码(在某种意义上)以确保我仍在构建我应该构建的东西。

于 2008-10-01T14:10:47.303 回答
0

我觉得作为一个项目的独立开发人员,尤其是一个更大的项目,你往往会被分散得很薄。
当突然检测到由于某种原因在预发布测试期间没有出现的几个关键错误时,您正处于大规模重构的中间。在这种情况下,您必须放下所有东西并修复它们,在花了两周时间撕掉头发之后,您终于可以恢复到以前所做的任何事情。
一周后,您的一位最大客户意识到他们绝对必须拥有这个酷炫的新闪亮功能,否则他们将不会订购他们应该在一个月前已经订购的 100 万个单位。
现在,三个月后,你甚至不记得你为什么开始重构,更不用说你重构的代码应该做什么了。感谢上帝,你在编写这些单元测试方面做得很好,因为至少它们告诉你重构后的代码仍在做它应该做的事情。
起泡,冲洗,重复。

..我过去 6 个月的生活故事。:-/

于 2008-10-01T14:11:49.813 回答
0

唯一的开发人员应该在他的项目上使用 TDD(跟踪记录无关紧要),因为最终这个项目可能会被传递给其他一些开发人员。或者可以引入更多的开发人员。

如果没有测试,新人将很难使用代码。他们会破坏东西。

于 2008-10-01T14:12:20.560 回答
0

当您交付产品时,您的客户是否拥有源代码?如果您可以说服他们通过单元测试交付产品会增加价值,那么您就是在向上销售您的服务并交付更好的产品。从客户的角度来看,测试覆盖率不仅可以确保质量,还可以让未来的维护人员更容易地理解代码,因为测试将功能与 UI 隔离开来。

于 2008-10-01T14:23:55.570 回答
0

我认为 TDD 作为一种方法论不仅仅是“在进行更改时进行测试”,因此它不依赖于团队,也不依赖于项目规模。这是关于在一个人开始真正考虑如何实现所指出的行为之前,注意一个人对一段代码/应用程序的期望。TDD 的主要关注点不仅是为编写的代码进行测试,而且编写更少的代码,因为您只需做使测试绿色的事情(并在以后重构)。

如果您像我一样发现很难考虑部分/整个应用程序的功能而不考虑如何实现它,我认为在您的代码之后编写您的测试并因此让代码“驱动”测试。

如果您的问题不是关于先测试 (TDD) 或后测试(良好的编码?),我认为测试应该是任何开发人员的标准做法,无论是单独还是在一个大团队中,他们创建的代码仍然在生产中超过三个月。根据我的经验,在这段时间之后,即使是原作者也必须认真思考这 20 行复杂、超级优化但文档很少的代码真正的作用。如果您进行了测试(涵盖了代码的所有路径),则无需思考-甚至几年后也不会考虑 ERR..​​.

于 2008-10-01T14:36:38.210 回答
0

以下是一些模因和我的回答:

“TDD 让我思考它会如何失败,这让我成为了一个更好的程序员”

如果有足够的经验,那么高度关注故障模式自然应该成为您流程的一部分。

“应用程序需要正常工作”

这假设您能够绝对测试所有内容。在正确地覆盖所有可能的测试方面,你不会比一开始就正确地编写功能代码更好。“应用程序需要更好地工作”是一个更好的论点。我同意这一点,但它是理想主义的,而且还不够具体,无法像我希望的那样激励。指标/轶事在这里会很棒。

“非常适合我的 <library component X>”

我在问题中说我在这些情况下看到了价值,但感谢你的轶事。

“想想下一个开发者”

这可能是我最好的论据之一。但是,很可能下一个开发人员也不会实践 TDD,因此在这种情况下,这将是一种浪费,甚至可能是一种负担。后门传福音就是在那里。不过,我很确定 TDD 开发人员会真正喜欢它。

当你继承一个已弃用的必须做的方法时,你会有多少欣赏项目?RUP,有人吗?如果 TDD 没有大家想象的那么好,想想 TDD 对下一个开发人员意味着什么。

“重构要容易得多”

重构和其他任何技能一样,是一种技能,迭代开发当然需要这种技能。如果我认为新设计从长远来看会节省时间,我倾向于丢弃大量代码,而且感觉也会丢弃大量测试。哪个更有效率?我不知道。

...

我可能会向任何新来的人推荐某种程度的 TDD……但是对于那些已经在街区附近几次的人来说,我仍然无法获得好处。我可能会开始向库中添加自动化测试。这样做之后,我可能会看到通常这样做的更多价值。

于 2008-10-01T16:04:51.803 回答
0

激发自身利益。

就我而言,唯一的开发者转化为小企业主。我已经编写了合理数量的库代码来(表面上)让我的生活更轻松。很多这些例程和类都不是火箭科学,所以我可以通过审查代码、一些现场测试和调试方法来确保它们正常工作(至少在大多数情况下)以确保它们的行为方式我认为他们会。蛮力,如果你愿意的话。生活很好。

随着时间的推移,这个库不断增长,并被用于不同客户的更多项目中。测试变得更加耗时。特别是在我(希望)修复错误并且(甚至更有希望)不破坏其他东西的情况下。这不仅适用于我的代码中的错误。我必须小心添加功能(客户不断要求更多“东西”)或确保代码在移动到新版本的编译器(Delphi!)、第三方代码、运行时环境或操作系统时仍然有效。

走极端,我可以花更多的时间审查旧代码,而不是处理新的(阅读:可计费的)项目。将其视为软件的休止角(未经测试的软件在倒下之前可以堆叠多高:)。

像 TDD 这样的技术为我提供了设计更周到、测试更彻底(在客户得到它们之前)并且需要更少维护的方法和类。

最终,它转化为更少的时间进行维护,更多的时间花在更有利可图、更有趣(几乎任何事情)和更重要(如家庭)的事情上。

于 2009-07-17T21:38:35.953 回答
-1

我们都是拥有良好记录的开发人员。毕竟,我们都在阅读 Stackoverflow。我们中的许多人都使用 TDD,也许这些人有很好的记录。我被录用是因为人们想要一个编写出色的测试自动化并且可以教给其他人的人。独自工作时,我在家里对我的编码项目进行 TDD,因为我发现如果我不这样做,我会花时间进行手动测试甚至调试,而谁需要它。(也许那些人只有良好的记录。我不知道。)

当谈到成为一名优秀的汽车司机时,每个人都认为自己是一名“好司机”。这是所有司机都有的认知偏差。程序员有自己的偏见。像 OP 这样的开发人员不做 TDD 的原因在这个Agile Thoughts 播客系列中进行了介绍。播客存档还包含有关测试自动化概念的内容,例如测试金字塔,以及关于什么是 TDD 以及为什么首先在播客存档中的第 9 集开始编写测试的介绍。

于 2019-03-28T05:33:05.143 回答