本系列文是软件巨著《人月神话》读书笔记,全系列分为三部分,会逐步介绍。
书籍简介
作者简介,FredericP.Brooks.Jr 弗雷德里克.布鲁克斯。

作者任职经历:1956~1965年任职IBM公司,1956~1963年主要从事硬件架构的工作,1964年担任360系统的项目经理。
项目经历:上个世纪60年代IBM公司想打造一款360操作系统来统一计算机行业,当时360项目的项目经理错误的认为 人月=月人,他投入了2000个优秀的工程师一同完成这个项目,于是这个噩梦就开始了,大量的沟通成本和矛盾导致这个项目陷入泥潭,后期又不得不持续投入人力,而人力的投入只会进一步增加沟通的成本,导致工程继续延期,整个项目像一只陷入泥潭的野兽越挣扎,越陷越深,这个项目从原计划投入2000人用时一年完成,变成最终花费4年的时间,投入5000人年的劳动力,投入资金超过5亿美元。
360项目的问题:360操作系统在设计和执行上出现了很多的问题,比如发布延期,需要的内存更多,成本更高,首次发布无法运行等。
此书来源:1975年,Brooks博士总结了他多年在IBM管理OS/360研发期间的经验,以一个个小故事的方式描述了软件工程中存在的现象,探讨软件工程的管理问题,这就是著名的《人月神话》 。
书籍发版时间线:
1975年: 初版-1~15章,介绍了大型软件工程遇到问题及如何更有效的进行项目管理。
1995年:20周年纪念版,添加了四个章节的内容
16章,"没有银弹",1986年发表的一篇论文"没有银弹:软件工程的根本和次要问题"17章,"再论没有银弹":对外界关于16章论文的一些评论进行回答18章,《人月神话》的观点,"是与非":对前面的1~15个章节进行总结19章,20年后的《人月神话》,一篇更新的短文2007年,32周年中文纪念版,是基于20周年版的一个翻译版本。
20015年,40周年中文纪念版,20周年版本的一个再译版本。
写在前面的话计算机领域经过几十年的飞速发展,软硬件都比作者所处的年代有了极大的提升。硬件资源实现了跨数量级的提升,诞生了著名的摩尔定律,PC的普及以及服务器性能的提升,使计算和存储资源在应用程序中越来越宽裕。
摩尔定律: 集成电路上可以容纳的晶体管数目在大约每经过18个月到24个月便会增加一倍。换而言之,处理器的性能大约每两年翻一倍,同时价格下降为之前的一半。摩尔定律是内行人摩尔的经验之谈,汉译为"定律",但是并非自然科学定律,它一定程度揭示了信息技术进步的速度。
软件的发展也是令人兴奋。伴随着网络性能的飞速发展,编程领域由单机程序迅速向网络分布式系统转换。虽然计算机领域飞速发展了几十年,我们拥有更快的硬件,更快的网络,更多的计算,存储资源、更优秀的重用库,更完善的框架、更方便的语言,更先进的思想等等之前无法想象的海量资源,让我们感觉软件工程领域的种种问题似乎应该也迎刃而解了,不复存在了,或者最起码应该是由新的问题困扰我们。
但时间未能改变的是,这些问题依旧困扰着我们:
我们依旧无法准确评估工作量我们依旧难以进行合理的进度安排项目落后时,只能被动的延长工作时间或者增加人力大量的bug反复出现开发的软件不能使用户满意,甚至用户仅仅使用软件的极少功能。这些现象早在40年前《人月神话》中描述的现象类似。经历了几十年依然存在,并且大量存在。
难道软件工程几十年没有发展了吗?还是软件工程的根本问题还是没有较好的解决呢?
软件工程的发展可以看看: 一起看看,软件工程发展简史
同时《人月神话》 在当下最经典的价值,是其论证了软件开发的主要困难是复杂度,最主要的复杂度来自于设计概念,次要的复杂度是实现概念。换句话说,最困难的是知道"该怎么做才正确",而不是"做出来"。
关于本书
《人月神话》中的”人”是指的人力,”月”指的是工作的时间,主要的意思是:”用人月作为衡量软件开发工作量是一个危险和误导人的神话,它暗示人员数量和工作时间是可以相互替换的"
举例来说: 1个人可以在10周之内做完的项目,10个人不一定可以在一周之内完成。在书中作者更进一步指出,单纯的增加开发人力,不仅不能对应地减少项目的开发时间,甚至有可能增加开发的时间。因为更多的开发人员需要更多的沟通交流,这部分的时间成本也是很可观的。当然,这部书不仅仅是论述这一个观点,而是从这个观点出发,本书还介绍了很多其他的大型软件工程的规律和最佳实践。
本书虽然出版至今有40多年,至今仍未过时。Brooks博士为人们管理复杂的项目提供了具有洞察力的见解,还有大量软件工程的实践。书中提出的许多概念至今仍被广泛应用到现今的各类软件开发实践中人月神话,没有银弹,Brooks法则。
如何阅读本书《人月神话》中文译本是典型的英译书,如果逐字逐句的读会非常费力,因为翻译的人为了保持原汁原味,逐字逐句的进行翻译,而未能转为方便我们理解的语言。有的语句,你仔细读可能还会觉得语句不通顺。
它更适合自我提炼,根据每一章节的核心思想,再结合自己的项目经验来品味作者想向我们表达的内容。如果有的章节,你读完还是不理解作者要表达什么,也是很正常的,因为我们不会有作者写书时候的项目背景经验,但切记要反复多读几遍。等你以后有类似的项目经历时,你可能会突然想起和书中相似的场景,联系起来再去重复读某些章节更有意义。
焦油坑
软件开发就是一个焦油坑,充满着乐趣和苦恼。
一副可怕的场景:“上帝见证着恐龙,猛犸象,剑齿虎在焦油中挣扎。他们挣扎德越猛烈,焦油纠缠得越紧,没有哪种猛兽足够强壮或者具有足够的技巧,能够挣脱束缚,它们最后都沉到坑底”。
过去几十年的大型系统开发就犹如这样一个焦油坑,各种团队, 大型的和小型的, 庞杂的和精干的, 一个接一个淹没在了焦油坑中。他们中大多数开发出了可运行的系统——不过, 其中只有非常少数的项目满足了目标、 时间进度和预算的要求
这到底为什么呢? 表面上看起来好像没有任何一个单独的问题会导致困难, 每个都能被解决, 但是当它们相互纠缠和累积在一起的时候, 团队的行动就会变得越来越慢。 对问题的麻烦程度, 每个人似乎都会感到惊讶, 并且很难看清问题的本质。 不过, 如果我们想解决问题,就必须试图先去理解它。因此,首先让我们来认识一下软件开发这个职业,以及充满在这个职业中的乐趣和苦恼吧。
软件开发这个职业产出什么?
什么程序(Programming),系统(System),产品和系统产品(System Product)
程序(Program),它本身是完整的,可以由作者在所开发的系统平台上运行。报纸上经常会出现这样的,讲述两个程序员如何在经改造的简陋车库中,编出了超过大型团队工作量的重要程序,但是往往这种程序不会变得更通用。有两种途径可以使程序转变成更有用的,但是成本更高的东西,它们表现为图中的边界。
方式一: 程序变成编程产品(Programming Product),这是可以被任何人运行、测试、 修复和扩展的程序。
可以再多种操作系统和平台上运行,供多套数据使用。程序必须按照普遍认可的风格来编写,特别是扩展性,以适用所有可以合理使用的基本算法完备的测试,确保它的稳定性和可靠性,使其值得信赖还需要有完备的文档, 每个人都可以加以使用、 修复和扩展经验数据表明, 相同功能的编程产品的成本, 至少是已经过测试的程序的三倍。
方式二: 程序变成编程系统(Programming System)中的一个构件单元。 它是在功能上能相互协作的程序集合, 具有规范的格式, 可以进行交互, 并可以用来组装和搭建整个系统。
程序必须按照一定要求编制,精确定义相关的接口以及接口的输入和输出,也要拥有完备的文档符合预先定义的资源限制,内存空间、输入输出设备、计算机时间等。可以方便和其他系统构建一些组合,一起进行完备的测试。因此相同功能的编程系统构件的成本至少是独立程序的三倍。如果系统有大量的组成单元,成本还会更高。
然而上真正有用的产品,是编程系统产品(Programming Systems Product),是大多数系统开发的目标。和以上的所有的情况都不同的是, 它的成本高达九倍。
职业的乐趣
创建事物的纯粹快乐:成年人喜欢创建事物,特别自己进行设计,如小孩玩泥巴。开发对他人有用的东西:劳动成果能被他人使用,并对他人有帮助,如小孩用粘土捏铅笔盒过程有强大的魅力:将零件组装一起,以精妙的方式运行,并收到预期效果,如自动电唱机持续学习的快乐:非重复特性,面临的问题总是各不相同,而解决问题就可以从中学到新事物易于驾驭的介质上工作:单纯的思考中工作,运用自己的想象建造自己的"城堡职业的苦恼
追求完美:计算机是要求非常准确,而现实人类活动很少会要求如此完美,所以人类会不习惯由他人设定目标、供给资源、提供信息:编程人员很少能控制工作环不境和工作目标对他人依赖是一件痛苦的事:依靠他人的程序,程序可能设计不合理里、实现拙劣、发布不完束或文档记录很糟寻找琐碎bug是一项重复性活动:调试和查错是线性收敛的,寻找最后一个错误比第一个错误将花费更多时间产品完成或即将完成却显得陈旧过时:可能竞争对手有新品或替代方案有安排这, 就是编程。 一个许多人痛苦挣扎的焦油坑以及一种乐趣和苦恼共存的创造性活动。对于许多人而言, 其中的乐趣远大于苦恼。
而本书的剩余部分将试图搭建一些桥梁, 为通过这样的焦油坑提供一些指导,愿我们享受编程的快乐,遇到焦油坑时也不用妄自菲薄,很多软件项目的问题是普遍存在的,不要对自己的能力产生怀疑。
人月神话
美酒的酿造需要年头,美食的烹调需要时间;片刻等待,更多美味,更多享受。
过去几十年的大型系统开发,产生了无数可运行的系统——不过, 其中只有非常少数的项目满足了目标、 时间进度和预算的要求,软件开发项目在进度安排上经常出现的问题,原因主要有以下几点:
原因1:乐观主义者: 总是理想地想象一切都想运作良好,每项任务仅花费它所应该花费的时间
实际上,我们在实现过程中总会碰到各种各样的困难,可能是我们构思的缺陷,也可能是程序其他部件带来的错误影响,修复这些错误将占用我们大量的时间。
所有的编程人员都是乐观主义者。可能是这种现代魔术特别吸引那些相信美满结局的人;也可能是成百上千琐碎的挫折赶走了大多数人,只剩下了那些习惯上只关注结果的人;还可能仅仅因为计算机还很年轻, 程序员更加年轻, 而年轻人总是些乐观主义者——无论是什么样的程序, 结果是勿庸置疑的:“这次它肯定会运行。” 或者“我刚刚找出了最后一个错
误。对这种弥漫在编程人员中的乐观主义,理应受到慎重的分析。
Dorothy Sayers 在她的“ The Mind of the Maker”一书中, 将创造性活动分为三个阶段: 构思、实现和交流。
书籍、 计算机、 或者程序的出现, 首先是作为一个构思或模型出现在作者的脑海中, 它与时间和空间无关。 接着, 借助钢笔、 墨水和纸, 或者电线、 硅片和铁氧体, 在现实的时间和空间中实现它们。然后, 当某人阅读书本、 使用计算机和运行程序的时候, 他与作者的思想相互沟通,从而创作过程得以结束。
对于创造者, 只有在实现的过程中, 才能发现我们构思的不完整性和不一致性。在许多创造性活动中,往往很难掌握活动实施的介质,例如木头切割、油漆、电器安装等。 这些介质的物理约束限制了思路的表达, 它们同样对实现造成了许多预料之外的困难。由于物理介质和思路中隐含的不完善性,实际实现起来需要花费大量的时间和汗水。
然而,计算机编程基于十分容易掌握的介质,编程人员通过非常纯粹的思维活动——概念以及灵活的表现形式来开发程序。 正由于介质的易于驾驭, 我们期待在实现过程中不会碰到困难, 因此造成了乐观主义的弥漫。 而我们的构思是有缺陷的, 因此总会有 bug。也就是说,我们的乐观主义并不应该是理所应当的。
在单个的任务中,“一切都将运转正常” 的假设在时间进度上具有可实现性。 因为所遇的延迟是一个概率分布曲线, “不会延迟”仅具有有限的概率,所以现实情况可能会像计划安排的那样顺利。 然而大型的编程工作, 或多或少包含了很多任务, 某些任务间还具有前后的次序,从而一切正常的概率变得非常小,甚至接近于无。
原因2:估计和进度安排中使用的工作量单位:人月,它错误的假设人和月可以互换,以人月为单位去衡量开发工作的规模是一个危险和带有欺骗性的神话。
人数和时间的互换仅仅适用于以下情况:某个任务可以分解给参与人员,并且他们之间不需要相互的交流。这在割小麦或收获棉花的工作中是可行的;而在系统编程中近乎不可能。
当任务由于次序上的限制不能分解时,人手的添加对进度是没有帮助的。在开发工作中,添加更多的人手,意味着不得不花费时间去培训新人,并且随着开发人员的增多,沟通交流的时间成本也越来越大
对于可以分解,但子任务之间需要相互沟通和交流的任务,必须在计划工作中考虑沟通的工作量。 因此, 相同人月的前提下, 采用增加人手来减少时间得到的最好情况, 也比未调整前要差一些。
沟通所增加的负担由两个部分组成,培训和相互的交流。每个成员需要进行技术、 项目目标以及总体策略上的培训。 这种培训不能分解, 因此这部分增加的工作量随人员的数量呈线性变化。
相互之间交流的情况更糟一些。如果任务的每个部分必须分别和其他部分单独协作,则工作量按照 n(n-1)/2 递增。一对一交流的情况下,三个人的工作量是两个人的三倍,四个人则是两个人的六倍。 而对于需要在三四个人之间召开会议、 进行协商、 一同解决的问题,情况会更加恶劣。所增加的用于沟通的工作量可能会完全抵消对原有任务分解所产生的作
用,此时我们会被带到下图境地。
件开发本质上是一项系统工作——错综复杂关系下的一种实践——沟通、交流的工作量非常大,它很快会消耗任务分解所节省下来的个人时间。从而,添加更多的人手,实际上是延长了,而不是缩短了时间进度。
看各种场景下,人月关系总结如下:
原因3:系统测试估时被低估:理论上,bug的数目应该为0,但由于我们的乐观主义,实际的bug数量比预料的要多得多,系统测试的进度安排常常是编程中最不合理的部分。
对于软件的进度安排,作者以自己多年的管理经验总结出如下法则:
与大多数传统进度安排相比,这份进度安排显得计划时间过长,测试占用了一半的时间,编码是最容易估算的部分,仅分配了1/6的时间,如果不为测试安排足够的时间简直就是一场灾难,因为bug会没有任何预兆,很晚才出现在客户和项目经理面前,此时此刻的延迟具有不寻常的、会造成严重的财务(商业代价)和心理(极限冲刺)上的反应。
原因4:空泛的估算,为了满足顾客期望的日期而造成的不合理进度安排, 在软件领域中却比其他的任何工程领域要普遍得多。
某项任务的计划进度,可能受限于顾客要求的紧迫程度, 但紧迫程度无法控制实际的完成情况。非阶段化方法的采用, 少得可怜的数据支持, 加上完全借助软件经理的直觉,这样的方式很难生产出健壮可靠和规避风险的估计。
我们需要两种解决方案。一方面开发并推行生产率图表、缺陷率、估算规则等等,而整个组织最终会从这些数据的共享上获益。另外一方面在基于可靠基础的估算出现之前,项目经理需要挺直腰杆,坚持他们的估计,确信自己的经验和直觉总比从期望派生出的结果要强得多
原因5:向进度落后的项目加派人手,这样的应对方案好比用汽油灭火,只会让火势更大,而更大的火势又需要更多的汽油,从而陷入循环的灾难之中。
Brooks法则:向进度落后的项目中增加人手,只会使进度更加落后。
小结:用人月来估算项目进度是不合理的,更大的队伍不一定能带来更快的开发进度。
那么什么样的队伍才是合适的呢? 小团队固然高效,但是不能指望一个20人的小团队在合理的时间内去开发一套完整的 操作系统。
软件开发充满着复杂,有哪些大项项目的实践经验呢,请继续阅读系列二文章。