acm-header
登录

ACM通信

实践

在苹果里发现不止一条虫子


在苹果里发现不止一条虫子,插图照片

来源:Shutterstock.com

回到顶部

今年2月,苹果披露并修复了一个自2012年9月iOS 6.0发布以来一直未被发现的安全套接字层(SSL)漏洞。由于SSL/TLS(传输层安全)握手算法的一个短路,它使用户容易受到中间人攻击转到声明。自从发现这个非常严重的错误以来,许多人都写了关于潜在原因的文章。然而,对代码的仔细检查不仅揭示了如何编写单元测试来捕获错误,而且还揭示了如何重构现有代码以使算法具有可测试性,以及更多关于错误的性质和产生错误的环境的线索。

本文解决了关于SSL漏洞的五个大问题:错误是什么(为什么是坏的)?它是怎么发生的(又怎么没发生)?测试怎么可能检测到呢?为什么测试没有发现它?我们如何解决根本原因?

Apple SSL漏洞的正式名称为CVE-2014-1266,是由包含一个虚假的、无条件的漏洞而产生的转到语句绕过了SSL/TLS握手算法的最后一步。根据国家脆弱性数据库(http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2014-1266)及通用漏洞及暴露(CVE)标准漏洞条目(http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-1266),该漏洞存在于附表所示的iOS、OS X和Apple TV操作系统版本中。

这些正式报告对该漏洞的描述如下SSLVerifySignedServerKeyExchange在数据安全组件的安全传输特性中的libsecurity_ssl/lib/sslKeyExchange.c函数…不检查TLS服务器密钥交换消息中的签名,这允许中间人攻击者通过在签名步骤中使用任意的私钥或忽略签名步骤来欺骗SSL服务器。”这个错误可以通过在苹果发布的开源代码(http://opensource.apple.com/source/Security/Security-55471/libsecurity_ssl/lib/sslKeyExchange.c),寻找这一系列的语句:

ins01.gif

熟悉C编程语言的人会认识到第一个转到失败是必然的如果紧接在它前面的语句;第二个被无条件处决。这是因为,用于嵌套条件语句以提高可读性的空格被C编译器忽略;当应用多个语句时,必须将绑定到if语句的所有语句括起来。

另一个转到失败在整个算法中出现的语句是C语言中常见的习惯用法,用于在函数在完成之前遇到致命错误时释放资源。在有缺陷的代码中,成功了update ()调用将导致无条件跳转到函数的末尾,在算法的最后一步之前;返回值将表示握手成功。从本质上说,算法短路了。

对于在受影响的平台上使用苹果Safari和其他基于安全传输的应用程序的用户来说,“安全”连接很容易受到中间人攻击,通过中间人攻击,可以将消息从客户端通过互联网转发到“安全”服务器的攻击者可以冒充服务器,在虚假握手后拦截所有通信。(采用自己的SSL/TLS实现的产品的用户,如谷歌Chrome和Mozilla Firefox,没有受到影响。)虽然尚不清楚这个漏洞是否曾被利用过,但它在17个月的时间里使数亿设备(和用户)容易受到攻击。

苹果公司因在2014年2月21日星期五为iOS设备和Apple TV打补丁而受到批评,这使得漏洞广为人知,但却将OS X Mavericks的补丁推迟到了下星期二。这四天的窗口让那些不知道iOS补丁的用户容易受到现在非常公开的漏洞攻击。

回到顶部

它是怎么发生的(又怎么没发生)?

许多人已经注意到,明显缺失的因素可能会引发这种疾病。编码标准,特别是那些强制使用缩进和花括号结合自动样式检查工具和代码检查的标准,可能已经引起了对重复语句的注意。自动合并可能会产生违规的额外行,而开发人员可能缺乏足够的经验来检测它。如果收集了覆盖率数据,它将突出显示不可访问的代码。编译器和静态分析警告也可能检测到不可访问的代码。

其他人则指出,代码似乎缺乏单元测试,而单元测试很可能会发现这个bug。虽然许多其他工具和实践可能已经足够防止这个特定的漏洞,但一个更深层次的问题最终产生了重复转到语句,将被适当的单元测试规程所阻止。

一些人质疑是否进行了充分的系统测试,而另一些人则认为,因为系统测试不能找到每个错误,这只是一个偶然疏忽的不幸案例。其他人声称使用转到声明和/或蓄意破坏是罪魁祸首。这些说法都经不起推敲。

不被认为是有害的。既然它是比较流行的理论之一,让我们抛开使用的争论转到就是这个漏洞的罪魁祸首。许多人提到了一个流行的概念转到根据Edsger Dijkstra在1968年3月发表的信,被认为是“有害的”ACM通信.这正是Dijkstra在《反对GO TO声明的一个案例》中所说的:“我并没有声称上述条款是详尽无遗的,因为它们将满足所有的需求;但是,无论建议什么条款(例如,流产条款),它们都应该满足这样的要求:可以维护一个独立于程序员的坐标系,以一种有用的和可管理的方式描述过程。”9换句话说,“流产条款”释放一个功能的资源可能仍然依赖转到,缺乏其他直接的语言支持。

这个C语言的“流产条款”习惯用法是合法的,而且很容易理解,其他语言也直接支持它。例如,在c++中,自动析构函数实现了资源获取即初始化(RAII)习惯用法;Java使用try/catch/finally阻塞(http://docs.oracle.com/javase/tutorial/essential/exceptions/handling.html);去提供推迟(),恐慌(),恢复()机制(http://blog.golang.org/deferpanic-and-recover);和Python已经试着/ /最后除外块(http://docs.python.org/3/reference/compound_stmts.html#try)和语句,用于实现RAII (http://docs.python.org/3/reference/compound_stmts.html#the-with-statement).没有这些机制,在C语言中这仍然是一个合法的应用转到语句,以免代码因重复语句而变得臃肿,或者控制结构嵌套太深而影响可读性和可维护性。

其实是放错了地方返回这句话本可以产生同样的效果。假设定义了如下的宏:

ins02.gif

那么这个bug可能会出现在这个版本中:

ins03.gif

即使强制使用花括号也可能无法防止错误,因为它们可能不匹配:

ins04.gif

这一漏洞的责任不在于转到声明。正确的单元测试应该能够捕获错误,而不管它是如何编写的。

代码重复.握手算法,其中额外转到语句在整个代码中重复了六次。图1显示了包含重复转到失败中显示的行SSLVerifySignedServerKeyExchange ()函数。图2显示紧接在此算法之前的块。这种重复是导致脆弱性表现出来的关键因素它可以直接追溯到单元测试规程的缺乏,因为缺乏可测试代码所需要的工艺和设计意识。在编写代码时考虑到单元测试的人会确保算法只有一个副本存在,这不仅是因为它在理论上更合适,而且因为它更容易测试。

编码员不能“闻到”(http://blog.codinghorror.com/code-smells/)的重复代码,或复制它的第二次,第三次,第四次,第五次,或第六次!这表明一种长期以来的不良习惯模式,而不是一个粗心的错误。归根结底,这是一个文化问题,而不是个人的一时失误。

回到顶部

测试怎么可能检测到呢?

Landon Fuller发表了一个用Objective-C实现的概念验证单元测试,10使用Xcode测试框架。2富勒指出:“没有任何理由或借口SSLVerifySignedServerKeyExchange ()函数]没有对“所有潜在的错误条件”进行充分测试。然而,这种概念证明错过了深入研究代码和提供这个特别关键算法的完整测试覆盖的机会——如此关键以至于它在同一个文件中出现了六次。

正确测试算法的第一步是将它提取到一个单独的函数中,这个函数本身可能会防止重复转到失败这导致了错误,因为单个代码块比六个几乎相同的代码块更不容易受到编辑或自动合并错误的影响(图3).

前面的两个代码块来自SSLVerifySignedServerKeyExchange ()现在出现在图4

这很有效,因为HashReference是一个“跳转表”结构,而SSLHashMD5和SSLHashSHA1是HashReference,它们指向特定的哈希算法实现。的HashReference接口使得编写一个小测试非常简单,可以通过隔离的HashHandshake ()算法使用HashReferenceStub,并验证它是否捕获了这个特定的错误:

ins05.gif

的代码TLS _ digest _ test.c可以在http://goo.gl/PBt9S7.安全- 55471 -错误修复和test.tar.gz (http://goo.gl/tnvIUm)包含了我所有的概念验证更改;build.sh自动下载代码、应用补丁,以及使用单个命令构建和运行测试。测试和补丁是非常快速的工作,但作为独立的演示工作,不需要构建整个库所需的全套依赖项。无可否认,这个演示并没有进一步解决代码中出现的重复或其他问题。

关键是,如果一个已经离开这个行业2.5年的前程序员能够在几个小时内成功地重构和测试这段代码,而之前从未见过它,为什么负责这段代码的工程师或团队没有在17个月前正确地测试它?

回到顶部

为什么测试没有发现它?

有几篇文章试图解释为什么Apple SSL漏洞能够通过苹果可能已经准备好的任何测试、工具和流程,但这些解释都是不合理的,特别是考虑到上面的演示与之相反在工作代码.在发布之前未能检测到此漏洞的最终责任不在于任何单独的程序员,而在于生成代码的文化。让我们回顾一些最著名的解释,并说明为什么它们不尽如人意。

亚当·兰利经常引用的博客帖子13讨论了这个错误的确切技术后果,但放弃了断言自动测试会捕捉到它:“一个测试用例可以捕捉到它,但它很困难,因为它是如此深入握手。一个人需要编写一个完全独立的TLS堆栈,有很多发送无效握手的选项。”

这种“很难测试”的辞职补充了“我没有时间测试”的借口,我是谷歌的test雇佣兵之一,经常听到(尽管,到我们解散的时候,测试在谷歌根深蒂固,这个借口很少再听到了)。11然而,正如前面所演示的,单元测试绝对可以捕捉到这一点,而不会有过多的困难。有效地测试算法不需要“一个完全独立的TLS堆栈”;使用精心设计的代码进行精心设计的测试会发现错误认为很可能会完全阻止它的发生。

不幸的是,有些人采用了Langley的立场,没有考虑到在系统级别测试所有东西的不可行性,这就是为什么存在小、中、大测试规模的模式单元测试、集成测试,系统对世界上绝大多数国家(谷歌)来说。8在持续集成系统(例如,谷歌的TAP、Solano CI)下运行的不同规模的自动化测试正在成为整个行业的标准实践。有人会认为这是像苹果这样的大型软件开发公司的核心功能,尤其是涉及到其产品的安全关键组件时。

写为板岩, David Auerbach为非程序员分析了这个缺陷,并假设这个错误可能是由合并错误引起的(基于这个差异:https://gist.github.com/alexyakoubian/9151610/revisions;然后他总结道:“我认为以今天的标准来看,这段代码是相当不错的。如果代码不好,苹果就不会把它作为开源发布,即使他们做了,如果他们仔细查看它,发现它是垃圾,开源社区也会强烈抗议的。”3.

奥尔巴赫的结论假设苹果发布的所有东西都是高质量的,它有合理的控制来确保高质量,所有的开源代码都受到大量程序员的集中审查(感谢Stephen Vance在我的演讲中特别指出了这一点),至少是那些有动机报告安全缺陷的程序员。然而,从实际的代码中可以看出,苹果缺乏自动化测试规程和相应的工艺,也缺乏其他质量控制,而不是像奥尔巴赫想象的苹果已经采用的现有规程那样容易出错。

安全专家Bruce Schneier指出:“漏洞很微妙,在扫描代码时很难发现。很容易想象这是如何错误地发生的. ...这是故意的吗?我不知道。但如果我想做这样的事情,我就会这么做。”15Schneier关注的是安全性,而不是代码质量,所以他的观点是可以理解的;但有证据表明这是程序员错误和缺乏质量控制造成的。

代尔夫特大学计算机科学教授Arie van Deursen指出,许多行业标准的工具和实践可能会感染病毒;但尽管他自诩为单元测试的坚定倡导者,但他反对断言应该应用这种实践:“在当前的代码中,函数很长,它们涵盖了不同条件分支中的许多情况。这样就很难调用特定的行为. ...因此,考虑到当前的代码结构,单元测试将是困难的。”16然而,正如前面所演示的,这个特殊的、关键的算法很容易提取和测试。软件结构可以改变以促进许多目的,包括改进可测试性。推动这样的改变是谷歌测试雇佣兵的工作。

我的前Test雇佣兵同事C. Keith Ray在他对van Deursen文章的评论和他自己的博客中指出:“大多数试图在一个设计糟糕、没有单元测试的项目中使用TDD(测试驱动开发)的开发人员会发现TDD在这种环境下很难实现,并会放弃。如果他们尝试“测试后”(与TDD的测试优先实践相反),他们也会发现在这种环境中很难做到并放弃。这就形成了一个恶性循环:未经测试的糟糕代码鼓励了更多未经测试的糟糕代码。”14

我在很大程度上同意Ray的说法,但希望他能抓住这个机会提及明显的重复代码气味以及如何消除它。再说一次,这是我们作为测试雇佣兵的惯用伎俩。过去没有TDD并不妨碍现在的代码更具可测试性,我们有责任演示如何做到这一点。

哥伦比亚大学计算机科学教授Steven M. Bellovin对漏洞及其后果提供了另一个彻底的解释,但当他问到“为什么他们没有在第一个地方发现漏洞”时,他的重点仍然是详尽的系统级测试的不可行性:“无论你测试了多少次,你都不可能测试所有可能的输入组合来试图找到一个故障;组合是不可能的。”4

如前所述,此漏洞不是系统测试不足的结果;这是因为单元测试不足。Keith Ray自己写了一篇"马桶上的测试"8文章《太多的测试》11解释如何将复杂的逻辑分解成小的、可测试的函数,以避免输入的组合爆炸,同时仍然能够覆盖关键的角落案例(“等价类划分”)。考虑到TLS算法的复杂性,单元测试应该是第一道防线,而不是系统测试。当相同算法的6个副本存在时,系统测试人员就会为失败做好准备。

这种缺乏开发人员测试规程的证据,特别是对于安全关键型代码,说明了工程和/或企业文化的失败,没有认识到单元测试和代码质量的重要性和影响,以及容易预防的故障的实际成本,并鼓励经过良好测试的代码而不是未经测试的代码。查尔斯·亚瑟引用了一位匿名前苹果员工的评论《卫报》2支持这种说法:

“为什么苹果没有早点发现这个漏洞?”


考虑到TLS算法的复杂性,单元测试应该是第一道防线,而不是系统测试。当相同算法的6个副本存在时,系统测试人员就会为失败做好准备。


“该公司的前程序员说,‘苹果没有强大的测试或测试驱动开发文化。苹果过度依赖自己也[使用自己的产品]进行质量过程,这在安全情况下是不合适的. ...

“我们从中得到了什么教训?”

但这位前苹果员工表示,除非公司引入更好的测试制度——静态代码分析、单元测试、回归测试——否则我对此并不感到惊讶……下一次这样的炸弹袭击只是时间问题。”唯一最小的安慰是:“我怀疑这是恶意的。’”

评论人安东尼·皮卡德(Antoine Picard)在评论这一安全漏洞与苹果MacBook电源线问题的相似之处时指出:“当一切都只在乎设计时,其他一切都会遭殃。”12

回到顶部

我们如何解决根本原因?

那些有单元测试经验的人理解它的生产力好处,超过了风险预防;但是,当没有经验的人仍然顽固地不相信时,像这样明显的错误可以证明单元测试的具体价值在工作代码

抓住教育的时刻!写文章、博客、传单、演讲、发起对话;在可能的情况下进行工作单元测试;让开发人员、团队和公司对代码质量负责。

随着时间的推移,通过不断的努力,文化可以改变。苹果的漏洞,以及2014年4月在OpenSSL中发现的Heartbleed漏洞(在本文最初起草之后),本可以通过与我的测试小组(http://mike-bland.com/tags/testing-grouplet.html),测试认证,5《厕所上的测试》和《Test雇佣兵》的犯罪伙伴在几年的时间里努力向谷歌工程演示。到我们完成的时候,彻底的单元测试已经成为了预期的文化规范。(我对Heartbleed的评论,带有工作代码,可以在http://mike-bland.com/tags/heartbleed.html.)

改变文化并不容易,但这是可能的。如果志同道合的开发人员跨团队、跨公司、甚至跨行业联合起来,就像自动化测试波士顿Meetup (http://www.meetup.com/Automated-Testing-Boston/),它在纽约、旧金山和费城的姐妹小组,以及AutoTest Central社区博客(http://autotestcentral.com/),并进行创造性的追求,以提高人们对这些问题及其解决方案的认识,随着时间的推移,变化将会到来。

我们的目标是让这篇文章和其他文章包括我的文章《Goto Fail, Heartbleed, and Unit Testing Culture》由Martin Fowler (http://martinfowler.com/articles/testing-culture.html)推动围绕Apple SSL和Heartbleed漏洞的讨论,传播意识并提高话语质量;不仅围绕这些特定的错误,而且围绕单元测试和一般代码质量的主题。这些bug是一个完美的风暴,使它们成为这种讨论的理想因素:

  • 苹果漏洞的实际缺陷非常明显,“心脏出血”漏洞只需要少量的技术解释。
  • 可以阻止它们的单元测试方法很简单。
  • 用户对缺陷及其严重性的认识甚至比其他众所周知的软件缺陷更为广泛,产生了流行的和技术的新闻。
  • 现有的解释要么否定单元测试发现此类bug的能力,要么为缺陷开脱,这显然是站不住脚的。

如果我们不抓住这些机会,为自动化测试、代码质量和工程文化的重要性和影响提出强有力的理由,并让公司和同事对可避免的缺陷负责,还会发生多少可避免的、广泛存在的漏洞和故障?如果我们不采取适当的纠正措施,等待我们的将是怎样的命运转到失败和Heartbleed吗?这些借口能持续多久?它们最终会给我们带来什么?

如果人们拒绝解决导致容易预防的灾难性缺陷的真正问题,那么经常被引用的开源软件的基本原则——莱纳斯定律“只要有足够的眼球,所有的bug都是肤浅的”又有什么用呢?

基于多年的经验和可靠的证据工作代码,我一直在努力生产合理推理的产品,以苹果补丁和测试tarball和heartbeat_test.c的形式,为OpenSSL (http://goo.gl/1F7SKs)来支持我相当直接的主张:一个单元测试文化最有可能阻止这场灾难转到失败以及Heartbleed安全漏洞。

像Apple SSL/TLS漏洞和Heartbleed漏洞这样引人注目的失败是展示自动化测试的好处的最佳机会;演示人们可以应用于现有代码的技术方法;为了说明产生不良习惯和bug的更大的,通常是文化上的根本原因。鉴于现代社会对软件的依赖程度,软件从业者社区必须让其成员对未能遵守旨在减少可预防缺陷发生的基本最佳实践负责,无论这种责任是非正式的,而且必须向前迈进,不是为了惩罚错误,而是帮助解决导致此类缺陷的根本原因。如果你看到什么,说出来!

进一步的阅读.这篇文章是基于我的演讲“在苹果中发现不止一个相同的蠕虫”(http://goo.gl/F0URUR),相应的材料,5678摘录自我的博客文章(http://mike-bland.com/2014/04/15/goto-fail-tott.html).

图5是由凯瑟琳·拉普拉斯,基于作者从测试组/EngEDU Noogler单元测试讲座幻灯片的图像草图为新谷歌工程师。

回到顶部

致谢

我最深切地感谢谷歌的前同事,波士顿自动化测试Meetup的新同事,以及我只在网上认识的慷慨的熟人:David Plass, Isaac Truett, Stephen Vance, RT Carpenter, Gleb Bahmutov, Col Willis, Chris Lopez和Antoine Picard。感谢AutoTest meeup和AutoTest Central博客的Sarah Foster提供了一个讨论这个问题的论坛。感谢Guido van Rossum, George Neville-Neil和Martin Fowler对我工作的支持。

ACM队列的q戳相关文章
queue.acm.org

安全比你想象的要难得多
约翰·维加和马特·梅西耶
http://queue.acm.org/detail.cfm?id=1017004

九个即时通讯帐户和计数
乔·希尔德布兰德
http://queue.acm.org/detail.cfm?id=966720

浏览器安全案例研究:外观可能具有欺骗性
耶利米·格罗斯曼,本·利夫什茨,丽贝卡·贝斯和乔治·内维尔-尼尔
http://queue.acm.org/detail.cfm?id=2399757

回到顶部

参考文献

1.苹果(aapl . o:行情)。Xcode概述,2014;http://bit.ly/1kXUAzD

2.Arthur, C.苹果的SSL iPhone漏洞:它是如何发生的,下一步是什么?《卫报》,(2014年2月25日);http://www.theguardian.com/technology/2014/feb/25/apples-ssl-iphone-vulnerability-how-did-it-happen-and-what-next

3.奥尔巴赫,d,一个非常愚蠢的人。板岩(2014年2月25日);http://slate.me/1o75yGs

4.贝洛文,S.M.后藤失败。SMBlog(2014年2月23日);https://www.cs.columbia.edu/~smb/blog/2014-02/2014-02-23.html

5.布兰德,M.测试认证,2011;http://mike-bland.com/2011/10/18/test-certified.html

6.《厕所上的测试》,2011;http://mike-bland.com/2011/10/25/testing-on-the-toilet.html

7.布兰德,M. Test雇佣兵,2012;http://mike-bland.com/2012/07/10/test-mercenaries.html

8.布兰德,M. AutoTest Central, 2014;http://autotestcentral.com/small-medium-and-large-test-sizes

9.Dijkstra, e。一个反对GO TO声明的案例。Commun。ACM 11, 3(1968年11月),147148;http://www.cs.utexas.edu/users/EWD/ewd02xx/EWD215.PDF

10.可测试安全性:证明SSLVerifySignedServerKeyExchange ()是可测试的,2014;https://github.com/landonf/Testability-CVE-2014-1266

11.谷歌公司。太多的测试。谷歌测试博客(2008年2月21日);http://googletesting.blogspot.com/2008/02/in-movie-amadeus-austrian-emperor.html

12.格林菲尔德:为什么苹果的电源线总是断。电线(2012年7月30日);http://www.thewire.com/technology/2012/07/why-apples-power-cords-keep-breaking/55202/

13.兰利,A.苹果的SSL/TLS漏洞。紫罗兰帝国(2014年2月22日);https://www.imperialviolet.org/2014/02/22/applebug.html

14.Ray, C.K. TDD和签名SSLVerifySignedServerKeyExchange。探索敏捷解决方案:用敏捷实践进行软件开发(2014年2月23日);http://agilesolutionspace.blogspot.com/2014/02/tdd-and-signed-sslverifysignedserverkey.html

15.iOS SSL漏洞是故意的吗?Schneier谈安全:一个涵盖安全和安全技术的博客(2014年2月);https://www.schneier.com/blog/archives/2014/02/was_the_ios_ssl.html

16.从苹果的#gotofail安全漏洞中吸取教训。Arie van Deursen:软件工程的理论与实践(2014年2月22日);http://avandeursen.com/2014/02/22/gotofail-security/

回到顶部

作者

迈克平淡从2005年到2011年,我是谷歌的软件工程师。在从事web搜索基础设施工作之前,他领导了测试和修复小组;是测试雇佣兵、测试技术和构建工具团队的成员;并且对于带来工程文化的改变是有帮助的,这使得彻底的开发人员测试被接受的文化规范。他不代表谷歌以任何身份,他是伯克利音乐学院的学生。http://mike-bland.com/

回到顶部

数据

F1图1。的握手算法转到失败bug。

F2图2。重复的握手算法立即出现在有错误的块之前。

F3图3。握手算法提取到它自己的函数。

F4图4。SSLVerifySignedServerKeyExchange ()提取握手算法后。

F5图5。小型/中型/大型测试策略。

回到顶部

UT1表格受影响系统和安全更新的时间表。

回到顶部


版权归所有者/作者所有。授权ACM出版权利。

数字图书馆是由计算机协会出版的。版权所有©2014 ACM, Inc.


评论


Peter Kriens

我非常赞同单元测试,甚至可能更赞同复制粘贴编码的弊端。

然而……这个错误在我的Eclipse工作空间中是一个闪亮的红色错误,因为简单的静态分析可以检测到它。关于单元测试还有更好的理由…


迈克尔平淡

部分原因是这个bug可能会以另一种形式出现,比如括号不匹配。静态分析虽然是一个非常有用的工具,它可能会捕捉到这个bug的一个表现形式,但很可能不会捕捉到不匹配的大括号。单元测试会有。无论如何都应该调用一个单元测试,比如我为本文编写的概念证明测试,以确保在各种虚假输入情况下触发正确的故障点。然后是消除重复的设计压力,我认为这是导致这个bug的直接原因。

不管怎样,这里似乎既没有单元测试也没有静态分析,甚至可能没有代码审查(或者,最好的情况是,差异太大,审查人员看不到隐藏的错误)。这指向了我所提出的更深层次的文化问题,不合格的代码质量表明开发(可能是企业)文化没有足够认真地对待其社会责任,或者至少在这种情况下有一个危险的失误。把大部分的媒体带宽花在讨论测试有多困难,或者代码有多好,这无助于解决问题,因为这不仅仅是一个技术问题。此外,我们需要人们说些比“X会抓住它”或“goto是e-ville”或“没人应该再用C了”更多的话。这些反应都不足以帮助解决问题。

还有什么更好的理由支持单元测试呢?说真的,如果它们真的存在,请分享。我们需要更具体、更有说服力的论证,特别是单元测试的价值,以及一般的代码质量实践的价值。请记住,借用杰弗里·摩尔(Geoffrey Moore)的《跨越鸿沟》(Crossing the chasm)中的比喻,在鸿沟的另一边,纯粹理性的论证往往是无效的。这样的呼吁得到了志同道合的创新者和早期采用者的认可(摩尔在书中描述过),但其他人需要更多的例子,最好是经验(因此需要概念验证测试)。

我写这篇文章的部分动机是为了激励更多的人分享他们具体的观点和经验,即使只是在他们自己的公司内部。像这样的bug,我们既可以清楚地指出代码,又可以清楚地指出下游的影响,提供了其他任何机会来证明代码质量的重要性,特别是单元测试是我们可以使用的最好的工具之一,可以在早期防止大量真正直接的编码错误——如果做得好,还可以产生大量有益的二级影响。我还给Martin Fowler写了一篇题为“Goto Fail, Heartbleed, and Unit Testing Culture”的文章,链接在文章的最后一节。(这篇文章共七页,包括图片;另一篇从Chrome上打印出来的文章,去掉了结尾的致谢,只有47页。)


显示所有2评论

Baidu
map