TDD死了吗?

2020-08-26 20:38:08

一场挑衅性的谈话和博客帖子促成了一场对话,我们的目标是了解彼此的观点和经历。

更多…。这场对话开始于David的RailsConf主题演讲,他在会上表达了他对Rails社区中的TDD和单元测试的不满。不久之后,他发表了一些博客帖子,其中第一篇宣布“TDD死了”。

几天后,我给他发了一篇后续帖子的打字错误更正,他说他欢迎我对他的演讲和博客帖子的想法。然后,我们在Skype上进行了长达一个小时的愉快而深思熟虑的讨论。大卫与肯特进行了类似的讨论,肯特建议我们继续与我们三个人讨论,并将对话公之于众。大卫在推特上发布了这个想法,得到了很多积极的回应。

我们对这个系列没有太多的计划,只是粗略地设想了六个30分钟的对话。我们这么做主要是因为我们想了解彼此的经历和观点--我们只是太自恋了,以为很多人都想看我们。我们在前几集没有回答问题,但在最后一集我们确实回答了几个问题。当我们这样做的时候,我们很享受在博客和推特上继续讨论的方式。

我们要感谢ThoughtWorks,特别是Wesley Clock,他们为组织视频设置和安排闲逛时间做了大量的后勤工作。在每一集之后,我为那些喜欢阅读而不是观看的人写下了讨论的记录。

我们谈到了我们对TDD流程的不同体验,以及TDD和自测代码经常被混淆的方式。

David认为,使用TDD会导致像六角形Rails这样的方法,这是由于过度间接的复杂性而导致的测试导致的设计损坏。肯特认为它更多的是关于设计决策的质量,而不是TDD。

在观看这段对话之前,您应该先看看David准备展示他所关心的设计损坏的示例的要点。你可能还会看视频,在视频中,人们非常怀念的Jim Weirich探索了这种六边形建筑的方法。

大卫的要旨是展示他所关心的那种设计损害的例子。本文的要点基于Jim Weirich在一次演讲中对六角形Rails架构的探索。

术语六边形架构最初是由阿里斯泰尔·科克伯恩首创的,它也不太为人所知的是端口和适配器。

在这个聚会之后,我和我的同事Badri Janakiraman做了另一个关于六边形Rails架构的本质和使用它的权衡的演讲。

我们讨论了在编程时获得反馈的各种方式,以及QA在向开发人员提供反馈方面的作用。

我们讨论了测试和TDD的一些缺点:你能做太多的测试吗?团队重视测试多于重视功能代码有问题吗?

关于滥用度量的话题,看看Pat Kua&39;关于适当使用度量的文章。

我们回答观众的问题:TDD的开源示例有哪些,哪些变化会使我们改变TDD的使用,以及它对经验不足的开发人员有多好。最后,我们总结一下我们对拓展署健康状况的看法。

我首先要说的是,我们将通过挑选和回答观众提交的一些问题来组织这个聚集地。David从Mike Harris那里挑了一个问题开始,他询问了使用TDD的开源项目的例子,这些项目要么受到了测试引起的设计损害,要么使用得很好。大卫回应说,没有好的例子,这是类似辩论的问题之一。一般来说,我们没有很好的应用程序示例,因为开源贡献者经常在私有应用程序和开源公共框架和库上工作。因此,我们在不同的背景下进行这些讨论,这往往会让人看起来有更多的分歧,而不是实际存在的。当你有真正的代码而不是哲学原则时,人们就会聚集在一起。我们的代码示例是次要的示例,而不是人们实际正在做的事情,所以你必须通过演示来理解人们--这就是为什么他使用Jim Weirich的示例来破坏设计。对于好的Rails代码,他建议使用展示标准测试方法的Rails书籍。

我认为理解真正的代码需要付出很大的努力。我对我们的代码库做了一些深入研究,但这需要很多时间,而且即便如此,这也与您通过与团队一起工作而获得的理解不同。Kent说,JUnit是严格使用TDD并且结果良好的项目的一个例子。但是对于这个讨论来说,它不是一个很好的例子,因为它有清晰的接口,这是TDD的最佳选择。我们在这里谈论的是不同类型的应用程序。如果有人有一个很好的例子,他们应该把它写下来。

大卫说,我的评论表明,我们不能把编程当作一门科学--我们不能客观地评估技术。这并不意味着它不值得争论。我们不能得到一个明确的答案,你的工作就是找出什么是有意义的。肯特同意我们不能重复实验,但他说我们仍然可以用科学的思维来看待事物。我们可以自己进行实验,但是你不能得到普遍的答案。

Kent选择了下一个问题(由Graham Lee提出):对于Kent和Martin,我们编写软件的方式会有哪些改变,从而使TDD变得冗余或过时?对于执行TDD的方式,又会有哪些改变,从而使其对David有用?肯特回应说,他的RIP TDD帖子指出了他的立场(如果是讽刺的话)。TDD解决了几个问题,从自信开始。拓展署亦让他可以将问题零碎分解,处理具体个案,而无须一下子解决一般个案。他不准备仅仅因为TDD很难就放弃它。

我说,对我来说,这不是关于会使TDD过时的变化,而是TDD在不同环境中的适用性。我经历过以机械的方式跟随TDD,从容不迫地快速从容,在那里我犯了错,做出了好的设计。这些天我的大部分编程都是我的网站工具链,虽然我做的是零碎的进展,并且有一个很好的回归测试套件-我不觉得TDD适用。但是当我构建信息平台代码时,有很多TDD有效的应用程序行为。有些上下文非常适合TDD,而有些上下文则不太适合。人们把他们的个性带到了那个背景下。

大卫说,他的经历与此类似。他是通过TDD介绍测试的,他喜欢TDD,并试图将它应用到所有东西上,但慢慢地意识到MVC Web应用程序中的许多领域对TDD来说并不是很好。这并不意味着TDD在某些情况下不有效,只是这些情况只占他工作的一小部分。但是放弃TDD并不意味着他想要放弃自我测试代码--这对他来说一直是TDD的价值所在。

我说,这正是人们应该如何对待TDD(或任何技术)的。试一试,过度使用,进入一种适合你的模式。然后再看得更深一点:TDD是通往自我测试代码的入门药物。肯特说,他并不介意人们在做完这类流程后,他们的工作流程最终会落到什么地步。他使用TDD的经历与David不同,他发现在开发过程中,有些事情是困难的,他对具有特定协议的对象有了一个想法,从而简化了事情。TDD为他提供了一种机制,可以快速获得对这种想法的反馈,尝试并示范API的使用并实现它。他还发现了TDD不符合的案例。然后他发现COMMAND-R是获得反馈的好方法,但他希望有一天他能看到简化的对象,并用TDD来尝试它。

我选择了下一个问题(来自Tudor Pavel):TDD如何与经验较少的开发人员协作。我的回答是,TDD强迫人们做一些小事,并帮助他们将接口与实现分开。它不能保证有很好的效果,因为没有经验就不能做好的设计。当经验较少的人做TDD时,他们通常不会进行足够的重构,从而导致次优设计。您不能将一个没有经验的开发人员的输出与一个有经验的开发人员的输出进行比较,您必须将其与有索引经验的开发人员在没有TDD的情况下所做的工作进行比较。虽然我们无法衡量这一点,但它看起来确实很有优势,并且创建了一个自测试代码库,更容易在以后通过重构进行改进。因此,TDD为您提供了一个很好的起点。

大卫说,这就是他从TDD获得的价值。他从TDD开始,发现这是一个很棒的培训轮,然而他觉得从那以后讨论就没有足够的进展了。当人们说你必须给新人提供简单、直接、夸张的建议时,他持怀疑态度,否则他们不会这么做。这表明你对自己正在教授的东西缺乏信心。我同意这种对教条声明的厌恶。如果我找不到反对我所描述的东西的论据,我就会怀疑。然而,一个转折是,我们确实必须不断重复

大卫认为这就是我们现在进行这次谈话的原因。正如人们描述TDD时,他们在基本的基础上添加了自己的旋律,经过十年的发展,你最终会从你开始的地方走上很长一段路,而且不是在一个好的地方。你需要按下重置按钮,这是一种粗糙但有效的方法。当他说TDD已经死的时候,他指的是目前的突变--我们必须回到首要原则上来。肯特说,他对大卫最初的主旨演讲的本能反应是这样的。程序员通常会多次做同样的事情,把事情搞得太复杂,并在工作中坚持使用功能失调的系统。他很高兴重新启动到第一原则,但他不想失去人们在过去十年里对编程的期望的演变。您应该能够感到自信,指向进步,进行富有成效的技术协作。他觉得他现在可以在工作中做他自己,这是他开始职业生涯时所不能做到的。

David认为有几个东西同时出现:TDD、XP和Ruby。人们嘲笑编程应该有趣的想法,但他想在开发Rails时继续这个想法。现在他认为Ruby世界认为这种快乐是理所当然的--这些东西都赢了--敏捷也是如此。我不同意敏捷赢了-标签赢了,但很多人说他们做了敏捷,但并不是真的。这是典型的,我称之为语义扩散的过程。最大的胜利是现在我们能够在客户面前公开进行敏捷。David从其他方面观察到了这个重启问题--十年后,你会得到很多麻烦。他举了Pinkberry的例子,它一开始只有两种口味,但后来就像其他冰淇淋一样,得到了一系列复杂的口味--大多数人都他妈的不能放弃好主意。TDD和Agile现在都是非常广泛的帐篷。自称在做敏捷的人做的事情恰恰相反。肯特说,他还没有看到大卫所拥有的TDD的东西。在他的工作中,他总是从最基本的原则出发,运用TDD。

Kent很感激David已经引起了TDD的注意,他收购了一些藤壶,需要一些刮除。大卫说他看到过类似的Rails问题。他使用Rails的基本形式,并对他看到的一些Rails用法感到震惊。肯特还记得第一个OOPSLA,当时XP引起了人们的关注,吉姆·伦博(Jim Rhumaugh)说过,你在十年内都不会意识到XP发生了什么,他是对的。我说这就是成功的样子,否则事情就不会腾飞。总是很难辨别出是由于某种技术固有的原因还是由于对某种技术的误用而发生了一些不好的事情。我们所能做的就是不断重复基础知识和好的教训。大卫同意:你要么英勇牺牲,要么成为别墅。Ruby是编程方面好主意的重新启动。函数式编程是另一种重启。这些重新启动是健康的。他对Rails和TDD的持续时间印象深刻。在Rails出现之前,他使用PHP。如果你用得好,你可以用PHP写出好的代码,他觉得其他语言在鼓励好的使用方面做得更好。他认为在MVC web应用中很好地使用TDD比编写干净的PHP更难。

肯特还没有发现--只要他能把一个问题分解成一个有用的抽象概念,他就可以使用TDD。他想要探索其他途径来实现这些宏伟的目标,即把自己全部投入到编程中来。他将继续通过实验来探索这一点:做得太多,做得不够,找到戈利洛克带,并了解为什么。他站出来坚决反驳大卫:TDD并没有死,但很高兴大卫放火烧了它,这样它就可以像凤凰一样出现。

大卫说,他发起这场讨论是因为人们不会谈论TDD无效的案例。他们感觉不好,也不自信,但他们被告知必须使用TDD。他想打开可接受反应的范围,这样我们就可以讨论什么时候TDD是合适的,什么时候不合适。很多人在互联网上谈论TDD有多好,但人们不敢说它对他们不起作用。对David来说,婴儿是自我测试的代码,我们不想在询问TDD时丢失这一点。

我最后说(正如我在开始之前怀疑的那样),我们有很多共识。我们都非常重视自测试代码,我们都同意TDD在某些上下文中是有价值的,我们可能不同意有多少上下文(虽然很难真正区分)。一切都可以归结为,如果你参与了软件开发,你必须深思熟虑,你必须建立对你和你的团队有效的实践,你不能盲目地采用任何技术。您需要尝试它,使用它,过度使用它,并找到对您和您的团队有效的方法。我们不是在一门经过编纂的科学中,所以我们必须根据自己的经验来工作。