本文要点
- 现代软件测试中,开发人员需编写测试,并逐渐负责测试自己及同事的代码。
- 害怕失败或“评价焦虑”是十分常见的心理状态,它们受自我测试和团队测试的直接影响。
- 测试驱动开发(TDD,Test Driven Development)提出的严格测试所有代码的方法,在一定程度上可以看成是一种开发人员寻求规避对他们代码批评的防御机制。
- 行为驱动开发(BDD,Behavior Driven Development)等新方法可以减轻这种焦虑,使团队共同承担失败的责任。
- 为将注意力从开发人员代码中的软件缺陷上转移到团队达成客户需求的能力上,需要一种更宽泛代码覆盖率( Code coverage)测量方法。
作为一名编程人员,我永远也不会去编写测试,这不是我的工作。
上面的话来自于一个开发人员的声明。这名开发人员在团队领导宣布采纳 TDD 的两天后决定辞职,因为此后他所发现的严重代码质量问题将由他自己去处理。这一事情发生在 2006 年,当时的团队领导是杰出的开发者和测试者 Jeff Langr。Langr 在他撰写并由 Addison Wesley 出版的《开发人员测试》(Developer Testing)一书的序言中分享了这一故事。在该书中,Langr 这样写道:
感谢上帝,经过了十年的时间,很多开发人员已经意识到,测试自己的代码的确是他们自己的工作。很少有人会碰上那种不讨论各种类型开发人员测试的面试。面试者希望面试人员是软件开发专业人士,而成为这样的专业人士就要具备构造高质量产品的能力。事情已过去了十年,如果在面试中想要雇用一位认为不必亲自测试自己代码的开发人员,这样的想法都会被我压制下来。
身处敏捷开发和 DevOps 的时代,开发人员愈发需要对自己代码的各个方面负责,从编码质量到可维护性、可部署性、扩展性和安全。这一巨大转变使得编程人员从“代码技工”转变为作为需要交付价值给顾客的企业整体一员,已有不少人从文化角度对这一转变著书立传。
在本文中,我们将聚焦于该转变的另一个特定方面,即编程人员在承担了测试人员的职责后在情感上的影响。
对于一名编程人员,使自己的代码可以部署在生产环境中,这是应该负责做到的一件事情。而另一件需要做到的事情就是测试代码并发现问题,这时必须承认代码中存在着问题,去修复这些问题,并以一种透明的方式将这些问题提交给共享代码库。
我们也可以从另一个方面去做,即考虑使用敏捷团队中的一般实践做法。例如,当有人“破坏了构建”时,我们为了让团队看到是谁做错了,就在大屏幕上显示报警,或是发出刺耳的报警声。不可避免的是,这将会对大多数经历此过程的开发人员的情感产生影响。
开发人员测试会产生“评价焦虑”
测试正成为一种自省性和评估性活动。开发人员经常性地测试他们自己的工作。他们亲近的同事和上级也测试他们的工作。他们工作中的缺陷被经常性代码评估公之于众。
当然,通常也会有 QA 团队对开发人员的工作提出批评意见。不同之处只是 QA 团队是从外部做这件事情的,并通常是以“黑箱测试”的方式。QA 测试者曾被看成是底层雇员(至少过去是这样做的),他们是低收入的,并且时常是外包或海外雇用的,这降低了他们批评意见的影响力。
如果批评意见是来自于开发人员,而开发人员通常处于企业食物链的更高层级,他们对代码有一定的理解,因此他们所给出的批评意见具有更大的伤害。
焦虑是美国最常见的心理疾病,它影响了全美 18.1% 的人口。“社交和评价焦虑”最最常见的焦虑类型,它是美国第三大心理障碍问题,定义为“害怕被其他人做负面评估或评价,会导致感觉不适合、尴尬、羞辱和沮丧”。或者可以简单说成是害怕失败。按焦虑症医师 Thomas A. Richards 的说法:
如果你的医师说:“当你面对你的恐惧时,它们就会消失”,那么他们并未理解社会焦虑的机制。我们自一出生以来,就会经常面对我们的恐惧,现在我们感觉比过去更为恐惧。
我们并非试图指出测试实践会导致焦虑紊乱的全面爆发(不排除在一些极端情况下可能会是如此)。但是看上去很多(如果不是大部分)参与现代敏捷测试实践的程序开发人员正面对这种对负面社会评价的恐惧。
这种焦虑将会影响到开发人员的良好状态,对他们的生产力产生负面影响,并且从长远看,会阻碍专业发展。
TDD:一种无意识的防御机制
在敏捷开发中,曾出现了关于 TDD 的合法性和必要性的讨论。TDD 是一种严格的方法,可归纳为“红灯 / 绿灯 / 重构”的过程,其中对任何软件单元的开发都应该开始于评估该单元的一个测试。虽然一开始测试会失败,但是此后的功能会导致测试通过。进而,任何重构应确保测试能继续通过。
早至 2014 年,我们听到的一个突出说法是“ TDD 已死”。据声乐评论家 David Heinemeier Hansson 所写,虽然 TDD 承诺了对清晰可预测代码的涅槃重生,但事实上它已成为一种强迫开发人员遵循的福音,即便它导致了负面效果。原文如下:
在过去数年中,“测试为大”的措辞喧嚣尘上,也容不得其它的方式。当时我也被吸入到这个原教旨主义的漩涡中,痛苦于没有遵循真正的福音。……在公开场合,最好情况下我只是提及不要“测试为大”,而最坏情况下,我会继续坚持这种做法是“正确的方式”。
我现在很后悔这样。
可能出于要打破业界缺乏自动回归测试的遗憾,的确有必要使用“测试为大”作为一种反直觉的冲击。……但是我早已跳出了设计教条。我建议大家也认真查看一下这一方法对系统设计整体性的所作所为(本文原作者 Gilad David Maayan 对此句话加了重点)。
目前对 TDD 体验的盲从导致了测试主要集中于单元测试。……我并不认为这是健康的。测试驱动单元形成了过于复杂的网络,其中充斥着中间对象和间接结果。……它所产生的架构中具有一些十分可怕的怪物,是一个由服务对象、命令模式以及甚至更糟的对象所组成的密集丛林。
很高兴看到不少企业正从以 TDD 为测试模式中跳出,并转向 BDD。Atlassian 的 Heather Krebsbach 在 2016 年就明确写道:
“测试为大”的方法被称为是 TDD,它正日益得到广泛使用。但是我们很快就认识到,TDD 并未给予我们对系统中大多数重要业务案例所需的可见性和覆盖率。因此产生了 TDD 的一个变种,称为 BDD。BDD 聚焦于系统的行为,而非技术方面。
上面是描述“TDD 不工作”原因的干货,但是我们要做进一步深挖。使用 David Hansson 描述的那些“盲信的”并且时常不合理的实践,并结合了 Krebsbach 对 TDD 无效性的描述,这共同构成了一个称为“理智化”(Intellectualization)的心理学概念。根据维基的描述:
在心理学中,理智化(intellectualization)是一种防卫机制,其中,推理用于阻碍无意识冲突并对抗相关情感的压力,思考用于避免情感影响。理智化涉及从情感上去除一个人在有压力的事件中的自我。理智化可能会伴生合理化(rationalization),一种非理性的伪理性理由,但是理智化不同于合理化。
鉴于 TDD 是一种“强制”测试每行代码的行为,TDD 是否无意识中成为一种保护开发人员免受对代码批评的机制?
这是个强声明,我们并非建议 TDD 仅是如此。我们建议的是,该情感潜台词是一种方法论的背景,可能是导致了 TDD 缺乏变通、教条和有时短视的原因。
BDD 是否在心理上更健康?
BDD 是否要优于 TDD?在当前场景中,可能是。BDD 侧重于业务需求,而非代码。它以形式化语言指定了一个敏捷“故事”,并允许开发团队测试该故事。
BDD 使我们从由特定开发人员编写测试代码的操作,以及对“破坏构建”开发人员的搜索,转向更宽泛的评估整个团队性能的操作。
终究,一个敏捷团队会分享向客户交付价值的责任,并将价值作为开发人员、测试人员和运维人员间的团队工作。在 BDD 中,测试故事而非代码单元,这使得“热点”不再落在个体开发人员身上,而是成为一种小组的反思(Inspectction)行为,就像是由团队共同完成的“Scrum 回顾”。
我们断定,虽然 TDD 曾是(至少部分上曾是)一种允许每个开发人员辩解自身代码的防卫机制,但是 BDD 是一种心理上更健康的方法。BDD 允许开发人员以团队的形式评估自身的工作,并分担了在代码中发现缺陷的责任,解决并缓解了评估焦虑(Evaluative Anxiety),而非只是理智化。
推出更宽泛的测试覆盖率概念
SeaLights 是一家聚焦于为敏捷团队增加测试覆盖率提供帮助的初创公司。该公司认为,敏捷开发当前使用的测试度量通常是偏斜的(需要指出的是,我是SeaLights 公司的一名顾问)。“测试/ 代码覆盖率”是一个更令人垂涎的度量,它几乎总是意味着“单元测试覆盖率”。这看上去是TDD 时代的一个退步。在TDD 时代,单元测试被认为是敏捷测试的首要的和最重要的部分。
在BDD 方法中,测试更加广泛,也更为包容,但是测试的度量并未随之发展。团队越来越多的使用自动UI 测试、集成和接收测试,但依然继续使用“覆盖率”测定代码被单元测试覆盖的百分比。
在BDD 中,单元测试覆盖率并非真正地测定了测试套件的全面性,也不是一种管理层可用于评估测试程序有效性的度量。
因此我们需要对代码覆盖率做更整体的测量,同时也应考虑到集成测试、UI 测试和接收测试。这并非是要强制性驱动对每一行代码的测试,团队应该转变为可确保敏捷团队所覆盖的每个业务功能或“故事”都得到测试。
能真正降低开发人员焦虑的方法是对整体覆盖率进行测定,并一起工作去实现覆盖率。这有助于我们去共同面对代码中缺陷,而非力图去对这些缺陷理智化或是合法化。
作者简介
Gilad David Maayan是一位技术作家,他为向新观众阐明领先的技术品牌产品提供帮助。他也是 Agile SEO 的创始人和 CEO。Agile SEO 通过搜索引擎将开发人员、IT 领导者即相关内容联系在一起。
译者注:原文的评论情况
该文在 InfoQ 上得到了广泛的讨论,读者的不同意见可总结为:
- TDD 并非是对每一行代码的逐一测试,而是用于发现应编写的代码。它更倾向于是一种信任构建实践,团队人员一起工作实现分析和设计。
- TDD 中很少将代码覆盖率作为一个指标,因为它本身就实现了很好的代码覆盖率。
作者回复的要点是:
- TDD 的目标的确是生成开发人员共同依据的框架,但是在实践中,不少企业使用 TDD 的目标在于改进设计。
- 本文目标也并非以代码覆盖率为核心讨论 TDD 问题,而是从心理学角度分析 TDD 对开发及开发人员的影响。
从译者角度看,我比较支持 David Farley 的观点。他指出,TDD 并非一种测试方法,而是一种设计原则。如果得以很好的应用,会放大软件开发人员的技能,帮助团队中落后的开发人员做出更多贡献。TDD 关注的主要是低层级的单元测试,而 BDD 关注的是高层级的接收测试(Acceptence Test),即更复杂的基于场景的测试。因此,不同的方法归根结底取决于终端用户与代码间的关系。单元测试并非直接面对最终用户,因此在行为中具有一定强制性。
查看英文原文: Is TDD a Form of OCD?
评论