内容简介
本书内容来自Brooks博士在IBM公司SYSTEM/360家族和OS/360中的项目管理经验,该项目堪称软件开发项目管理的典范。该书英文原版一经面世,即引起业内人士的强烈反响,全球销售数百万册。
作者简介
布鲁克斯博士1956年开始任职于IBM公司,早期担任Stretch和Harvest计算机的体系建构师。他被认为是“IBM360系统之父”,曾担任360系统的项目经理。凭借在此项目中的杰出贡献,他在1985年获得了美国国家技术奖。
第1章焦油坑
编程系统产品
编程系统(programing system)开发的工作量是供个人使用的、独立开发的构件程序的9倍。估计软件构件产品化引起了3倍的工作量,将软件构件整合成完整系统所需要的设计、集成和测试又加强了3倍的工作量,这些高成本的构件在根本上是相互独立的。
编程的乐趣
这种快乐是一种创建事物的纯粹快乐;
这种快乐来自于开发对他人有用的东西;
快乐来自于整个过程中体现出的一股强大魅力;
这种快乐是持续学习的快乐;
这种快乐来自于易于驾驭的介质上工作。
编程的苦恼
苦恼来自追求完美;
苦恼来自由他人来设定目标、供给资源和提供信息;
依赖于其他人的拙劣程序是苦恼的;
概念性设计是有趣的,但寻找bug却只是一项重复性的活动;
投入大量辛苦劳动,产品上线时却显得陈旧过时。
第2章人月神话
缺乏合理的时间进度是造成项目滞后的主要原因,它比其他所有因素的综合影响还大。
良好的烹饪需要时间,某些任务无法在不损害结果的情况下加快进度。
所有的编程人员都是乐观主义者:一切都将运作良好。
由于编程人员通过纯粹的思维活动来开发,我们期待在实现过程中不会碰到困难,但我们的构思本身是有缺陷的,因此总会有bug。
我们围绕成本核算的估计技术,混淆了工作量和项目进展。人月是危险和带有欺骗性的神话,因为它暗示人员数量和时间是可以相互替换的。
在若干人员中分解任务会引发额外的沟通工作量—培训和相互沟通。
关于进度安排,我的经验是1/3计划、1/6变化,1/4构件测试以及1/4系统测试。
我们对自己的估计技术不确定,因此在管理和客户的压力下,我们常缺乏坚持的勇气。
Brooks法则:向进度落后的项目增加人手,只会使进度更加落后。
向软件项目中增派人手从三个方面增加了项目必要的总体工作量:任务重新分配本身和所造成的工作中断:培训新人员;额外的相互沟通。
第3章 外科手术队伍
同样有两年经验而且在受同样培训的情况下,有些专业程序员的生产率是较差的程序员的10倍。
小型、精干队伍是最好的—思绪尽可能的少。
两个人的团队,其中一个是领导者,常常是最佳的人员使用方法(留意一下上帝对婚姻的设计)。
对于真正意义上的大型系统,小型精干的队伍太慢了。
实际上,绝大多数大型编程系统的经验显示,一拥而上的开发方法是提高成本、速度缓慢、低效的,开发出的产品无法进行概念上的集成。
一位首席程序员、类似外科手术队伍的团队架构提供了一种方法—既能获得由少数头脑产生的产品完整性,又能得到多位协助人员的总体生产率,还彻底减少了沟通的工作量。
第4章 贵族专制、民主政治和系统设计
概念完整性是系统设计中最重要的考虑因素。
功能与理解上的复杂程度的比值才是系统设计的最终测试标准,而不仅仅是丰富的功能(该比值是对易用性的一种测量,由简单和复杂应用共同验证)。
为了获得概念完整性,设计必须由一个人或者具有共识的小型团队来完成。
对于非常大型的项目,将体系结构方面的工作与具体实现相分离是获得概念完整性的强有力方法(同样适用于小型项目)。
如果要得到系统概念上的完整性,就必须有人控制这种概念。这实际上是一种无须任何歉意的贵族专制统治。
纪律、规则对行业是有益的,外部的体系结构规定实际上是增强,而不是限制实现小组的创造性。
概念上统一的系统能更快地开发和测试。
体系结构、设计实现、物理实现的许多工作可以并发进行(软件和硬件设计同样可以并行)。
第5章 画蛇添足
尽早交流和持续沟通能使结构师有较好的成本意识,使开发人员获得对设计的信息,并且不会混淆各自的责任分工。
结构师如何成功的影响实现:
牢记是开发人员承担创造性的实现责任,结构师只能提出建议。
时刻准备着为所指定的说明建议一种实现的方法,准备接受任何其他可行的方法。
对上述建议保持低调和平静。
准备对所建议的改进放弃坚持。
听取开发人员在体系结构上改进的建议。
第二个系统是人们所设计的最危险的系统,通常的倾向是过分的进行设计。/*设计第一个系统时因没经验而比较谨慎*/
为功能分配一个字节和微妙的优先权值是一个很有价值的规范化方法。
第6章 贯彻执行
即使是大型的设计团队,设计结果也必须由一两个人来完成,以确保这些决定是一致的。
必须明确定义体系结构中与先前定义不同的地方,重新定义的详细程度应该与原先的说明一致。
出于精确性的考虑,我们需要形式化的设计定义;同样,我们需要记述性定义来加深理解。
必须采用形式化定义和记述型定义中的一种作为标准,另一种作为辅助措施,它们都可以作为表达的标准。
直接整合是一种强制推行软件的结构性标准的方法。(硬件上也是如此)
如果起初至少有两种以上的实现,体系结构定义会更加整洁和规范。
允许体系结构师对实现人员的询问做出电话应答解释是非常重要的,并且必须进行日志记录和整理发布。
项目经理最好的朋友就是他每天要面对的对手—独立的产品测试小组。
第7章 为什么巴比伦塔会失败
交流
巴比伦塔项目的失败是以为缺乏交流以及交流的结果—组织。
左手不知道右手在做什么,从而进度灾难、功能的不合理和系统缺陷纷纷出现。由于对其他人的各种假设,团队成员之间的理解开始出现偏差。
团队应以尽可能多的方式进行相互之间的交流:非正式的进行简要技术陈述的常规项目会议,共享的正式项目工作手册。
项目手册
项目工作手册不是独立的一篇文档,它是对项目必须产生的一系列文档进行组织的一种结构。
项目所有的文档都必须是该工作手册结构的一部分。
需要尽早和仔细的设计工作手册结构。
事先制定了良好结构的工作手册可以将后来书写的文字放置在合适的章节中,并且可以提高产品手册的质量。
每个团队成员应该了解所有的材料(工作手册)。
实时更新是至关重要的。
工作手册的使用者应该讲注意力集中在上次阅读后的变更以及关于这些变更重要性的评述上。
组织架构
团队组织的目标是为了减少必要的交流和协作量。
为了减少交流,组织结构包括了人力划分和限定职责范围。
传统的树状组织结构反映了权利的结构原理—不允许双重领导。
组织中的交流是网状,而不是树状结构,因此所有的特殊组织机制都是为了进行调整,以克服树状组织结构中缺乏交流的困难。
每个子项目具有两个领导角色:产品负责人、技术主管,两种角色的任意组合都可以是非常有效的,一个作为总指挥,另一个作为副手。
第8章 胸有成竹
仅通过对编码部分时间的估计,然后乘以任务其他部分的相对系数,是无法得出对整个项目的精确估计的。
程序开发呈程序规模的指数增长,研究报告显示指数约为1.5。
数据显示相对于其他活动开销,全职程序员仅将50%的时间用于编程和调试。
在基本语句级别,生产率看上去是个常数。
当使用适当的高级语言时,程序编制的生产率可以提高5倍。
第9章 削足适履
除了运行时间以外,程序所占的内存空间也是主要开销。特别是对于操作系统,它的很多程序是永久驻留在内存中的。
即便如此,花费在驻留程序所占内存上的金钱仍是物有所值的,比其他任何在配置上投资的效果都要好,规模本身不是坏事,但不必要的规模是不可取的。
软件开发人员必须设立规模目标,控制规模,发明一些减少规模的方法—就如同硬件开发人员为减少元器件所做的事一样。
规模预算不仅在占据内存方面是明确的,同时还应该指明程序对磁盘的访问次数。
规模预算必须与分配的功能相关联,在指明模块大小的同事,确切定义模块的功能。
在大型团队中,各个小组倾向于不断的局部优化,以满足自己的目标,而较少考虑对用户的整体影响。这种方向性的问题是大型项目的主要危险。
在整个实现的过程期间,系统结构师必须保持持续的警觉,确保连贯的系统完整性。
培养开发人员从系统整体出发、面向用户的态度是软件编程管理人员最重要的职能。
在早期应该制定策略,以决定用户选项目的粗细程度,因为它们将作为整体打包能够节省内存空间。(常常还能节约市场成本)
暂存区空间的尺寸,以及每次磁盘访问的程序数量都是很关键的决策,因为性能是规模的非线性函数。
为了获取良好的空间—时间折中,开发队伍需要得到特定于某种语言或机型的变成技能培训,特别是在使用新语言或新机器时。
编程需要技术积累,每个项目需要自己的标准组件库。
精炼、充分和快读的程序往往是战略性突破的结果,而不仅仅是技巧上的提高。
战略上的突破常来自于对数据或表的重表达。数据的表现形式是编程的各根本。
第10章 提纲挈领
对于计算机硬件开发项目,关键文档是目标、手册、进度、预算、组织机构图、空间分配以及机器本身的报价、预测和价格。
对大学科系,关键文档类似于目标、课程描述、学位要求、研究报告、课程表和课程的安排、预算、教室分配、教室和研究生助手的分配。
对于软件项目,要求是相同的:目标、用户手册、内部文档、进度、预算、组织机构图和工作空间分配。
因此,即使是小型项目,项目经理也应该在项目早期对上述的一系列文档进行规范化。
以上集合中每一个文档的准备工作都将注意力集中在思索和对讨论的提炼上,而书写这项互动需要上百次的细小决定。正式由于它们的存在,人们才能从令人迷惑的现象中得到清晰、确定的策略。
对每个关键文档的维护提供了状态监督和预警机制。
每个文档本身就可以作为检查列表或者数据库。
项目经理的基本职责是使每个人都向着相同的方向前进。
项目经理的主要日常工作是沟通,而不是做出决定,文档使各项计划和决策在整个团队范围内得到交流。
第11章 未雨绸缪
化学工程师已经意识到无法一步将实验室工作台上的反应过程移到工厂中,需要一个实验性工厂来为提高产量和在缺乏保护的环境下运作提供宝贵经验。
对于编程产品而言,这样的中间步骤同样是必要的,但是软件工程师在着手发布产品之前,并不会常规的进行试验性系统的现场测试。(现在,这已经成为了一项普遍得实践,beta版本不同于有限功能的原型,alpha版本同样是我所倡导的实践)
第一个开发的系统对于大多数项目并不合用,它可能太慢、太大,而且难以使用,或者三者兼而有之。
系统的丢弃和重新设计可以一步完成,也可以一块块的实现,但这是个必须完成的步骤。
将开发的第一个系统—丢弃原型—发布给用户,可以获得时间,但是它的代价高昂,对于用户,使用极度痛苦;对于重新开发的人员,分散了经理;对于产品,影响了声誉,及时最好的再设计也难以挽回名声。
因此,为舍弃而计划,无论如何,你一定要这样做。
开发人员交付的是用户满意程度,而不仅仅是实际的产品。
用户的实际需要和用户感觉会随着程序的构件、测试和使用而变化。
软件产品易于掌握的特性和不可见性,导致它的构件人员(特别容易)面临着永恒的需求变更。
目标上和开发策略上的一些正常变化无可避免,事先为它们准备总比假设它们不会出现要好得多。
为变更计划组织架构
程序员不愿意为设计书写文档,不仅仅是因为惰性,更多的是源于设计人员的踌躇—要为自己尝试性的设计决策进行辩解。
为变更组件团队比为变更进行设计更困难。
只要管理人员和技术人才的天赋允许,老板必须对他们的能力培养给予极大关注,使管理人员和技术人才具有互换性;热别是希望能在技术和管理角色之间自由的分配人手的时候。
具有两条晋升线的高效组织机构存在着一些社会性的障碍,人们必须警惕并积极的同它做持续的斗争。
很容易为不同的晋升线建立相互一致的薪水级别,但同等威信的建立需要一些强烈的心理措施:相同的办公室、一样的支持和技术调动的优先补偿。
组建外科手术队伍的软件开发团队是对上述问题所有方面的彻底冲击,对于灵活组织架构问题,这的确是一个长期行之有效的解决方案。
程序维护
程序维护基本上不同于硬件的维护,它主要由各种变更组成,如修复设计缺陷、新增功能,或是使用环境或配置变更引起的调整。
对于一个广泛使用的程序,其维护总成本通常是开发成本的40%或更多。
维护成本受用户数目的严重影响,用户越多,所发现的错误也越多。
缺陷修复总会以20%~50%的几率引入新的bug。
每次修复之后,必须重新运行先前所有的测试用例,确保系统不会以更为隐蔽的方式被破坏。
能消除、至少是能指明副作用的程序设计方法,对维护成本有很大影响。
实现设计的人员越少、接口越少,产生的错误也就越少。
系统熵随时间增加
模块数量随大型操作系统版本号的增加而呈线性增长,但是收到影响的模块以版本号指数的级别增长。
所有修改都倾向于破坏系统的架构,增加了系统的混乱程度(熵)。即使是最熟练的软件维护工作,也只是延缓了系统退化到不可修复的混乱状态的进程,以致必须要重新进行设计(许多程序升级的真正需要,如性能等,尤其会冲击它的内部结构边界。原有边界引发的不足常常在日后才会出现。)
第12章 干将莫邪
项目经理应该制定一套策略,并为通用工具的开发分配资源,于此同时,他还必须意识到专业工具的需求。
开发操作系统的队伍需要自己的目标机器,进行调试开发工作。相对于最快的速度而言,它更需要最大限度的内存,还需要安排一名系统程序员,以保证机器上的标准软件是及时更新和实时可用的。
同时还需要配备调试机器或软件,以便在调试过程中,所有类型的程序参数可以被自动计数和测量。
目标机器的使用需求量是一种特殊曲线:刚开始使用率非常低,突然出现爆发性的增长,接着趋于平缓。
抛开理论不谈,一次分配给某个小组的连续的目标时间块被证明是最好的安排方法,比不同小组的穿插使用更为有效。
如果目标机器是新产品,就需要一个目标机器的逻辑仿真装置。这样,可以更快的得到辅助调试平台。即使在真正机器出现之后,仿真装置仍可提供可靠的调试平台。
主程序库应该被划分成:一系列独立的私有开发库;正处在系统测试下的系统集成子库;发布版本,正式的分离和进度提供了控制。
在编制程序的项目中,节省最大工作量的工具可能是文本编辑系统。
系统文档中的巨大容量产生了新的不易理解的问题,但是它比大多数未能详细描述变成系统特性的短小文章更加可取。
自上而下、彻底的开发一个性能仿真装置。尽可能早的开始这项工作,仔细的听取“它们表达的意见”。
交互式编程
在某些应用上,批处理系统绝不会被交互式系统所替代。
调试是系统编程中较慢和较困难的部门,而漫长的调试周转时间是调试的祸根。
有限的数据表明,系统软件开发中,交互式编程的生产率至少是原来的两倍。
第13章 整体部分
第4、5、6章所以为的煞费苦心、详尽体系结构工作不但使产品更加易于使用,而且使开发更容易进行且bug更不容易产生。
许许多多的失败完全源于那些产品未精确定义的地方。
在编写任何代码之前,规格说明必须提交给外部测试小组,以详细的检查说明的完整性和明确性。开发人员自己无法完成这项工作。
自上而下的设计(逐步细化)将会是最重要的新型形式化软件开发方法。
每个步骤中,都尽可能使用级别较高的表达方法。
有时必须退回,推翻顶层设计,重新开始。
结构化编程中,程序的控制结构仅由支配代码块(相对于任意的跳转)的给定稽核所组成,这种方法很好的避免了bug,是一种正确的思考方式。
对良好(对交互式调试做出快速反应)系统的正确使用,往往要求每两小时的终端会话对应于两小时的桌面工作:1小时会话后的清理和文档工作,1小时为下一次计划变更和测试。
系统调试(相对于单元测试)说话的时间会比预料的更长。
系统调试仅仅应该在所有部件能够运作之后开始。
开发大量的辅助调试平台和测试代码是很值得的,代码量甚至可能会有测试对象的一半。
必须有人对变更和版本进行控制和文档化,团队成员应使用开发库的各种受控拷贝来工作。
系统测试期间,一次只添加一个构件。
第14章 祸起萧墙
一天一天的进度落后比起重大灾难更难以识别,更不容易防范和弥补。
根据一个严格的进度表来控制大型项目的第一个步骤是制定进度表,进度表由里程碑和日期组成。
里程碑必须是具体的、特定的和可度量的时间,能进行清晰的定义。
如果里程碑定义的非常明确,以至于无法自欺欺人时,程序员很少会就里程碑的进展弄虚作假。
对于大型开发项目中的估计行为,政府的承包商所做的研究显示:每两周进行仔细修订的活动时间估计,随着开始时间的临近不会有太大的变化。期间内对时间长短的过高估计,会随着活动的进行持续下降。过低估计直到计划的结束日期之前大约三周左右,才会有所变化。
慢性进度偏离是士气杀手,如果你错过了第一个最终期限,确保完成下一条。
不存在关键路径进度的替代品,使人们能够辨别计划偏移的情况。
PERT的准备工作是PERT图使用中最有价值的部分,它包括了整个网状结构的展开、任务之间依赖关系的识别和各个任务链的估计。这些都要求在项目早期进行专业的计划。
每个老板同时需要采取行动的异常信息以及用来进行分析和早期预警的状态数据。
状态的获取是困难的,因为下属经理又充分的理由不提供信息共享。
老板的不良反应会对信息的完全公开造成压制,相反,仔细区分状态报告、毫无惊慌的接收报告、决不越俎代庖,将能鼓励诚实的汇报。
必须有评审的机制,使所有成员可以通过它了解真正的状态。出于这个目的,里程碑的进度和完成文档是关键。
对于大型项目,一个队里程碑报告进行维护的计划和控制小组是非常可贵的。
第15章 另外一面
对于软件编程来产品来说,程序向用户所呈现的面貌—文档,与提供给机器识别的内容同样重要。
即使对于完全开发给自己使用的程序,描述性文字也是必须的,因为它们会被用户—作者所遗忘。
培训和管理人员基本上没有能向编程人员成功的灌输对待文档的积极态度—文档能在整个生命周期对克服懒惰和进度的压力起促进和激励作用。
这样的失败并不都是以为缺乏热情或说服力,而是没能正确的展示如何有效和经济的编制文档。
大多数文档只提供了很少的总结性内容,必须放慢脚步,稳妥的进行。
由于关键的用户文档包含了跟软件相关的基本决策,因此它的绝大部门需要在程序编制之前书写,它包括了9项内容(目的、环境、范围、实现功能和使用的算法、输入—输出格式、操作指令、选项、运行时间、精度和效验)。
每一份发布的程序拷贝应该包括一些测试用例,其中一部分用于效验输入数据,一部分用于边界输入数据,另一部分用于无效的输入数据。
对于必须修改程序的人而言,他们需要程序内部结构文档,同样要求一份清晰明了的概述,它包括了5项内容。(流程图或子系统的结构图、对所用算法的完整描述、对所有文件规划的解释、数据流处理的概要描述、初始设计中对已预见修改的讨论)
为了使文档易于维护,将它们合并至源程序是至关重要的,而不是作为独立文档进行保存。
最小化文档担负的3个关键思路:借助那些必须存在的语句,如名称和声明,来附加尽可能多的文档信息;使用空格和格式来表现从属和嵌套关系,提高程序的可读性;以段落注释,特别是模块标题的形式,向程序中插入必要的记叙性文字。
程序修改人员所使用的文档中,除了描述事情如何以外,还应阐述它为什么那样,对于加深理解,目的是非常关键的,但即使是高级语言的语法,也不能表达目的。
在线系统的高级语言(应该使用的工具)中,自文档化技术发现了它的绝佳应用和强大功能。
20年后的《人月神话》
核心观点:概念完整性和结构师
一个整洁、优雅的编程产品必须向它的每位用户提供一个条理分明的概念模型,这个模型描述了应用、实现应用的方法以及用来知名操作和各种参数的用户界面使用策略。用户所感受到的产品概念完整性是易用性中最重要的因素。
任何规模很大或非常紧急并需要人力较多的项目,都会碰到一个特别的困难:必须由多人来设计,但同时还要在概念上与单个使用人员保持一致。结构师是用户的代理,在不可避免的对功能、性能、规模、成本和进度进行平衡时,卓有成效的体现用户的利益。结构师就像电影的导演,而经历类似于制片人。
将体系结构和设计实现、物理实现相分离,为了使结构师的关键任务更加可行,有必要将用户所感知的产品定义—体系结构,与它的实现相分离,体系结构和实现的划分在各个设计任务中形成了清晰的边界,边界两边都有大量的工作。(概念的完整性是产品质量的核心)