人月神话 读书笔记
1 人月神话
在众多软件项目中,缺乏合理的时间进度是造成项目滞后的最主要原因,比起其他因素加起来的影响还大。导致这种普遍灾难的原因是什么呢?
1.1 乐观主义
所有的编程人月都是乐观主义者。编程人员通过非常纯粹的思维活动——概念以及灵活的表现形式来开发程序。正由于介质的易于驾驭,我们期待在实现过程中不会碰到困难,因此造成了乐观主义的弥漫。而我们的构思是有缺陷的,因此总会有bug。也就是说,我们的乐观主义并不应该是理所应当的。
在单个的任务中,“一切都将运转正常”的假设在时间进度上具有可实现性。因为所遇的延迟是一个概率分布曲线,“不会延迟”仅具有有限的概率,所以现实情况可能会像计划安排的那样顺利。然而大型的编程工作,或多或少包含了很多任务,某些任务间还具有前后的次序,从而一切正常的概率变得非常小,甚至接近于无。
1.2 人月
第二个谬误的思考方式是在估计和进度安排中使用的工作量单位:人月。成本的确随开发产品的人数和时间的不同,有着很大的变化,进度却不是如此。因此我认为用人月作为衡量一项工作的规模是一个危险和带有欺骗性的神话。它暗示着人员数量和时间是可以相互替换的。
人数和时间的互换仅仅适用于以下情况:某个任务可以分解给参与人员,并且他们之间不需要相互的交流(图2.1)。这在割小麦或收获棉花的工作中是可行的;而在系统编程中近乎不可能。
图2.1:人员和时间之间的关系——完全可以分解的任务
当任务由于次序上的限制不能分解时,人手的添加对进度没有帮助(图2.2)。无论多少个母亲,孕育一个生命都需要十个月。由于调试、测试的次序特性,许多软件都具有这种特征,
图2.2:人员和时间之间的关系——无法分解的任务
对于可以分解,但子任务之间需要相互沟通和交流的任务,必须在计划工作中考虑沟通的工作量。因此,相同人月的前提下,采用增加人手来减少时间得到的最好情况,也比未调整前要差一些(图2.3)。
图2.3:人员和时间之间的关系——需要沟通的可分解任务
沟通所增加的负担由两个部分组成,培训和相互的交流。每个成员需要进行技术、项目目标以及总体策略上的培训。这种培训不能分解,因此这部分增加的工作量随人员的数量呈线性变化。
相互之间交流的情况更糟一些。如果任务的每个部分必须分别和其他部分单独协作,则工作量按照n(n-1)/2递增。一对一交流的情况下,三个人的工作量是两个人的三倍,四个人则是两个人的六倍。而对于需要在三四个人之间召开会议、进行协商、一同解决的问题,情况会更加恶劣。所增加的用于沟通的工作量可能会完全抵消对原有任务分解所产生的作用,此时我们会被带到图2.4的境地。
图2.4:人员和时间之间的关系——关系错综复杂的任务
因为软件开发本质上是一项系统工作——错综复杂关系下的一种实践——沟通、交流的工作量非常大,它很快会消耗任务分解所节省下来的个人时间。从而,添加更多的人手,实际上是延长了,而不是缩短了时间进度。
1.3 系统测试
在时间进度中,顺序限制所造成的影响,没有哪个部分比单元调试和系统测试所受到的牵涉更彻底。而且,要求的时间依赖于所遇到的错误、缺陷数量以及捕捉它们的程度。理论上,缺陷的数量应该为零。但是,由于我们的乐观主义,通常实际出现的缺陷数量比预料的要多得多。因此,系统测试进度的安排常常是编程中最不合理的部分。
对于软件任务的进度安排,以下是我使用了很多年的经验法则:
1/3计划
1/6编码
1/4构件测试和早期系统测试
1/4系统测试,所有的构件已完成
在许多重要的方面,它与传统的进度安排方法不同:
1. 分配给计划的时间比寻常的多。即便如此,仍不足以产生详细和稳定的计划规格说明,也不足以容纳对全新技术的研究和摸索。
2. 对所完成代码的调试和测试,投入近一半的时间,比平常的安排多很多。
3. 容易估计的部分,即编码,仅仅分配了六分之一的时间。
但现实的情况往往不会是这样,他们测试往往没有安排这么多时间,但最后实际却花费了一半的时间。
1.4 空泛的估计
有时为了满足客户期望的日期而造成的不合理进度安排,在软件领域中比其他的任何工厂领域要普遍的多。而且,非阶段化方法的采用,少的可怜的数据支持,加上空泛的估计,很难产出健壮可靠的估计。
1.5 重复产生的进度灾难
当一个软件项目落后于进度时,通常的做法是什么呢?自然是加派人手。如图2.1至2.4所示,这可能有所帮助,也可能无法解决问题。
我们来考虑一个例子3。设想一个估计需要12个人月的任务,分派给3个成员4个月时间,在每个月的末尾安排了可测量的里程碑A、B、C、D(图2.5)。
现在假定两个月之后,第一个里程碑没有达到(图2.6)。项目经理面对的选择方案有哪些呢?
1. 假设任务必须按时完成。假设仅仅是任务的第一个部分估计不得当,即如图2.6所示,则剩余了9个人月的工作量,时间还有两个月,即需要4.5个开发人员,所以需要在原来3个人的基础上增加2个人。
2. 假设任务必须按时完成。假设整个任务的估计偏低,即如图2.7所示,那么还有18个人月的工作量以及2个月的时间,需要将原来的3个人增至9个人。
3. 重新安排进度。我喜欢P.Fagg,一个具有丰富经验的硬件工程师的忠告:“避免小的偏差(Take no small slips)”。也就是说,在新的进度安排中分配充分的时间,以确保工作能仔细、彻底地完成,从而无需重新确定时间进度表。
4. 削减任务。在现实情况中,一旦开发团队观察到进度的偏差,总是倾向于对任务进
行削减。当项目延期所导致的后续成本非常高时,这常常是唯一可行的方法。项目经理的相应措施是仔细、正式地调整项目,重新安排进度;或者是默默地注视着任务项由于轻率的设计和不完整的测试而被剪除。
图2.5
图2.6
图2.7
图2.8
前两种情况中,坚持把不经调整的任务在四个月内完成将是灾难性的。考虑到重复生成的工作量,以第一种为例(图2.8)——不论在多短的时间内,聘请到多么能干的两位新员工,他们都需要接受一位有经验的职员的培训。如果培训需要一个月的时间,那么三个人月将会投入到原有进度安排以外的工作中。另外,原先划分为三个部分的工作,会重新分解成五个部分;某些已经完成的工作必定会丢失,系统测试必须被延长。因此,在第三个月的月末,仍然残留着7个人月的工作,但此时只有5个有效的人月。如同图2.8所示,产品还是会延期,如同没有增加任何人手(图2.6)。
期望四个月内完成项目,仅仅考虑培训的时间,不考虑任务的重新划分和额外的系统测试,在第二个月末需要增添4个,而不是2个人员。如果考虑任务划分和系统测试的工作 量,则还需要继续增加人手。到那时所拥有的就不是3人的队伍,而是7人以上的团队;并且小组的组织和任务的划分在类型上都不尽相同,这已经不是程度上的差异问题。注意在第三个月的结尾时,情况看上去还是很糟。除去管理的工作不谈,3月1日的里程碑仍未达到。此时,对项目经理而言,仍然存在着很强的诱惑——添加更多人力,结果往往会是上述循环的重复。这简直就是一种疯狂、愚蠢的做法。
前面的讨论仅仅是第一个里程碑估计不当的情况。如果在3月1日,项目经理做出了比较保守的假设,即整个估计过于乐观了,如图2.7所示。6个人手需要添加到原先的任务中。培训、任务的重新分配、系统测试工作量的计算作为练习留给读者。但是毫无疑问,重现“灾难”所开发出的产品,比没有增加人手,而是重新安排开发进度所产生的产品更差。
简单、武断地重复一下Brooks法则:
向进度落后的项目中增加人手,只会使进度更加落后。(Adding manpower to a late software project makes it later)
这就是除去了神话色彩的人月。项目的时间依赖于顺序上的限制,人员的数量依赖于单个子任务的数量。从这两个数值可以推算出进度时间表,该表安排的人员较少,花费的时间较长(唯一的风险是产品可能会过时)。相反,分派较多的人手,计划较短的时间,将无法得到可行的进度表。总之,在众多软件项目中,缺乏合理的时间进度是造成项目滞后的最主要原因,它比其他所有因素加起来的影响还要大。
2 团队的扩建
在计算机领域的会议上,经常听到项目经理声称他们喜欢由人才小组组成的小型、精干的队伍,而不是那些几百人的大型团队。
但是这样有一个问题----如何在有意义的时间进度内创建大型的系统呢?
2.1 问题
软件经理很早就认识到优秀程序员和较差的程序员之间生产率的差异,但实际测量出的差异还是令我们所有的人吃惊。在他们的一个研究中,Sackman、Erikson和Grand曾对一组具有经验的程序人员进行测量。在该小组中,最好的和最差的表现在生产率上平均为10:1;在运行速度和空间上具有5:1的惊人差异!简言之,$20,000/年的程序员的生产率可能是$10,000/年程序员的10倍。
但对于大型项目,小型、精干的队伍他们需要的时间会延长,即使所需要的沟通交流成本会下降。这种进退两难的境地是非常残酷的。对于效率和概念的完整性来说,最好由少数干练的人员来设计和开发,而对于大型系统,则需要大量的人手,以使产品能在时间上满足要求。如何调和这两方面的矛盾呢?
2.2 Mills的建议
Harlan Mills的提议提供了一个崭新的、创造性的解决方案2,3。Mills建议大型项目的每一个部分由一个团队解决,但是该队伍以类似外科手术的方式组建,而并非一拥而上。也就是说,同每个成员截取问题某个部分的做法相反,由一个人来进行问题的分解,其他人给予他所需要的支持,以提高效率和生产力。
2.3 如何运作
首先,概念的一致性。传统的团队将工作进行划分,每人负责一部分工作的设计和实现。在外科手术团队中,外科医生和副手都了解所有的设计和全部的代码。这节省了空间分配、磁盘访问等的劳动量,同时也确保了工作概念上的完整性。
第二,在传统的队伍中大家是平等的,出现观点的差异时,不可避免地需要讨论和进行相互的妥协和让步。由于工作和资源的分解,不同的意见会造成策略和接口上的不一致,例如谁的空间会被用作缓冲区,然而最终它们必须整合在一起。而在外科手术团队中,不存在利益的差别,观点的不一致由外科医生单方面来统一。这两种团队组建上的差异——对问题不进行分解和上下级的关系——使外科手术队伍可以达到客观的一致性。
另外,团队中剩余人员职能的专业化分工是高效的关键,它使成员之间采用非常简单的交流模式成为可能。
另外,团队中剩余人员职能的专业化分工是高效的关键,它使成员之间采用非常简单的交流模式成为可能。