就在不久以前,我房地产界的好朋友Kirk阅读了Tracy Kidder的《新机器的灵魂》。这本书讲述了Data General公司的工程师们如何在创纪录的时间里生产出Eclipse计算机。Kirk认为这是一本有趣的书,写得很好;但是对其中高压力的生产计划和精疲力竭的人们感到难过。他说了一句让我十分意外的话:“我无法相信Kidder所描述的这种高强度的日程安排是真的,没有人能长久地像那样工作。”
我该怎样向一个与高科技领域没有任何联系的人解释,日程安排一直都是我们最头痛的事;在我的以及几乎所有我认识的工程师的职业生涯中,我们做的每一个项目的最后期限都是反复无常并且不可能完成的?最近几年,时间线收缩得更多,以今天的标准来看,Kidder的叙述甚至可以说是过于温和的。
我由此想到,不是身在技术行业的人对于我们如何被不可能完成的最后期限逼得发疯也许真的一无所知。我们的行业很独特吗?还有多少其他行业也有这样长期、无情的压力以使事情做得更快?经常性的、没有报酬的加班是否也是其他经济部门的主题?
较完善的项目管理软件于20世纪80年代出现。任何人都可以输入复杂的PERT(计划评审法)和甘特(Gantt)图。谁能成功地运用这些?我见过无数的开发人员试图围绕由市场设定的最后期限去建立时间表,他们希望这个时间安排具有可信度,但心里完全清楚是不可能的。我上中学的时候,耶稣会的教士们总在周五下午寄来成绩单,我们会从邮箱抽出成绩单,等到周一再重新塞回去,这样周末就不会被毁掉。这只是个孩子气的小花招,来推迟不可避免的事情;而这正是工程师们所做的。
项目进度规划软件被宣传为原始手工工具的进步。现在,我们能更快速地制造错误数据。这就是计算机的美妙之处:以前需要几秒钟,甚至几分钟去犯一个错误,现在一秒钟内就可以产生几千个错误。
人们写软件已超过50年之久,开发嵌入式系统也有30年了。这段时间里不变的是:日程计划紧缩下的性能提升。
我们尝试处理3件相互冲突的事:不可能完成的日程、过多的预期功能、质量。如果去掉3条腿中的1条,这个项目就会失去价值。我们能够在出货时还存留很多bug吗?如果答案是“是”,那么按时交付将会非常容易。我们能忽视出货时间吗?如果拥有无限的时间,我们就能完善每项功能。
这纠结的3者从一开始就成为隐患,而开发人员和管理人员却无法认识到矛盾所掩盖的事实。老板无一例外地想要所有的3条腿:按时交付、完美的质量、无穷的功能。但他不可能得到所有。
合乎逻辑的想法是,我们必须强调功能,因为日程计划和质量问题总是没有商量余地的。利用需求淘汰法来识别并去除那些实际上并不需要的功能。用条理化的方式建立系统,这样即使落后于计划,仍然可以拿出能良好完成大多数重要功能的产品。
当然,还有其他因素影响开发环境:资源。合用的工具、足够多的优秀开发人员、开明的管理团队,这些构成了我们要完成项目所需的基础架构。
20世纪里我们学习如何建立嵌入式系统,但管理上却一直没有搞清楚资源在所开发项目中的恰当位置。工程项目通常被看作如同是在生产线上制造小玩意。需要更多产品吗?那就加入更多的人和更多的机器。但是这在软件工程领域根本行不通。
Fred Books在他的《人月神化》(注:“人月”指一月人工)一书中展示了一个现象:给一个已经滞后的软件项目增加人员,这总会致使其更加滞后。两个开发人员之间只有单一的通信渠道,但当增加工程师时,备忘/会议/电子邮件的链接数量将随人数的平方增长。
IBM发现,当项目的规模扩大,软件生产率由于同样的原因会明显下降。他们的调查显示代码产量(行/天)随着项目的扩大以数量级降低。
Barry Boehm的建设性成本模型是最著名的软件规划预测模型,它也显示时间线比固件大小增长得快得多。将代码行数乘以2,则交付时间的增加将远远超过一倍。有时会更多。
然而,当一个项目出现麻烦时,“再雇些人回来”似乎是普遍应用的管理格言。但就是不起作用。
难道没有希望了么?我们的项目注定要失败?这种在《新机器的灵魂》中贴切描述的压力是否就是我们的命运?
随着项目复杂度迅速增长,很明显,除非我们投身一种全新的开发模式,否则在过去的半个世纪里学到的关于软件工程的一切会让我们停滞不前、退化并最终失败。接受新思维模式(以及已被验证的旧模式)的那些公司将会获得成功。特别有两方面对新的理解十分关键,就是本文将要谈到的重用和工具。
工具
20世纪40年代,所有的软件用机器码写成。50年代见证了首个编译语言:Fortran,几乎是在一夜之间提高了编程效率。使用Fortran的代价是更大、更慢的代码,这在当时被过多的工程师认为是不可接受的。但是那些接受了Fortran的人则证明是未来的先驱。
今天,关于建模、C++和Java,我们听到了类似的争论。太慢、太大。但很明显,继续制造出几百万行的C程序不能解决任何问题;要赶上日益增长的产品需求必须提高生产率,而手工编写代码不再提供这样的提升。
高级语言给予我们抽象以及在更高层次做项目的能力。抽象是未来的基础。我们再也不能去为比特和字节烦恼,因为这样的代价太高。不管你喜欢与否,Windows API的确给台式机开发者提供了大量丰富的资源。
各种风格的工具能够使我们从较底层的细节抽象出来。第一个Fortran编译器,按今天的标准来看简单得可笑,给予了50年代的工程师们强大的武器。现在我们有了更多的选择。
我们基本上接受编译器带来的额外开销。其他抽象能力更强的工具会带来更大的开销,但也带来了更快、更好的交付能力。建模工具,如UML,在一些领域以获得成功。太少的开发人员充分了解LabView和MATLAB,而它们是嵌入式领域很重要的角色。
能够自动搜寻bug的工具将会进一步提高程序员的生产率。Coverity、Klocwork、Polyspace、Green Hills以及GrammaTech公司都在推动其寻找运行时问题的静态分析器。这些工具当然无法找到所有的bug,但它们提供了一项对付日程计划的武器,虽然到目前为止的市场渗透率还很低。
重用
能让我们更快地写出更多代码的工具只是解决方法的一部分。显然,迫切需要一种新的重用模型。由百万行代码构成的产品,如果一行一行编译链接的话,那就太慢了。
把软件工程中某些出色的新发展挡在门外,那么未来肯定只能属于重用。除非我们能讨来、借来、偷来或者买来大量的代码库,否则永远都得靠自己去写每一行。这是难以忍受的。
重用不仅仅是把以前项目中的一些代码保存起来,而是要回收利用超过20%的固件。百万行以上规模的系统需要最大限度的重用。
让我们定义几个专门用语来说明什么是重用,什么不是。软件回收是指利用并非为重用而设计的代码。即在旧资源中取出一部分并放入新的应用中。
代码沿用是将固件从以前的项目移植到新项目中。和回收利用一样,这通常是一种有些鲁莽的源码使用。
真正的重用是在建造系统的时候,一次建立一个组件,而不只是一行。这些块已明确定义,这样就不需要深入到内部来进行调整、调试或优化。Richard Selby发现,当移植旧代码到新项目时,如果超过25%被修改,就不能有效缩短项目时间。重用只有在大块作用时才最有效。
一个程序包必须至少重用3次,才可看作是真正可重用。换句话说,域分析会比较难。我们还没有聪明到能真正理解应用程序的范畴。每个域要有自己独特的功能和特点;当我们在实际中,将代码在足够广范围的应用上使用过多次以后,才能将其通用化到真正可重用的程度。
从这可以看出,重用是很昂贵的。我们花费了大量金钱来生产非常好的代码,但只有重用3次时才有所回报。我们中有多少人有足够的耐心和纪律性——以及时间——去写为了以后使用的代码?重用就像存折,如果你不向账户里存入足够多的钱,它就没有价值。你投资得越多,回报增长得越多。
何时我们能够用购买的方式得到应用程序的大部分,而不是从零开始去写?软件IC是否真的可能?
未来属于那些足够勇敢和聪明的人们,他们丢弃旧的思维模式,创造新的想法。我们将会找到利用以前写就的代码来设计产品的方法。这样做的好处显而易见,一行一行搭建系统的做法应该停止了。这也许意味着在低端应用中增加资源、存储和高端CPU;也许意味着新的工具。我们当然会用不同的方式设计系统。虽然一些实施细节目前还不明朗,但结果是非常清楚的。
最大的改变将是我们的态度,以及我们开发产品的方式。总有一天,在管理部门的支持下,我们都会认识到2件重要的事:固件是最昂贵的东西、傻瓜都可以写代码。未来属于那些寻找产品开发更好方式的开发者,而不是编程高手。
因此,我要对我的朋友Kirk和所有不是工程师的人说,我们的确在巨大的日程计划压力下工作。是你们的需求所致。你拥有的数字防抖双目望远镜、价值100美元的GPS、数字照相机,以及构成你的世界的所有其他电子产品,都来自这些在最后期限面前挣扎并开发出惊人廉价、可靠系统的工程师们。
当你使用这些系统之一的时候,偶尔也想想我们吧!我们正坐在实验室里,在为下一个版本而工作。
作者介绍:Jack Ganssle是嵌入式系统开发方面的授课者和顾问,在embedded.com的一次问卷调查中,被评选为嵌入式领域20年中最重要的人物之一;其他当选者包括Linux的创造者Linus Torvalds、Wind River公司的创始人Jerry Fiddler,以及Steve Jobs、Gordon Moore和GNU计划的发起人Richard Stallman。