人月神话读书笔记
焦油坑
为什么两个人的创业团队可以超越大公司9倍以上的效率开发任何程序。而大公司的产业化团队效率只有1000代码行/年
程序员,就像诗人一样,几乎仅仅工作在单纯的思考中。程序员凭空运用自己的想象,来建造自己的“城堡”。很少有这样的介质——创造的方式如此灵活,如此得益于精炼和重建,如此得容易实现概念上的设想。
评论:这个观点与《黑客与画家》中的观点不谋而合,后者把程序员的工作看成和画家、作家一样的类似。但是也正因为程序员所做的工作是纯粹的智力创造,不断的推到重来就成为常态。概念设计上的不完善,使得软件架构变得越来越庞大、复杂并且难以为继,成为一个焦油坑,越是挣扎,越是深陷其中。
人月神话
Brooks法则:
“向进度落后的项目中增加人手,只会使进度更加落后。”
“Adding mapower to a late software project makes it later.”
评论:注明的Brooks法则,人月神话一文的核心观点。用人月这一观念来衡量项目进度带有欺骗性。因为他使得项目看上去好像人力和时间是可交换的。如果时间不够,那么增加人手就可以加快进度。但是这个衡量方式忽略了新增加人手的培训时间、队员之间的沟通时间等等因素,结果就是,盲目的增加人手只会导致项目落后。所以问题是,如何使得项目进度不落后;要想使得项目进度不落后,就要制定出合理的项目进度。所以,问题是,如何制定出合理的项目进度。
对于软件任务的进度安排,以下是我使用了很多年的经验法则:
1/3 计划
1/6 编码
1/4 构建测试和早期系统测试
1/4 系统测试,所有的构建已完成
评论:充足的测试时间,只占1/6的编码时间。可惜很多时候我们常常以为编码时间就是全部的时间了,难怪会进度落后。
外科手术队伍
最好的和最差的表现在生产率上平均为10:1,在运行速度和空间上具有5:1的惊人差异!简言之,$20,000/年的程序员的生产率可能是¥10,000/年程序员的10倍。
得出的结论很简单:如果一个200 人的项目中,有25 个最能干和最有开发经验的项目经理,那么开除剩下的175 名程序员,让项目经理来编程开发。
评论:所以说有经验的程序员才是最廉价的劳动力啊
Harlan Mills 的提议提供了一个崭新的、创造性的解决方案2,3。Mills 建议大型项目的每一个部分由一个团队解决,但是该队伍以类似外科手术的方式组建,而并非一拥而上。
也就是说,同每个成员截取问题某个部分的做法相反,由一个人来进行问题的分解,其他人给予他所需要的支持,以提高效率和生产力。
评论:有时候民主和平等也许并非是最好的选择:因为首先在人在智力上、能力上就并不平等。外科手术式的团队其实是延续了早期英雄式的编程风格:主要的程序员决定了项目的大部分内容,而其他人则成为他的副手,帮助他完成各项细节性的工作。
贵族专制、民主政治和系统设计
现在让我们来处理具有浓厚感情色彩的问题——贵族统治和民主政治。结构师难道不是新贵?他们一些智力精英,专门来告诉可怜的实现人员如何工作?是否所有的创造性活动被那些精英单独占有,实现人员仅仅是机器中的齿轮?难道不能遵循民主的理论,从所有的员工中搜集好的创意,以得到更好的产品,而不是将技术说明工作仅限定于少数人?
评论:为了实现概念完整性,在软件体系结构设计的时候必须实行贵族专制,让少数的架构师来决定整体的架构,普通程序员毫无发言权。但是Brooks为了安慰那些可怜的普通程序员,就告诉他们:其实实现细节也是需要一样的创造性、同样的新思路和卓越的才华。但是谁都知道,如果能够成为贵族,为何要在制造工艺上费劲心思呢?
画蛇添足
第二个系统是设计师们所设计的最危险的系统。而当他着手第三个或第四个系统时,先前的经验会相互验证,得到此类系统通用特性的判断,而且系统之间的差异会帮助他识别出经验中不够通用的部分。
一种普遍倾向是过分地设计第二个系统,向系统添加很多修饰功能和想法,它们曾在第一个系统中被小心谨慎地推迟了。
评论:这个标题起得让人摸不清头脑,其实值得是第二系统效应(second-system effect)。认识到第二个系统存在的风险,可以让架构师保持警惕,少犯错误。
为什么巴比伦塔会失败?
- 清晰的目标?是的,尽管幼稚得近乎不可能。而且,项目早在遇到这个基本的限制之前,就已经失败了。
- 人力?非常充足。
- 材料?在美索不达米亚有着丰富的泥土和柏油沥青。
- 足够的时间?没有任何时间限制的迹象。
- 足够的技术?是的,金字塔、锥形的结构本身就是稳定的,可以很好分散压力负载。对砖石建筑技术,人们有过深刻的研究。同样,项目远在达到技术限制之间,就已经失败了。
那么,既然他们具备了所有的这些条件,为什么项目还会失败呢?他们还缺乏些什么?两个方面——交流,以及交流的结果——组织。他们无法相互交谈,从而无法合作。当合作无法进行时,工作陷入了停顿。通过史书的字里行间,我们推测交流的缺乏导致了争辩、沮丧和群体猜忌。很快,部落开始分裂——大家选择了孤立,而不是互相争吵。
胸有成竹
本章只解决一个问题:一个程序员的生产效率究竟有多高?
对规模平均为3200指令的程序...大约单个的程序员所需要的编码和调试时间为178个小时,由此可以外推得到每年35800语句的生产率。而规模只有一半的程序花费时间大约仅为前者的四分之一,相应推断出的生产率几乎是每年80,000代码行1。计划、编制文档、测试、系统集成和培训的时间必须被考虑在内。因此,上述小型项目数据的外推是没有意义的。就好像把100码短跑记录外推,得出人类可以在3分钟之内跑完1英里的结论一样。
工作量和代码行数不是线性关系,而是指数型关系:
工作量 = (常数)×(指令的数量)^1.5
Aron的数据:
很少的交互 10,000指令每人年
少量的交互 5,000
较多的交互 1,500
Harr的数据
OS/360的数据
600-800(经过调试的指令)/人年
Corbato的数据
平均生产率是1200行经过调试的PL/I语句/人年
Corbato的数据是行为单位,每行语句对应3-5个指令。
上述所有数据的结论:
- 对于常用编程语句而言,生产率似乎是固定的。这个固定的生产率包括了编程中需要注释,并可能存在错误的情况。
- 生产率随着系统复杂性或者难度增加而降低。
- 使用适当的高级语言,编程的生产率可以提高5倍。
未雨绸缪
因此,管理上的问题不再是“是否构建一个试验性的系统,然后抛弃它?”你必须这样做。现在的问题是“是否预先计划抛弃原型的开发,或者是否将该原型发布给用户?”从这个角度看待问题,答案更加清晰。将原型发布给用户,可以获得时间,但是它的代价高昂——对于用户,使用极度痛苦;对于重新开发的人员,分散了精力;对于产品,影响了声誉,即使最好的再设计也难以挽回名声。
因此,为舍弃而计划,无论如何,你一定要这样做。
虽然Brooks在50年前就已经提出构建可抛弃原型的必要性,并且在各类开发模型中也都强调原型的必要性,但是到今天,可抛弃原型仍然没有被大部分实践所接受。或许,知道该做什么,和实际去做之间,永远存在一个鸿沟。另一种可能性是,可抛弃原型虽然很好,但是显然没有达到“必须”的程度。它带来的好处不足以弥补其代价,是今天大部分实践中并未采用的原因。
系统软件开发是减少混乱度(减少熵)的过程,所以它本身是处于亚稳态的。软件维护是提高混乱度(增加熵)的过程,即使是最熟练的软件维护工作,也只是放缓了系统退化到非稳态的进程。
系统开发的熵论,非常的形象有趣。为变更而计划组织架构,其实只是一句让你认识到软件开发过程中“唯一不变的是变化”这一条真理。然而这也是一条悖论,如果只有变化的话,那么计划就没有意义了。关键在于我们需要计划出不变的部分,为变化留出空间。
祸起萧墙
项目是怎样延迟了整整一年的时间?…一次一天。
但是一天一天的进度落后是难以识别、不容易防范和难以弥补的。昨天,某个关键人员生病了,无法召开某个会议。今天,由于雷击打坏了公司的供电变压器,所有机器无法启动。明天,因为工厂磁盘供货延迟了一周,磁盘例程的测试无法进行。下雪、应急任务、私人问题、同顾客的紧急会议、管理人员检查——这个列表可以不断地延长。每件事都只会将某项活动延迟半天或者一天,但是整个进度开始落后了,尽管每次只有一点点。
对于这种逐渐延迟的进度,Brooks提议简历项目里程碑,并且持续的修订项目计划,这样无论最后的情况变得多么糟糕,它都不会有太大的变化。里程碑是指百分之百的事件,必须有明显的边界和没有歧义。这样就很好有人可以在里程碑进展上弄虚作假。
另外一面
需要文档的必要性不言而喻,问题在于什么样的文档才是好的文档。
本文中给出了以下文档必要内容的参考:
- 目的。主要的功能是什么?开发程序的原因是什么?
- 环境。程序运行在什么样的机器、硬件配置和操作系统上?
- 范围。输入的有效范围是什么?允许显示的合法范围是什么?
- 实现功能和使用的算法。精确地阐述它做了什么。
- 输入-输出格式。必须是确切和完整的。
- 操作指令。包括控制台及输出内容中正常和异常结束的行为。
- 选项。用户的功能选项有哪些?如何在选项之间进行挑选?
- 运行时间。在指定的配置下,解决特定规模问题所需要的时间?
- 精度和校验。期望结果的精确程度?如何进行精度的检测?
没有银弹——软件工程中的根本和次要问题
没有任何技术或管理上的进展,能够独立地许诺十年内使生产率、可靠性或简洁性获得数量级上的进步。
There is no single development, in either technology or management technique, which by itself promises even one order-of-magnitude improvement within a decade in productivity, in reliability, in simplicity.
软件工程领域最著名的论断。
所有软件活动包括根本任务——打造由抽象软件实体构成的复杂概念结构,次要任务——使用编程语言表达这些抽象实体,在空间和时间限制内将它们映射成机器语言。
软件工程领域的根本难题在于复杂度,一致性,可变性和不可见性。值得注意的是,文章末尾提出了一些可能的银弹,比如面向对象编程,只能解决软件工程中的非本质困难,而对于软件工程根本的问题于事无补。就是说,我们某种程度上能够解决使用编程语言表达抽象的实体,或者将其变得结构化,构建起完整的概念结构,但是仍然没有解决软件工程的根本难题——复杂度、一致性、可变性和不可见性。
因此,现在的技术中最有希望的,并且解决了软件的根本而非次要问题的技术,是开发作为迭代需求过程的一部分——快速原型化系统的方法和工具。
快速原型之所以可以解决根本问题,是因为快速原型有助于澄清软件工程的概念结构,从而降低了后期变更的幅度。基于快速原型进行增量开发,目前已经成为实际开发的标准流程。
再论《没有银弹》
Brooks在这篇文章里面再次讨论了很多潜在的银弹。因为自从《没有银弹》发表以后,遭到了大量的误解、批评和质疑,Brooks专门写了这篇文章来继续解释他的观点和回应批评。
首先一个可能的银弹是Harel提出的一种叫做Vanilla的框架,有助于程序的概念设计和图形化呈现,看上去确实直面软件工程开发的根本困难:复杂性和不可见性。Brooks甚至也赞同如果Vanilla框架得到发展应用,也许就是银弹。但是今天看来,20年过去了似乎Vanilla已经遭人遗忘。显然它并非软件开发的银弹。
另一个可能的银弹是定制软件包的开发。基本上今天的开源社区已经这样做了。大量的公共库被开发出来,确实提高了通用需求的开发效率。Brooks也承认,他低估了软件包客户化的程度和重要性。
面向对象编程,被称为“铜制子弹”。但是面向对象技术“不会加快首次或第二次的开发,产品族中第五个项目的开发才会异乎寻常的迅速”。不过经过20年再来看,面向对象虽然发展缓慢,但是的确已经统治了软件开发行业,称得上一颗“铜制子弹”。
软件重用,也是一个可能的解决方案。
大多数有丰富经验的程序员拥有自己的私人开发库,可以使他们使用大约30%的重用代码来开发软件。公司级别的重用能提供70%的重用代码量,它需要特殊的开发库和管理支持。公司级别的重用代码也意味着需要对项目中的变更进行统计和度量,从而提高重用的可信程度。
但是重用面临一个问题,就是重用所带来的好处,必须大于其代价,才得以实施。比如一个数学库函数,如果不重用,那么程序员自己需要学习大量的相关知识才能写得出来。而对于项目中的某个功能,与其花费很多功夫寻找重用的模块,可能程序员直接重新实现一次是更快捷的做法。
重用是一件说起来容易,做起来难的事情。它同时需要良好的设计和文档。即使我们看到了并不十分常见的优秀设计,但如果没有好的文档,我们也不会看到能重用的构件。
“不管怎样,重用的模块一般是一些通用功能。”
软件重用的另一个问题是学习的成本。越复杂的功能,学习成本越高。高级语言比机器语言功能强大,但是也更加复杂。而重用一个模块,则需要学习相应该模块的成本。这种成本今天已经在各类专门开发职业中体现出来,如后台程序员,Web前段或者手机客户端,不同类别的程序员差别就在于其对某一重用模块的专门知识的掌握。
20年后的人月神话
今天,我比以往更加确信。概念完整性是产品质量的核心。拥有一位结构式是迈向概念完整性的最重要一步。这个原理不仅限于软件系统,它适用于所有的复杂事物。
如果要我用一个词语来概括人月神话,我想我会说“沟通代价”;如果可以有两个词,那就加上“概念完整性”。
20年后的人月神话有些结论得到验证,有些情况已经变化,下面是这些情况的简单概括:
- 第二系统定律得到验证:开发第二个系统总是因为盲目的功能导致易用性、甚至是可用性的灾难。
- 图形界面的成功
- 瀑布模型被证明是错的了,因为没有构建舍弃原型。事实上增量开发与快速迭代才是理想的开发方式。
- 增量开发和快速原型,渐进地精华,让软件像生物进化那样逐渐演化成更为复杂的结构,演化出更多的功能。
- 信息隐藏:Parnas是正确的,我是错误的。20年前关于信息隐藏的两大观念,其一是Brooks主张的,所有的程序员应该了解所有的材料。而Parnas则认为代码模块应该采用定义良好的接口来封装,这些模块内部结构应该是程序员的私有财产。Brooks承认,Parnas所主张的方案确实更符合实际。
- 对人月神话实际研究发现,向进度落后的项目中添加人手会增加项目的成本,但是不一定会使项目更加落后。如果在项目早期添加额外的人比在后期添加额外的人更安全些。
- 人就是一切。这一点可以从《人件:高生产率的项目和团队》可以见出。
- 放弃权利的力量——公司通过将权利下放到具体的团队,事实上使得组织机构变得更加“融洽和繁荣”。
- 最令人惊讶的新事物——数百万的计算机
- 使用塑料包装的成品软件包作为构建:成熟的模块和对象组合提升了软件复用的层次。
软件工程的未来
软件工程的焦油坑在将来很长一段时间内会继续地使人们举步维艰,无法自拔。软件系统可能是人类创造中最错综复杂的事物,只能期待人们在力所能及的或者刚刚超越力所能及的范围内进行探索和尝试。这个复杂的行业需要:进行持续的发展;学习使用更大的要素来开发;新工具的最佳使用;经论证的管理方法的最佳应用;良好判断的自由发挥;以及能够使我们认识到自己不足和容易犯错的——上帝所赐予的谦卑。
参考
《人月神话》FREDERICK P. BROOKS, JR.