escape
驱动老牛
驱动老牛
  • 注册日期2002-02-01
  • 最后登录2004-08-20
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
阅读:734回复:5

《人月神话》节选

楼主#
更多 发布于:2003-11-26 15:54
《人月神话》节选

http://www.umlchina.com
《人月神话》节选(文中图略)
Fred Brooks 著,Adams Wang 译

Fred Brooks 在1956-1965 之间领导IBM System/360 大型电脑的开发计划,由于复杂的需求,以及当时软件工程水平低下,使得System/360 的开发工作陷入了前所未有的、最可怕的“软件开发泥潭”,并催生了最著名的失败论著--《人月神话》(\"The Mythical Man-Month\")。1975 年出版的《人月神话》一书,是软件工程经典名著。1995 年,为纪念该书发行20 周年,第二版上市,第一次发行印数就达250,000 册。1986 年, Brooks 发表了重要文章──“ No Silver Bullet”,激起众多人士对软件危机与奇迹的好奇与争论论,而\"No Silver Bullet\"也成为烩炙人口的名词,一直持续到今天。《人月神话》的中文译本即将发行,译者为UMLChina 的Adams Wang,这是翻译草稿的片段。

焦油潭( The Tar Pit Pit)
史前史中,没有别的场景比在焦油潭中垂死挣扎巨兽的场面更生动逼真。上帝见证着恐龙、猛犸、剑齿虎与焦油束缚的搏斗。它们越是挣扎的猛烈,焦油纠缠的越紧,没有任何猛兽足够的强壮或者具有足够的技巧能挣脱,最后都沉入了坑底。
过去几十年的大型系统开发犹如这样一个焦油潭,许多大型和强壮的动物在其中剧烈的挣扎。大多数开发出了可运行的系统――其中,非常少数的满足了目标、时间安排和预算。各种团队,大型的和小型的,庞杂的和精干的,一个接一个在焦油潭中被束缚。看上去没有单个的问题会导致困难,任何一个都能被解决。但是它们的相互纠缠和同时累积使行动越来越慢。每个人似乎都被问题的麻烦程度感到惊讶,并且很难洞悉问题的性质。然而如果我们想解决问题,就必须试图去理解它。因此,首先让我们来识别系统开发这个职业以及它内在的乐趣和苦恼。


编程系统产品
某个人在报纸读到新闻,讲述两个程序员如何在改造的车库中编写了超过大型团队工作的重要程序。
接着,每个编程人员准备相信这样的神话,因为他知道自己能以超过产业化团队的1000 语句/年的生产率来构建任何程序。
为什么并不是所有的产业化队伍没有被专注的二人组所替代?这里必须看一下产出的是什么。
图1.1 (略)
在图1.1 的左上部分是程序(Program)。它自己是完整的,准备在作者开发的系统平台上运行。这通常是车库中产生的产品,以及单个的程序员在估计生产率时使用的标准。存在两个途径使程序转变成更有用的,但是成本更高的东西。它们表达为图中的边界。水平边界以下,程序变成编程产品(Programming Product)。这是可以被任何人运行、测试、修复和扩展的程序。它可以在多种操作平台上,供多套数据使用。欲成为通用的编程产品,程序必须以通用的风格来编写。特别的,输入的范围和形式必须推广以适用于所有合理采用的基本算法。接着,程序必须被彻底测试,以使它可以被依赖。这意味着一个能探测输入边界和范围的详实的测试用例库必须被准备、运行和记录。最后,程序向程序产品的提升需要完备的文档,以使每个人均可以使用、修复和扩展。作为经验数据,相同功能的编程产品的成本至少是经debug 程序的三倍。
垂直边界的右边,程序变成编程系统(Programming System)中的一个组成部件。它是在功能上协作、具有规范格式的、相互交互的程序集合,从而通过组装形成整个系统。欲成为编程系统部件,程序必须编写使输入和输出一致于精确定义接口的语法和语义。同时程序需要设计成满足预先定义的资源限制――内存空间、输入输出设备、计算机时间。最后,程序必须同其它系统部件,以任何所设想的组合进行测试。
测试的范围非常广,因为根据组合测试用例会不断增加。相同功能的编程系统部件的成本至少是独立程序的三倍。如果系统具有多个部件,成本会增加得更多。
图1.1 的右下部分代表编程系统产品(Programming Systems Product)。它同以上的所有情况不同,成本高达九倍。然而,它是真正有用的产品,大多数系统编程工作的目标产出物。

职业的乐趣
编程为什么有趣?作为回报,它的从业者期望着什么样的快乐?
首先是一种创建事物的纯粹的快乐。如同小孩从玩泥巴中感到愉快一样,成人喜欢创建事物,特别是自己的设计。我想这种快乐一定是对上帝创造世界的映射,一种呈现在每个独特、崭新的叶片和雪花的喜悦。
第二是创建对其他人有用东西的欢乐。内心深处,我们需要其他人使用我们的劳动成果并感到有所帮
助。从这个方面,编程系统与小孩用粘土为“爸爸办公室”捏制铅笔盒没有本质的区别。
第三是将相互啮合的部分组装在一起,并看到它们精妙的工作,实现预先所内建的结果,所体现的魔力。程序化的计算机具有像弹珠游戏或点唱机所有的令人入迷的魅力。
第四是学习的乐趣,来自于该工作的非重复的特性。问题在某个或其它方面总不同,解决的人员可以学习新的事物:有时是实践上的,有时是理论上的,或者两者兼有。
最后,是在如此易于驾驭的介质上工作的乐趣。程序员,像诗人一样,几乎工作在纯粹的思考中。程序员凭空地通过实现想象来建造自己的城堡。很少有创造的媒介如此的灵活,如此容易的完善和重建,以及如此容易的实现概念上的构架。(如同我们将看到的,容易驾驭的特性具有它自己的问题)然而程序同诗歌不同,是实实在在可以移动和工作的,以及产生独立于程序的可见输出。它打印出结果,绘制图形,发出声音,移动支架等。神话和传说的魔术在我们的时代变成了现实。即在键盘上键入正确的咒语,显示屏幕活动起来,显示从来没有或者存在的事物。
编程非常有趣,因为它满足我们内部深处的创建渴望和愉悦了所有人共同的感受。职业的苦恼然而并不全部都是喜悦,了解一些固有的烦恼能使它们出现时,更容易忍受。
首先,必须追求完美。计算机也以这种方式来变戏法。如果咒语的一个字符、一个停顿没有与正确的形式严格一致,魔术不会出现。人类不习惯于完美,只有很少的人类活动需要它。我认为,向完美的方式进行调整是学习编程的最困难的部分。
其次,其它的人设定了目标,供给资源,提供信息。编程的人员很少控制工作的环境,甚至工作的目标。用管理的术语而言,某人的权威对他所承担的责任是不充分的。不过,看起来在所有的领域中,对完成的工作,很少能提供与责任一致的正式的权威。而现实情况中,工作推进的动力需要实际(相对于正式)的权威。
对其他人的依赖的影响比较突出,这对系统编程人员尤其痛苦。他依赖者其他人的程序。通常这些程序设计得不合理,实现拙劣,发布不完整(没有源代码或测试用例),或者文档记录得很糟。所以系统编程人员必须花费时间研究和修改在理想情况下应该完整、可用和有用的东西。
下一个烦恼――设计概念是有趣的,但寻找琐碎的BUG 仅仅是一项工作。伴随着创造性活动的,往往是枯燥、沉闷的时间,艰苦的劳动;程序编制工作也不例外。
另外,人们发现调试查错具有线性的收敛,或者更糟的是具有二次方的复杂度。所以,测试一拖再拖,寻找最后一个错误比第一个错误花费更多的时间。
最后一个苦恼,有时也是一种无奈――当某人花费大量劳动的产品在完成以前或完成时,显得陈旧。可能同事和竞争对手已在追逐新的、更好的设想。可能替代的方案不仅仅在构思,而且已经在安排了。
现实的情况通常比上述的好一些。当产品开发完成时,新的、更佳的产品通常并不可用;仅仅是被大家所谈论。另外,它同样需要数月的开发时间。事实上,仅现实需要时,才要求使用最新的设想。因为所实现系统的价值已能体现回报,满足要求。
诚然,产品开发所基于的技术不断在进步。一旦设计被冻结,在概念上就已经陈旧了。不过,实际产品的实现需要阶段化和进行度量。实现的落后情况需要根据其它现有的系统进行测量,而非未实现的概念。
我们所面临的挑战和任务是在现实的时间、有效的资源范围内,寻找实际问题的切实可行的解决方案。
这,就是编程。一个许多人痛苦挣扎的焦油潭以及一个乐趣和苦恼共存的创造性活动。对于许多人而言,其中的乐趣远大于烦劳。本书的剩余部分试图为通过这样的焦油潭搭建一些木板小径。


神话的人月( The Mythical Man Man-Month Month)
在众多软件项目中,时间进度的缺乏是造成项目偏移的最主要原因,比其他所有因素加起来影响还大。
导致这种普遍性灾难的原因是什么呢?
首先,缺乏有效的估算技术。更加严肃的讲,它反映了一种无声,但并不真实的假设――一切都将运作的很好。
第二,我们采用的估算技术,错误地将进度与工作量相混淆,隐藏了人和月是可以互换的假设。
第三,由于对估算不确定,所以我们缺乏一种谦逊的坚持。
第四,对安排的进度缺少跟踪和监督。在其他工程领域被验证的技术和常规的程序在软件工程中往往是快速演化的。
第五,当进度的偏移被识别时,自然(且传统)的反应是增加人力。这就像使用汽油灭火一样,只会使事情更糟。越来越大的火势需要更多的汽油,从而开始了一场注定导致灾难的循环。
进度监督是另一篇论文的主题。本文我们对该问题的其他方面进行更详细的考虑。
乐观主义所有的编程人员都是乐观主义者。可能这个现代的魔术特别吸引那些相信美满结局的人。可能成百上千琐碎的挫折赶走了所以的人,除了那些习惯上只关注结果的人。可能仅仅因为计算机还很年轻,程序员更加年轻,而年轻人总是些乐观主义者。但不管所选择的过程如何工作,结果是勿庸置疑的:“这次它肯定会运行。”或者“我刚刚找出了最后一个错误。”所以系统编程的进度安排背后的第一个假设是:一切将正确运作。即每一项任务仅耗费它所“应该”花费的时间。
对这种在编程人员中乐观主义的弥漫理应受到慎重的分析。Dorothy Sayers 在她的《The Mind of the Maker》一书中,将创造性活动分为三个阶段:构思、实现和交流。书籍、计算机、或者程序的出现是首先作为一个构思概念或模型,在时间和空间之外构建,而在作者的脑海中完成。它们通过钢笔、墨水和纸,或者通过电线、硅片和铁氧体,在现实的时间和空间中被实现。当某人阅读书本、使用计算机和运行程序的时候,创作过程得以结束,从而与创意的作者相互交流。
以上Sayers 的阐述不仅仅可以描绘人类创造性活动,而且描述基督教义的形成过程。它可以协助我们日常的工作。对于创造者,我们构想的不完整性和不一致性只有在实现的过程中才能发现。因此,对于理论家而言,书写、试验以及“工作实现”是基本、必要的部分。
许多创建性的活动中,实施的媒介很难掌握,如木头切割、油漆、电器安装。这些媒介的物理约束限制了能被表达的构思,同样它们对实现造成了预料之外的许多困难。
由于物理媒介和构思背后的不完善,创造性的实现需要花费大量的时间和汗水。对遇到的大部分实现上的困难,我们总是责怪那些物理的介质;因为它们并不是顺应“我们”构思的思路,且我们的骄傲主观引导了我们的判断。
相应的,计算机编程基于非常容易掌握的介质。编程人员凭空通过思考来创建程序,即概念和和非常灵活的表达。因为介质的易于驾驭,我们期待在实现的过程中不会遭遇困难;因而造成了乐观主义的弥漫。而由于我们的构思是具有缺陷的,因此会有Bug;所以我们的乐观主义并不是得到认可的。
在单个的任务中,“一切都将运转正常”的假设在时间进度上具有随机性。由于将遭遇的延迟具有一定的概率分布,所以事实可能如计划安排的那样,而“不会延迟”仅具有有限的概率。大型的编程工作,或多或少包含了许多任务,某些任务间具有前后的次序。而一切正常的概率变得非常小,接近于无。
人月第二个谬误的思考方式是在估计和进度安排中使用的工作量单位:人月。成本的确随产品的人数和时间的长短变化非常大。进度却不是如此。从而使用人月作为测量一项工作的规模是一个危险和带有欺骗性的神话。它暗示着人数和时间是可以相互代替的。
人数和时间的互换仅仅适用于某个任务可以被分解给参与的人员,并且他们之间不需要相互交流(图2.1)。这在割小麦或收获棉花时是可行的;而在系统编程中近乎不可能。
图2.1(略)
当任务由于次序上的限制不能分解时,人手的添加对进度没有帮助(图2.2)。无论多少个母亲,孕育一个生命都需要十个月。由于调试、测试的次序要求,许多软件均具有这种特性,图2.2(略)
对于可以分解,但子任务之间需要相互沟通、交流的任务,沟通的工作量必须添加到待完成的工作中。
因此,相同人月的前提下,使用人数的增加来减少时间的最好情况也较未调整前也要差一些(图2.3)。
图2.3(略)
沟通所增加的负担由两个部分组成,培训和相互的交流。每个成员需要进行技术上的、项目目标以及总体策略上的培训。这种培训不能被分解,因而这部分增加的工作随人员的数量线性的变化。
相互之间交流的情况更糟一些。如果任务的每个部分必须分别同其他的部分单独的协作,则工作量按照n(n-1)/2 递增。单对单交流的情况下,三个人工作量是两个人的三倍;四个人则是两个人的六倍。而如果需要在三个、四个人之间召开会议,大家共同的解决问题,情况变得更糟。所增加的沟通的工作量可能会完全抵消对原有任务的分解,则我们会被带到图2.4 的境地。
因为软件构建本质上是一项系统工作――相互错综复杂关系下的一种实践――沟通、交流的工作量非常大,它很快会支配源于任务分解所节省下来的个人时间。从而,更多的人手的添加,实际上延长了,而非缩短了时间进度。
系统测试
时间进度中,没有其他的部分所受到次序限制的影响,比构件调试和系统测试所受到的影响彻底。而且,所需要的时间依赖于所遇到错误、缺陷的数量和难以捕捉的程度。理论上,缺陷的数量应为零。由于乐观主义,我们通常希望缺陷的数量比实际出现的要少。因此,系统测试进度的安排常常是编程中最不合理的部分。
对于软件任务的进度安排,以下的经验法则我使用了很多年:
1/3 计划
1/6 编码
1/4 构件测试和早期系统测试
1/4 系统测试,所有的构件可用
在许多重要的方面,它与传统的进度安排方法不同:
分配给计划的时间较寻常的多。即使如此,仍不足以产生详细和稳固的计划说明,且不足以包括对全新技术的研究和摸索。
对所完成的代码的调试、测试,投入近一半的时间,比平常的安排多许多。
容易估计的部分,即编码,仅仅被给予六分之一的时间。
通过对传统项目进度安排的研究,我发现很少项目允许为测试计划一半的时间,但大多数项目实际上为上述目的花费了一半的时间。它们中的许多在系统测试之前,仍能保持进度;或者说,除了系统测试,进度基本能保证。
特别的,不能为系统测试安排足够的时间,尤其是一场灾难。因为延迟产生于项目快完成的时候;直到项目的发布日期,才有人发现进度上的问题。坏消息,没有任何预兆、很晚的出现在客户和经理面前。
另外,此时此刻的延迟具有不寻常的、严重的财务以及心理上的反馈。项目配置了充足的人员,每天的人力成本达到了最大的程度。更重要的是,软件是用于支持其他的商业活动(计算机硬件的到货,新设备、服务的上线等等),延误这些活动的商业代价相当高――软件已经到了即将发布的时间。
实际上,上述的二次成本远远高于其他开销。因此,在早期进度策划时,允许充分的系统测试时间是非常重要的。
空泛的估算
观察一下编程人员,同厨师一样,某项任务的计划进度可能受顾客要求的紧迫程度所支配,但紧迫程度无法控制实际的完成情况。约定好在两分钟内完成一个煎蛋,看上去可能进行得非常好。但当它无法在两分钟内完成时,顾客有两个选择:等待或者生吃煎蛋。软件的顾客具有相同的选择。
厨师还具有其他的选择;他可以将火开大。其结果常常是无法“挽救”的煎蛋――一面已经焦了,而另一面还是生的。
现在,我并不认为软件经理内在的勇气和坚持不及厨师,或者不及其他工程经理。但为了满足顾客期望的日期,所进行的不合理进度安排,在软件的领域却较其他的任何工程领域要普遍的多。而使用非量化方法,少的可怜的数据支持,主要借助于软件经理的直觉的情况下,很难产出健壮的、可靠的、规避风险的估算。
显然我们需要两种解决方案。开发并推行生产率图表、缺陷率、估算规则等等。整个组织最终从这些数据的共享上获益。
在基于可靠基础的估算之前,项目经理需要挺直腰杆,坚持他们的估计,确信自己的经验、直觉总比从期望派生出的估计要强。
重复产生的进度灾难
当一个软件项目落后于进度时,通常的做法是什么呢?自然是添加人力资源。如图2.1 至2.4 所显示的,这可能有所帮助,也可能无法解决问题。
我们来考虑一个例子。设想一个估计需要12 个人月的任务,分派给3 个成员4 个月,在每个月的末尾安排了可测量的里程碑A、B、C、D(图2.5)。
现在假定两个月之后,第一个里程碑没有被达到(图2.6)。项目经理面对的选择方案有哪些呢?
假设任务必须按时完成。假设仅仅是任务的第一个部分估计的不得当,即图2.6 确切的表达了上述情况。则剩余了9 个人月的工作量,时间还有两个月,即需要4 1/2 的人力资源。所以在原分派3 个人的基础上增加2 个人。
假设任务必须按时完成。假设整个任务的估计偏低,即图2.7 描述了该情形。那么还有18 个人月的工作量以及2 个月的时间。将原来3 个人增至9 个人。
重新安排进度。我喜欢P. Fagg,一个具有丰富经验的硬件工程师的忠告:“避免小的偏差(Take no small slips)”。也就是指,新的进度安排中分配充分的时间,以确保工作能仔细、彻底的完成;从而无需重新的确定时间表。
削减任务。现实情况中,一旦开发团队观察到进度的偏差,总是倾向于对任务进行削减。当项目延期所导致的后续成本非常高时,这常常是唯一可行的方法。项目经理的相应措施是仔细的、正式的调整项目,重新安排进度;或者默默的注视着任务项由于轻率的设计和不完整的测试而被剪除。
前两种情况中,坚持不经调整的任务在四个月中完成是灾难性的。考虑重复生成的工作量,以第一种为例(图2.8)。不论两位新的员工多么有能力,在多短的时间内被雇用,他们均需要接受一位有经验的职员的培训。如果培训需要一个月的时间,那么三个人月会被投入到原有进度安排以外的工作中。另外,原先划分为三个部分的工作,要求重新分解成五个部分;从而某些已经完成的工作会丢失,系统测试必须被延长。因此,在第三个月的月末,7 个人月的工作仍然残留着,但此时只有5 个有效的人月。如同图2.8所示,产品还是会延期,如同没有增添任何人手(图2.6)。
期望四个月内完成项目,仅仅考虑培训的时间,不考虑任务的重新划分和额外的系统测试,在第二个月末需要增添4 个,而非2 个人员。如果考虑任务划分和系统测试的工作量,则还需增加人手。现在所拥有的不是3 人的队伍,而是7 人以上的团队;此时小组的组织和任务的划分在类型上都不尽相同,已经不是程度上的差异问题。
注意在第三个月的结尾时,情况看上去很糟。除去管理的工作不谈,3 月1 日的里程碑仍未达到。此时,存在着很强的重复上述循环的诱惑――添加更多人力。疯狂、愚蠢就在此中。
前面所述的假设第一个里程碑估计不当。如果在3 月1 日,项目经理做出了比较保守的假设,即整个估计过于乐观了,如图2.7 所示。6 个人手需要被添加至原先的任务中。培训、任务的重新分配、系统测试工作量的计算作为练习留给读者。毫无疑问,重现“灾难”所生成的产品,比未增加人手,重新安排开发进度所产生的产品更差。
简单、武断地重复一下Brook 的规律:
向进度落后的项目中增加人手,只会使进度更加落后。(Adding manpower to a late software project makes it later)
这就是除去了神话色彩的人月。项目的时间依赖于次序上的限制。人员的个数依赖于独立子任务的数量。从这两个数值,可以用较少的人数和较多的时间推导出进度时间表。(唯一的风险是产品可能过时。)
使用较多的人数和较少的时间不能得到可行的进度安排。在众多软件项目中,时间进度的缺乏是造成项目的偏移最主要的原因,比其他所有因素加起来影响还大。


green_pine
驱动太牛
驱动太牛
  • 注册日期2002-10-22
  • 最后登录2019-06-10
  • 粉丝3
  • 关注0
  • 积分48分
  • 威望599点
  • 贡献值1点
  • 好评度144点
  • 原创分0分
  • 专家分0分
  • 社区居民
沙发#
发布于:2003-11-26 17:21
《人月神话》very good
flytomoon
驱动巨牛
驱动巨牛
  • 注册日期2003-07-09
  • 最后登录2004-10-18
  • 粉丝1
  • 关注1
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2003-11-26 18:58
《人月神话》very good


有空看看!
znsoft
管理员
管理员
  • 注册日期2001-03-23
  • 最后登录2023-10-25
  • 粉丝300
  • 关注6
  • 积分910分
  • 威望14796点
  • 贡献值7点
  • 好评度2410点
  • 原创分5分
  • 专家分100分
  • 社区居民
  • 最爱沙发
  • 社区明星
地板#
发布于:2003-11-26 19:17
不用节选,站上下载中心就有中文完全版
http://www.zndev.com 免费源码交换网 ----------------------------- 软件创造价值,驱动提供力量! 淡泊以明志,宁静以致远。 ---------------------------------- 勤用搜索,多查资料,先搜再问。
guoxh9
驱动太牛
驱动太牛
  • 注册日期2003-10-13
  • 最后登录2011-10-14
  • 粉丝0
  • 关注0
  • 积分-9分
  • 威望1点
  • 贡献值0点
  • 好评度1点
  • 原创分0分
  • 专家分0分
地下室#
发布于:2003-11-28 08:21
《人月神话》
奇文共赏。
green_pine
驱动太牛
驱动太牛
  • 注册日期2002-10-22
  • 最后登录2019-06-10
  • 粉丝3
  • 关注0
  • 积分48分
  • 威望599点
  • 贡献值1点
  • 好评度144点
  • 原创分0分
  • 专家分0分
  • 社区居民
5楼#
发布于:2003-11-28 09:28
不用节选,站上下载中心就有中文完全版
当年俺就是在那里下的
游客

返回顶部