第 1 章 理解软件工程
软件工艺
为了看清软件工程适用(以及不适用)的范畴,我们首先需要对软件工程有一个深入的理解。为了理解软件工程,我们首先需要了解在早期的软件工程文献中提到的那些项目。稍做研究,你就会发现一个令人惊讶的事实:这些文献中几乎没有对商用软件的报告。在所有的案例中,绝大多数都是大型国防项目或者小型科研项目。在这两类项目中,开发者通常都需要面对极其严峻的硬件/软件条件;而在现代的商用项目中,环境通常会宽松得多。
一个非常典型的例子就是美国国防部于1969年至1975年间开发的SAFEGUARD弹道导弹防御系统1。“SAFEGUARD系统的开发和部署堪称有史以来最大、最复杂的软件系统。”在项目开始的第一年(1969年),工作量为188人年;到1972年,年工作量已经达到1 261人年;整个项目的工作量共计5 407人年,平均生产率为每人年418条指令。
SAFEGUARD是一个极其庞大的软件工程项目,它也代表了当时软件工程的最高水平。它所使用的计算机硬件是专为此项目而开发的。尽管程序设计工作都是用低级语言完成的,但编码和单元测试阶段在全部工作量中所占的比重还不到20%。系统工程(需求分析)和设计各自占据了20%的工作量,其他的工作量(超过40%)则用于集成测试。
1 W. E. Stephenson,《对SAFEGUARD系统软件开发中使用的资源的分析》(An analysis of the resources used in the SAFEGUARD system software development)。收录于《软件管理教程》(Donald J. Reefer, Tutorial: Software Management, IEEE Computer Society, 1981)。
软件工程的悖论
软件工艺
在试图理解软件工程时,我们需要在脑海中牢记下列两点:
像SAFEGUARD这样规模的项目属于凤毛麟角。
但软件工程正是在这些超大型项目(超过1 000人年)的基础上定义的。
同样,Fred Brooks的《人月神话》1也是建立在IBM开发OS/360操作系统的经验基础上的。所以,尽管Brooks在书中也提到了“由于人员的分工,大型编程项目碰到的管理问题和小项目区别很大”这一事实,但他的书仍然被用来支持软件工程背后的观点。
这些大型项目是真正的“系统工程”项目。这些项目通常同时包含硬件和软件的开发,其中的硬件是专为与软件协作而开发的。这一类项目有一个共通的特点:在项目的前期,软件开发者需要等待硬件的开发;而在项目的后期,则是硬件开发者在等待软件的开发。软件工程正是在这样一对矛盾中发展起来的。
等待硬件开发时,软件开发者在干什么?
在典型的软件工程项目的前期,软件开发者会有很多的时间。这时,硬件的发明或者设计尚未完成,所以软件开发者有大把的时间来做需求调研,并编写出详尽的软件设计规格书。他们根本不可能提前开始编码,因为用于执行代码的硬件环境根本还不存在(在很多较早的范例中,在这一阶段甚至连编译器和代码加载器都还不存在)。有时,连编程语言都必须到项目的后期才能选定。所以,就算设计规格书已经巨细靡遗,提前开始编码也是毫无意义的。
在这种情况下,“定义一个严格的需求获取过程,并通过这个过程生成详尽的、可复审的、一步到位的需求说明书”的做法就是有意义的。需求文档一旦完成,就可以交给设计团队;而设计团队则可以根据需求文档编写出极其详尽的设计规格书。我们都知道,硬件开发是相当费时的。就连为软件开发团队设计出一个可用的工程原型,也需要相当长的时间。所以,细致入微的设计复审也是软件开发过程中的一部分,因为软件设计团队有足够的时间来检查他们的设计。
得到可用的硬件之后,软件开发者如何加快交付的速度?
对于这个问题,最简单的答案就是:“投入大量的人手。”这也就是Steven Levy所说的“人海战术”,从SAFEGUARD项目的人力资源统计图中也可以很明显地看出这一点。一旦硬件能够投入使用,软件开发者就应该立刻动手将详细设计规格转换成代码。为了获得最高的开发效率,还需要对代码进行复审,以保证其完全与详细设计规格相符,因为任何的偏差都可能导致下游的集成阶段出现问题。
这个阶段需要大量的人手,因为整个项目都在等待软件的编码和测试。所以,从设计到代码的转换过程越快越好。早期的软件工程项目倾向于用大量的程序员来编码,但后来人们将关注的焦点转移到“使用CASE工具自动从设计生成代码”上面。之所以出现这样的转变,是因为在完成编码之后,项目组仍然需要排除代码中存在的大量错误才能让整个系统正常运转。如果代码能够从设计规格自动生成,那么集成阶段的问题就会大大减少,项目也可以更快地完成。
传统开发过程的内蕴
软件工程项目需要大量的文档。在整个项目的过程中,需要3类不同的技术人员:
分析师,负责编写需求文档;
设计师,负责创建设计规格;
程序员,负责编写代码。
在每个阶段,每份文档的作者都必须在文档中加入额外的细节,因为他们无法知道随后将要阅读这份文档的人是谁。由于无法假设阅读者的知识背景,所以唯一安全的办法就是:将作者所知道的所有细节、所有交叉引用都写在文档中。然后,文档的复审者必须仔细浏览整个文档,以确定它是完善并且明白无误的。
完善的文档也带来了另一个难题:当在实现阶段需要对需求和设计作出修改时,团队成员必须修改所有相关的文档,以保证文档与真实系统之间的一致性。软件工程项目解决这个问题的办法是:确保从需求分析到代码实现的整个过程是完全可回溯的。不论在任何时候需要作出修改,这种可回溯性都将保证相关的文档和组件能够被发现并被更新。
这种文档驱动的开发方式也影响项目中人员的工作方式:设计师不愿意主动置疑分析师的文档,而程序员对设计方案的置疑或改进建议也是不受鼓励的——对于任何一份文档的修改都需要付出高昂的代价,因此所有的修改都必须受到严格的控制。
要想控制对文档的修改,一个很好的办法就是:定义一个分层的项目人员体系,将分析师放在最顶端,设计师次之,程序员位于最低的地位。而维持这一结构的办法则是:将优秀的程序员提拔为设计师;同时让优秀的设计师担任分析师的角色。
1 Frederick P. Brooks, 《人月神话》(The Mythical Man-Month),20周年纪念版,Addison-Wesley,1995。中译本由汪颖翻译,清华大学出版社2002年出版。
本文仅用于学习和交流目的,不代表异步社区观点。非商业转载请注明作译者、出处,并保留本文的原始链接。