Richard Feynman, 挑战者号, 软件工程
源文:链接 (本文主要根据挑战者号的问题,以及Richard Feynman那对NASA严厉的批评报告,批评了不适当的“自顶向下”的设计方法,并总结了一下软件工程和其它工程的相通的一些观点。翻译水平有限,欢迎指正)
佛罗里达州,美国东部时间1986年1月28日上午11时39分,挑战者号航天飞机 执行为期6天的STS-51-L 任务,在发射后,其右侧固体火箭助推器(SRB – Solid Rocket Booster)的O型环密封圈(用于连接两节助推器)失效,泄漏出来的热汽达到了5000华氏度,直接蒸发了O型密封圈,并灼烧了毗邻的外部燃料舱,在几秒钟内,外部燃料舱出现结构连接失效,空气的动力迅速分解了航天飞机。在而航天飞机上升72秒以后,助推器脱落,导致航天发飞向侧面滑出。几乎在引航员 Michael J. Smith 发出”Uh oh” 的同时,整个航天飞机完全解体,片刻,航天飞机内部发生爆炸,所有7名宇航员罹难。 那时的我还只是一个小孩,我从电视下方滚动的新闻条目知道了这一惨剧。
在那个时候,火箭助推器工程师曾经警告过这个O型环可能存在问题,但可惜的是,NASA的管理层忽略了这个问题。美国总统里根委派罗杰斯委员会对事故进行了调查,调查成员包括著名的物理学家Richard Feynman。其不羁的态度和直来直去的方法和罗杰斯委员会的风格形成了鲜明的反差。主席罗杰斯,一个政客,评论Feynman是一个“真正的痛苦”。最后,在委员会提交的报告中,Feynman反判的观点几乎被清除了出去。并且,Feynman曾被主席威胁过要把他的名字从报告中完全除掉,但最终,他们还是同意在报告中加一个附录,但只是个人观点—— Appendix F – Personal Observations on Reliability of Shuttle。
这是一个好的报告,因为,这是一个富有才华的报告。其深深地洞察了在实现一些高可靠性的系统时的工程学中的一些很自然性的东西。是的,在这里,我并没有放上“软件工程” 的字样,只是工程。但Feynman的结论却非常和我们的软件开发有着不可分割的关系。这是最基本的东西,无论是软件工程,还是别的工程学。下面,让我们来看看,Feynman是怎么说的:
航天飞机主引擎的建造方式是自顶向下(top down),我们可以这样说。整个引擎被设计把所有的事情放在一起,而那些相关的细节上的东西在设计当时还并不是很成熟的。所以,当其中的小零件(轴承,涡轮片,散热管,等等)出现问题时,我们需要花费昂贵的代价才能找到事故的原因,也很难作出修改。要避免问题发生,需要频繁的维护和置换重要的零部件。修理很多时候不会解决真正的原因。
可见,软件开发中也一样,Bug在整个过程中存在的时间越长, 我们就越难解决这个问题。很显然,自顶向下的方法,因为在设计的时候并不熟悉实际问题,所以,Bug从设计的时候就出现了。然而,我们需要明白,需求和设计的不同之处。需求需要对产品一种清楚和良好的定义,设计则是解决如何达到需求的方法。Feynman 在这里并没有反对 功能规格说明书,他只是反对自顶向下的设计方法,比如: UML 就是蓝图 的鼓吹者。再来看看他的言论:
航天飞机主引擎是一个非常不同寻常的机器,它和以前所有的引擎都不一样。这完全超出了以前引擎制的工程经验。所以,不奇怪的,许多不同的流程和难点都会在工程中出现。然而,很不幸地,这是通过自顶向下设计,所以,那些流程和问题是很难被发现被修正的。设计要求的引擎寿命可以完成55次点火任务(相当于27,000秒的操作,也就是说,第次点火需要500秒),但事实上这并没有完成。而引擎现在则需要频繁维护,并需要经常更换重要的部件,比如:涡轮泵,轴承,金属片,等等。
“不合适的自顶向下的设计方式,导致了问题很难去发现和修正,最终没有完成设计需求,频繁性地维护”这些描述方式,听起来是不是似曾相识?我们每天在做的软件工程和这个不一样吗?Feynman 详细说明了为什么“自顶向下”的设计会让发现和解决这些问题成为那么的难和痛苦的一件事:
很多这些已被解决的问题在一开始设计时都是设计的难点。很自然地,没有人可以确定那些所有的已发现问题都能会出现,而其中一些,我们并没有根据正确的原因在正确的地方解决这些问题。
无论这是Linux内核,或是航天飞机引擎,这些设计时的基本的问题都是相通的。而“自顶向下”是其中荒唐的一个,因为,自顶向下,过度的注重了需求而忽略了现实,而那些下面非常细节的知识绝对是非常需要的,并不是所有的东西都可以抽象成出来。在他说起航空电子系统时(一个NASA的另一个部门):
该软件是采用了从底向上的方法被小心地做了检查。首先,每一行代码都被检查过,然后,代码段和模块和一些详细的功能被验证过。而检查范围在一步一步地被扩大,直到新的改变被组合进来最终成为一个完整的系统。这个过程最终的完整的输出成为了最终的产品,成为了新的release。这个部门完全以一种中立的态度,把软件作为一个敌对方,不停地测试,校验,就像自己就是这个软件的用户一样。
是的,这就是1986年Feynman告诉大家的——Unit Test(单元测试),今天,Unit Test成为了软件开发活动中最最重要的一个环节(也许你以为是Coding)。并不单单只是Unit Test,“步步为营的增量式”和“以敌对的态度”,都是值得我们所学习的。我们经常听到有人在抱怨软件道,因为软件工程还太年轻了,还有很多知识我们还没有得到,所以总是那么多问题。这完全是胡说!我们痛苦是因为,我们 总是忽略 早就确定了的, 早为人所熟知, 以经历和实践去证明一切的方法。 当然,在这方面,我们的管理层也需要负责,尤其是那些紊乱的时间进度,错误的激励机制,低档次的招聘,和一些让士气受挫的制度,等等。“管理”和“工程”间的紧张关系最终成为了糟糕的管理。Feynman在他的报告中也谈到了这点,下面其中的一小段话:
总而言之,计算机软件检查系统和最负责的态度。是的,那里并没有那种自欺欺人而不顾固体燃料助推器的标准。但可以肯定的是,有关管理部门最新的建议,建议取消此类复杂而昂贵的不必要的测试。
这只是其中的一个小段。我把其挑出来是因为其一针见血地指出了观点,比如“最负责的态度”,以及“逐步的自欺欺人”。我建议你读一读报告全文, 可以让你得到很多真相。关于软件工程,下面是几个主要观点:
- 工程仅当在和其管理有好的关系的时候才能好。
- 大型的从上从前端的设计是愚蠢的。
- 软件工程和其它传统的工程学是一样的。
- 可靠的系统由几近残酷的测试,增量式的自底向上的工程,以及高负责的态度来共同保证。
这篇报告中,还有很多不错的观点,如果你感受到了,欢迎你告诉我。