《人月神话》读书笔记

来源:互联网 发布:常用linux的shell 编辑:程序博客网 时间:2024/04/28 21:22

序言

《人月神话》作为最近十年排名第2的计算机书籍,可谓声名显赫!(http://www.dearbook.com.cn/subject/top50/)
我第一次听说这本书是2003年下半年,上OOAD课时,老师推荐的参考读物之一。
我当时便买来,挺薄的一本书,很快就读完了。
读完之后,没有什么太多的感受。越到后面越觉得不知所云,没什么实际内容。
有点怀疑它是否被宣传过分夸大。类似小时候看过的一本畅销书——《学习的革命》。
在学校的时候,总是被灌输,软件工程相关的书籍在没有很多开发经验的情况下,是不容易看懂的。当经验积攒足够之后,再回过头来看,会有一种字字真理的感觉。
坦白讲,学生时代,我一直怀疑这种观点。
因为我认为真理是没有界限的,真理是能够举一反三的,而且我足够聪明。
今天,4年多一转眼就过去了。我在第一线辛勤地工作快两年了。
不久之前,我看到《人月神话》32周年纪念版出版的消息,业界反响十分强烈。
于是乎,我抱着试一试的态度,重新拿起这本书。
谁料刚读完第一章便有无法释卷的感觉!
第一章中的种种描述和我日常工作时的心情形成绝妙的暗合!我仿佛瞬间找到了知音!
随着阅读的进行,我心里不时浮现出一句台词——
人类是最不长记性的动物。(《血色浪漫》郑桐)
我时常感到意识上的错位,似乎我看的不是一本技术书籍,而是一本历史书籍。
前人在30几年前犯下的错误,我们今天仍然在犯;前人在30几年前总结出的经验,我们今天却根本没有吸收。
软件开发最大的魅力在于控制,程序员对产品拥有完全的控制力,它满足了人类的创造欲和权力欲。
软件开发最大的问题在于控制,程序员以为自己无所不能,它诱发了人类贪婪和自大的天性。
再一次读《人月神话》给了我很多启示,让我受益匪浅!
我决定把一些关键点提取出来,记录下来,并加入少许我的感想,以后不时看看,以提醒自己保持清醒的头脑,并从前人的经验中汲取养分。

1 焦油坑

正确认识软件开发这个职业。

1.1 编程系统产品

多数情况下,我们对软件的认识仅仅是程序。这一认识是错误的,会导致盲目的乐观。
程序转化(通用化、测试、文档、维护)为编程产品需要至少三倍的成本。程序转化(接口、系统集成)为编程系统也需要至少三倍的成本。
而编程系统产品才是大多数情况下,我们最终需要的东西,它的成本高达九倍。

1.2 职业的乐趣

软件本身的特点满足了人类的创造欲;
软件能帮助他人;
软件开发过程体现出魔术般的力量;
软件开发的非重复性带来学习的乐趣;
程序员几乎能完全驾驭程序,让概念变为现实。

1.3 职业的苦恼

必须追求完美,而很少的人类活动要求完美;
由他人来设定目标,供给资源,提供信息;
程序员需要依赖他人,而现实情况下,其他人往往靠不住;
创造性活动的同时,也伴随着重复性的体力劳动;
竞争对手有时会让大量劳动赴之东流。

2 人月神话

缺乏合理的时间进度是造成项目滞后的主要原因,导致这种普遍性灾难的原因是什么?
我们对估算技术缺乏研究,并错误地假设一切都运作良好;
我们错误地假设人和月可以互换;
软件经理通常不会有耐心,持续地进行估算这项工作;
对进度缺少跟踪和监督;
当进度发生偏移时,增加人手,从而进入恶性循环。

2.1 乐观主义

软件开发基于极易掌控的介质——思维中的概念。
这一点不同于人类的其他创造性活动,从而使得乐观主意情绪在程序员中蔓延。
构思的不完整性和不一致性往往在实现阶段才浮现,从而影响了进度安排的准确性。

2.2 人月

用人月作为衡量软件的规模暗示人员的数量和时间可以互换。这是危险和极具欺骗性的。
许多软件由于次序上的限制不能分解,故而人手的增加没有任何作用。
对于可以分解的任务,必须考虑到人员沟通所带来的工作量。沟通包括交流和培训,这是不可分解的。而且随人数的增加而增加。可能出现人数增加,进度反而变慢的情况。

2.3 系统测试

系统测试的进度安排是编程中最不合理的部分。
对于软件任务的进度安排,作者的经验法则:1/3计划、1/6编程、1/4构件测试和早期系统测试、1/4系统测试(所有构件已完成)。
很少有项目为测试安排1/2的时间,但它实际上会占用这么多的时间。
延迟发现的错误带来的二次成本远远高于其他开销。

2.4 空泛的估算

软件经理对进度的估算带有强烈的直觉色彩,而缺乏方法和数据的支持。

2.5 重复产生的灾难

向进度落后的项目中增加人手,只会使进度更加落后。
恶性循环。

3 外科手术队伍

一个幼稚的观点——头等人才组成的小型队伍胜过几百平庸程序员组成的大型队伍。
如何在有意义的时间进度内创建大型应用?

3.1 问题

研究表明,最好的程序员的生产率是最差的程序员的10倍。
系统应该由尽量少的人员来开发。大型队伍一拥而上的方法是高成本的、速度缓慢的、不充分的。
而另一方面,对于真正意义上的大型系统来说,小型队伍需要的时间会非常长。
进退两难。

3.2 Mills的建议

大型系统的每个部分由一个团队解决,而该队伍以类似外科手术的方式组建。
不是每个成员截取问题的一部分,而是由一个人来分解问题,其他人给予支持。
外科医生(首席程序员):他亲自定义功能和性能技术说明书,设计程序,编制源代码,测试以及书写技术文档。首席程序员需要极高的天分、十年的经验和应用数学、业务数据处理或其他方面的大量系统和应用知识。
副手:他是外科医生的后备,能完成任何一部分工作,但是相对具有较少的经验。他的主要作用是作为设计的思考者、讨论者和评估人员。外科医生试图和他沟通设计,但不受到他建议的限制。他需要详细了解所有的代码,研究设计策略的备选方案。显然,他充当外科医生的保险机制。他甚至可能编制代码,但针对代码的任何部分,不承担具体的开发职责。
管理员:一个控制财务、人员、工作地点安排和机器的专业管理人员,该管理员充当与组织中其他管理机构的接口。仅在项目具有法律、合同、报表和财务方面的需求时,管理员才具有全职责任。否则,一个管理员可以为两个团队服务。
编辑:外科医生负责产生文档——出于最大清晰度的考虑,他必须书写文档。对内部描述和外部描述都是如此。而编辑根据外科医生的草稿或者口述的手稿,进行分析和重新组织,提供各种参考信息和书目,对多个版本进行维护以及监督文档生成的机制。
两个秘书:管理员和编辑每个人需要一个秘书。管理员的秘书负责项目的协作一致和非产品文件。
程序职员:他负责维护编程产品库中所有团队的技术记录。该职员接受秘书性质的培训,承担机器码文件和可读文件的相关管理责任。所有的计算机输入汇集到这个职员处。如果需要,他会对它们进行记录或者标识。输出列表会提交给程序职员,由他进行归档和编制索引。另外,他负责将任何模型的最新运行情况记录在状态日志中,而所有以前的结果则按时间顺序进行归档保存。
工具维护人员:承担团队成员所需要的特殊工具的构建、维护和升级责任。即使已经拥有非常卓越的、可靠的集中式服务,每个团队仍然要有自己的工具人员。因为他的工作是检查他的外科医生所需要的工具。工具维护人员常常要开发一些实用程序、编制具有目录的过程库以及宏库。
测试人员:外科医生需要大量合适的测试用例,用来对他所编写的工作片段,以及对整个工作进行测试。因此,测试人员既是为他的各个功能设计系统测试用例的对头,同时也是为他的日常调试设计测试数据的助手。他还负责计划测试的步骤和为测试搭建测试平台。
语言专家:大多数计算机项目中,总有一两个乐于掌握复杂编程语言的人。这些天才不同于外科医生,外科医生主要是系统设计者以及考虑系统的整体表现。而语言专家则寻找一种简洁、有效的使用语言的方法来解决复杂、晦涩或者棘手的问题。他通常需要对技术进行一些研究(两到三天)。通常一个语言专家可以为两个到三个外科医生服务。
以上Mills概念的真正关键是“从个人艺术到公共实践”的编程观念的转换。通过专业分工,使得整个软件系统成为整个团队的公共财产。

3.3 如何运作

虽然团队人数不少,但系统出自一个人或最多两个人的思考,因此概念一致性得到了保证。
传统的分工方式是对工作进行划分,每个人负责一部分,人人平等,接口和思想的不同在集成阶段由沟通来协调。
而外科手术式的队伍中,不存在概念的不一致性和利益的差别,因为上下级关系的存在,所有的不一致都由外科医生来统一。
团队中剩余人员职能的专业化分工是高效的关键,它使成员之间采用非常简单的交流模式成为可能

3.4 团队的扩建

大型项目由多个外科手术式团队组成。问题的关键在于必须统一所有外科医生的思路以达到整个系统的概念一致性。
需要一个系统结构师从上至下地进行所有的设计,必须清晰地划分体系结构设计和实现之间的界线,分解之后的任务交给一个个外科医生。

3.5 评

对于软件系统进行水平分解,然后一拥而上,是很直观的做法。
这种做法貌似提高了生产率,但其带来的、表面的缺点是集成困难。而集成是最后一步,且不可分解,所以成本在此急剧提高。
这种做法根上的原因在于各个部件概念上的不一致性,因为它们出自不同的人。
另外,在这种方式下,程序员承担了所有的工作,程序员需要掌握太多的专业技能,不利于提高生产率。
外科手术的队伍有两个特点:
  • 概念一致性由唯一的外科医生保障;
  • 按照专业进行分工,以提升每个人特定的专业技能。
卓越的想法,但我经历过的所有软件公司都没有采用,都是一拥而上。希望有一天我能主导实施这样的一个团队。

4 贵族专制、民主政治和系统设计

论证垂直分解的一些方法,以及传统理解的误区。

4.1 概念完整性

在系统设计中,概念完整性应该是最重要的考虑因素。
也就是说为了反映一系列连贯的设计思路,宁可省略一些不规则的特性和改进,也不提倡独立和无法整合的系统,哪怕它们其实包含着许多很好的设计。

4.2 获得概念的完整性

软件功能与理解上复杂程度的比值才是系统设计的最终测试标准。过分夸大功能是一个广泛的错误。
对于给定级别的功能,能用最简洁和直接的方式来指明事情的系统是最好的。
易用性实际上需要设计的一致性和概念上的完整性。

4.3 贵族专制统治和民主政治

概念的完整性要求设计必须由一个人,或者非常少数互有默契的人员来实现。而进度压力却要求很多人员来开发系统。
有两种方法可以解决这种矛盾。第一种是仔细地区分设计方法和具体实现。第二种是前一章节中所讨论的、一种崭新的组建编程开发团队的方法。
系统的体系结构指的是完整和详细的用户接口说明。
系统的结构师,是用户的代理人。结构师的工作,是运用专业技术知识来支持用户的真正利益,而不是维护销售人员所鼓吹的利益。
体系结构同实现必须仔细地区分开来。体系结构陈述的是发生了什么,而实现描述的是如何实现。
并非只有结构师才能想出好的主意,但为了系统的概念完整性,必须抛弃不能与系统基本概念进行整合的良好想法和特色。如果出现了很多非常重要但不兼容的构想,就应该抛弃原来的设计,对不同基本概念进行合并,在合并后的系统上重新开始。
为了得到系统概念上的完整性,必须由少数人控制这些概念,这是一种无需任何歉意的贵族专制统治。
结构师之外的工作并非没有创造性,它只是一项性质不同的创造工作而已。
在毫无限制的团队中,民主会消耗掉过多的精力。

4.4 在等待时,实现人员应该做什么?

实现同设计一样是一项高级别的创造性活动。具体实现中创造和发明的机会,并不会因为设计人员指定的外部技术说明而大为减少,相反创造性活动会因为规范化而得到增强,整个产品也一样。
设计阶段,实现人员无所事事。这是一个误解,有两种对策:
  • 设计完成的时候再雇佣编程实现人员;
  • 设计阶段和实现阶段有不少内容是可以并行的。
概念的完整性的确要求系统只反映唯一的设计理念,用户所见的技术说明来自少数人的思想。实际工作被划分成体系结构、设计实现和物理实现,但这并不意味着该开发模式下的系统需要更长的时间来创建。经验显示恰恰相反,整个系统将会开发得更快,所需要的测试时间将更少。同工作的水平分割相比,垂直划分从根本上大大减少了劳动量,结果是使交流彻底地简化,概念完整性得到大幅提高。

5 画蛇添足

如何约束结构师的创造热情以使得设计结果不超出开发能力?结构师和开发人员之间彻底仔细的沟通。
这一沟通存在困难。

5.1 结构师的交互准则和机制

结构师将设计结果交给开发人员,获得反馈通常会有较高的估算。
对此,结构师有两种选择:削减设计或建议成本更低的实现方法。
结构师必须注意:
  • 牢记是开发人员承担创造性和发明性的实现责任,所以结构师只能建议,而不能支配;
  • 时刻准备着为所指定的说明建议一种实现的方法,同样准备接受其他任何能达到目标的方法;
  • 对上述的建议保持低调和平静;
  • 准备放弃坚持所作的改进建议。

5.2 自律——开发第二个系统所带来的后果

在开发第一个系统时,结构师倾向于精炼和简洁。不熟悉的润色功能会被推迟到下一个系统。
第二个系统是设计师们所设计的最危险的系统。一种普遍倾向是过分地设计第二个系统,向系统添加很多修饰功能和想法。
再往后的系统会因为经验的丰富而降低此类危险。
结构师无法跳过第二个系统,但他可以有意识关注那些系统的特殊危险,运用特别的自我约束准则,来避免那些功能上的修饰;根据系统基本理念及目的变更,舍弃一些功能。
对于项目经理,他必须坚持至少拥有两个系统以上开发经验结构师的决定。同时,保持对特殊诱惑的警觉。

5.3 评

第二个系统的过度设计,这是一个常常出现,却几乎完全被忽略的现象。
作者提出此观点警示结构师,并提供了一些方法约束结构师。
不仅是第二个系统,即便后第三、第四个系统,也需要结构师保持足够的警惕。
面对新功能的诱惑,不是谁都能保持冷静的。

6 贯彻执行

如何贯彻结构师的设计意图?

6.1 文档化的规格说明——手册

手册是产品的外部规格说明,它描述和规定了用户所见的每一个细节;它也是结构师主要的工作产物。
手册需要不断地修改,然而对实现人员而言,修改的阶段化是很重要的——在进度表上应该有带日期的版本信息。
手册不但要描述包括所有界面在内的用户可见的一切,它同时还要避免描述用户看不见的事物。后者是编程实现人员的工作范畴,而实现人员的设计和创造是不应该被限制的。结构师必须为自己描述的任何特性准备一种实现方法,但是他不应该试图支配具体的实现过程。
手册的风格必须清晰、完整和准确。精确比生动重要。
好的手册在定义了规定什么的同时,还定义了未规定什么。

6.2 形式化定义

语言是不够精确的,所以需要引入形式化标记方法。
形式化定义的优点是精确,缺点是不容易理解。
规格说明可以同时使用形式化定义和记叙性文字,但必须以一种为主,一种为辅。
实现作为定义有一些优点,但缺点更显著,定义将被错误地扩大。

6.3 直接整合

软件结构师的一种强制方法,直接写出模块间的函数和变量声明,然后要求源程序引用。

6.4 会议和大会

会议分为两个级别——周例会和年度大会。
周例会,任何人可以提出建议,但必须事先分发建议书。重点是创新而不是结论。
反复几次后,一些问题会形成结论,不能形成的有首席结构师决策。
年度大会(或半年大会)一般持续两周,典型的包括200个议程,每天早上分发昨天形成的决议。
年度大会,不仅可以解决决策上的问题,而且使决策更容易被接受。每个人都在倾听,每个人都在参与,每个人对复杂约束和决策之间的相互关系有了更透彻的理解。

6.5 多重实现

在大多数计算机项目中,机器和手册之间往往会在某一天出现不一致,人们通常会忽略手册。因为与机器相比,手册更容易改动,并且成本更低。然而,当存在多重实现时,情况就不是这样。这时,如实地遵从手册更新机器所造成的延迟和成本的消耗,比根据机器调整手册要低。

6.6 电话日志

对于存有疑问的实现人员,应鼓励他们打电话询问相应的结构师。
一种有用的机制是由结构师保存电话日志。日志中,他记录了每一个问题和相应的回答。每周,对若干结构师的日志进行合并,重新整理,并发布给用户和实现人员。

6.7 产品测试

每个开发机构都需要这样一个独立的技术监督部门,来保证其公正性。
设立测试小组是使设计决策得以贯彻执行的必要手段,同样也是需要尽早着手,与设计同时实施的重要环节。

7 为什么巴比伦塔会失败

7.1 巴比伦塔的管理教训

巴比伦塔缺少的东西——交流、组织。

7.2 大型编程项目中的交流

团队如何进行相互之间的交流沟通:
  • 非正式途径。电话。
  • 会议。常规项目会议。
  • 工作手册。项目开始就准备。

7.3 项目工作手册

是什么:
项目工作手册不是独立的一篇文档,它是对项目必须产出的一系列文档进行组织的一种结构。
项目所有的文档都必须是该结构的一部分。这包括目的、外部规格说明、接口说明、技术标准、内部说明和管理备忘录。
为什么:
技术说明几乎是必不可少的。其内容不仅仅是思路,而且还有能追溯到最早备忘录的许多文字和章节,这些备忘录对产品提出建议或者解释设计。
控制信息发布。确保信息能达到所有需要它的人手中。
处理机制:
每一个编程人员应该了解所有的材料。工作手册的实时更新是非常关键的。
理解的问题可以通过持续的文档维护来解决。
现在如何入手:
文档的更新和分发,需要工具的支持。

7.3 大型编程项目的组织架构

团队组织的目的是减少不必要交流和合作的数量,因此良好的团队组织是解决上述交流问题的关键措施。
减少交流的方法是人力划分和限定职责范围。
树状组织架构是作为权力和责任的结构出现的,交流通过网状结构进行。
树状编程队伍中每棵子树所必须具备的基本要素:
  1. 任务(a mission)
  2. 产品负责人(a producer)
  3. 技术主管和结构师(a technical director or architect)
  4. 进度(a schedule)
  5. 人力的划分(a division of labor)
  6. 各部分之间的接口定义(interface definitions among the parts)
产品负责人和技术主管存在一些容易混淆的地方。
产品负责人的角色:他组建团队,划分工作及制订进度表。他要求,并一直要求必要的资源。这意味着他主要的工作是与团队外部,向上和水平地沟通。他建立团队内部的沟通和报告方式。最后,他确保进度目标的实现,根据环境的变化调整资源和团队的构架。
技术主管的角色:他对设计进行构思,识别系统的子部分,指明从外部看上去的样子,勾画它的内部结构。他提供整个设计的一致性和概念完整性;他控制系统的复杂程度。当某个技术问题出现时,他提供问题的解决方案,或者根据需要调整系统设计。他的沟通交流在团队中是首要的。他的工作几乎完全是技术性的。
两者所需技能完全不同。
作者建议在小型团队中,技术主管作为总指挥,产品负责人充当其左右手。在大型团队中,产品负责人作为管理者更合理。
对于后者,产品负责人必须树立技术主管的技术权威。

8 胸有成竹

工作量是规模的幂函数。
生产率会根据任务本身复杂度和困难程度表现出显著差异。在复杂程度估计这片“沼泽”上的指导原则是:编译器的复杂度是批处理程序的三倍,操作系统复杂度是编译器的三倍。
对常用编程语句而言。生产率似乎是固定的。这个固定的生产率包括了编程中需要注释,并可能存在错误的情况.
使用适当的高级语言,编程的生产率可以提高5倍。

9 削足适履

9.1 作为成本的程序空间

软件的规模是软件的一个重要开销。
控制规模很重要,但是不是越小越好,得看设计目的。
规模本身不是坏事,但不必要的规模就不可取了。

9.2 规模控制

仅对核心程序设定规模目标是不够的,必须把所有的方面都编入预算。
和制订驻留空间预算一样,应该制订总体规模的预算;和制订规模预算一样,应该制订后台存储访问的预算。
在指明模块有多大的同时,确切定义模块的功能。
培养开发人员从系统整体出发、面向用户的态度是软件编程管理人员最重要的职能。
对大型项目而言,开发人员默默优化自己的模块且缺乏交流,是项目最大的危险。

9.3 空间技能

减少程序空间的常用方法——
  • 减少功能;
  • 确保开发人员在编程技能上的培训;
  • 开发积累公共构件。

9.4 数据的表现形式是编程的根本

技艺改进的结果往往是战略上的突破,而不仅仅是技巧上的提高。
战略上突破常来自数据或表的重新表达——这是程序的核心所在。
数据结构的重要性 > 程序流程图。

10 提纲挈领

文档的跟踪维护是项目监督和预警的机制。文档本身可以作为检查列表、状态控制,也可以作为汇报的数据基础。

10.1 计算机产品的文档

  • 目标:定义待满足的目标和需要,定义迫切需要的资源、约束和优先级。
  • 技术说明:计算机手册和性能规格说明。它是在计划新产品时第一个产生,并且最后完成的文档。
  • 进度、时间表
  • 预算:预算不仅仅是约束。对管理人员来说,它还是最有用的文档之一。预算的存在会迫使技术决策的制订,否则,技术决策很容易被忽略。更重要的是,它促使和澄清了策略上的一些决定。
  • 组织机构图
  • 工作空间的分配
报价、预测、价格:这三个因素互相牵制,决定了项目的成败。

10.2 软件产品的文档

立刻正式生成若干文档作为自己的数据基础,哪怕这些迷你文档非常简单。
  • 做什么:目标。定义了待完成的目标、迫切需要的资源、约束和优先级。
  • 做什么:产品技术说明。以建议书开始,以用户手册和内部文档结束。速度和空间说明是关键的部分。
  • 时间:进度表
  • 资金:预算
  • 地点:工作空间分配
  • 人员:组织图。它与接口说明是相互依存的。

10.3 为什么要有正式的文档

书面记录决策是必要的;
文档能够作为同其他人的沟通渠道;
项目经理的文档可以作为数据基础和检查列表。

11 未雨绸缪

不变只是愿望,变化才是永恒。

11.1 实验性工厂和增大规模

对于大多数项目,第一个开发的系统并不合用。要解决所有的问题,除了重新开始以外,没有其他的办法。
管理上的问题不再是“是否构建一个试验性的系统,然后抛弃它?”,你必须这样做。
将原型发布给用户,百害而无一利。
为舍弃而计划,无论如何,你一定要这样做。

11.2 唯一不变的就是变化本身

开发人员交付的是用户满意程度,而不仅仅是实际的产品。
软件产品易于掌握的特性和不可见性,导致它的构建人员面临永恒的需求变更。
不但目标上的变化不可避免,而且设计策略和技术上的变化也不可避免。抛弃原型概念本身就是对事实的接受——随着学习的过程更改设计。

11.3 为变更计划系统

最重要的措施是使用高级语言和自文档技术,以减少变更引起的错误。采用编译时的操作来整合标准声明,在很大程度上帮助了变化的调整。
变更的阶段化是一种必要的技术。每个产品都应该有数字版本号,每个版本都应该有自己的日程表和冻结日期,在此之后的变更属于下一个版本的范畴。

11.4 为变更计划组织架构

通过设计文档化,设计人员将自己暴露在每个人的批评之下,他必须能够为他的每个结果进行辩护。如果团队架构因此受到任何形式的威胁,则没有任何东西会被文档化,除非架构是完全受到保护的。
只要管理人员和技术人才的天赋允许,老板必须对他们的能力培养给予极大的关注,使管理人员和技术人才具有互换性。
在管理线和技术线上分别建立晋升路线是一种降低内部矛盾的办法。
组建外科手术式的队伍是另外一种方法。

11.5 前进两步,后退一步

对于一个广泛使用的程序,其维护总成本通常是开发成本的40%或更多。
维护阶段引入新的bug是一件容易发生,但是非常头痛的事情。
使用能消除、至少是能指明副作用的程序设计方法,会在维护成本上有很大的回报。同样,设计实现的人员越少、接口越少,产生的错误也就越少。

11.6 前进一步,后退一步

大型操作系统的历史表明,所有修改都倾向于破坏系统的架构,增加了系统的混乱程度。
系统软件开发是减少混乱度的过程,所以它本身是处于亚稳态的。软件维护是提高混乱度的过程,即使是最熟练的软件维护工作,也只是放缓了系统退化到非稳态的进程。

12 干将莫邪

软件项目的现状:每个骨干人员都仔细地保管自己工作生涯中搜集的一套工具集,这些工具成为个人技能的直观证明。
这种方法对软件项目来说是愚蠢的。首先,项目的关键问题是沟通,个性化的工具妨碍——而不是促进沟通。其次,当技术发生变化时,所有工具的生命周期是很短的。
开发和维护公共的通用编程工具的效率更高。
为每个团队配备一名工具管理人员是一个好办法。这个角色管理所有通用工具,指导其他人使用工具,并编制需要的专业工具。
项目经理必须意识到专业工具的需求,对工具的开发不能吝啬人力物力。
对于稀缺资源(比如工作站),采用分时的方式,分配给各个小组是一种好的方法。
仿真装置、编译器、汇编平台、程序库管理系统、编程工具、文档系统、性能防震装置都是项目管理需要的。

13 整体和部分

如何开发一个可以运行的系统?如何测试系统?如何将经过测试的一系列构件集成到已测试过、可以依赖的系统?

13.1 剔除bug的设计

13.1.1 防范bug的定义

产品的概念完整性可以使得开发更容易进行以及bug更不容易产生。
关键的工作是产品定义。许许多多的失败完全源于那些产品未精确定义的地方。

13.1.2 测试规格说明

在编写任何代码之前,规格说明必须提交给测试小组,以详细地检查说明的完整性和明确性。

13.1.3 自顶向下的设计

自顶向下,逐步精化。
  • 清晰的结构和表达方式更容易对需求和模块功能进行精确的描述;
  • 模块分割和模块独立性避免了系统级的bug;
  • 细节的隐藏使结构上的缺陷更加容易识别;
  • 设计在每个精化步骤的层次上是可以测试的,所以测试可以尽早开始,并且每个步骤的重点可以放在合适的级别上。

13.1.4 结构化编程

现在已有很多更高层的编程方法,当然结构化编程依然占据了重要地位。

13.2 构件单元调试

这一步非常重要,但内容涉及具体的技术细节,略显陈旧。

13.3 系统集成调试

系统集成测试是非常困难的一个部分。
使用经过调试的构件单元。
搭建充分的测试平台。测试平台可能会有相当于测试对象一半的代码量,但这是合乎情理的。
控制变更。
一次添加一个构件。拒绝诱惑。
阶段(量子)化、定期变更。

14 祸起萧墙

项目进度的偏移是由一些小问题,日积月累而成的。

14.1 里程碑还是沉重的负担

里程碑必须是具体的、特定的、可度量的事件,能够进行清晰定义。有明显边界且没有歧义。
  • 如果在某项活动开始之前就着手估计,并且每两周进行一次仔细的修订。这样,随着开始时间的临近,无论最后情况会变得如何的糟糕,它都不会有太大的变化。
  • 活动期间,对时间长短的过高估计,会随着活动的进行持续下降。
  • 过低估计在活动中不会有太大的变化,一直到计划的结束日期之前大约三周左右。

14.2 “其他的部分反正会落后”

对软件开发队伍,进取是非常必要的。进取提供了缓冲和储备,使开发队伍能够处理常规的异常事件,可以预计和防止小的灾祸。
必须关心每一天的滞后,它们是大灾祸的基本组成元素。

14.3 地毯的下面

一线经理的利益和老板的利益是内在冲突的。他会把一些污垢埋在地毯下面,不让老板知道。
这存在潜在的危险,有两种办法来处理:
  • 减少角色的冲突,老板必须规范自己,不对项目经理可以解决的问题做出反应,并且决不在检查状态报告的时候做安排;
  • 猛地拉开地毯,定期检查,或者安排专人检查。

15 另外一面

对于软件来说,文档很重要。

15.1 需要什么样的文档

不同的用户需要使用不同级别的文档。
使用程序:
  • 目的
  • 环境
  • 范围
  • 实现功能和使用的算法
  • 输入-输出格式
  • 操作指令
  • 选项
  • 运行时间
  • 精度和校验
验证程序:
  • 测试用例
修改程序:
  • 流程图或子系统的结构图
  • 对所用算法的完整描述
  • 对所有文件规划的解释
  • 数据流的概要描述以及在每个处理过程完成的操作
  • 初始设计中,对已预见修改的讨论;特性、功能回调的位置以及出口;原作者对可能会扩充的地方以及可能处理方案的一些意见
  • 对隐藏缺陷的观察也同样很有价值

15.2 流程图

流程图的作用被过分的夸大了。很多程序不需要它。
对于需要流程图的地方,尽量在一页纸上完成整个流程图的绘制。

15.3 自文档化的程序

程序和文档的同步是痛苦的。
将它们合并,直接在程序中添加说明性的文字,是一个好方法。

16 20年后的人月神话

概念完整性是产品质量的核心。拥有一位结构师是迈向概念完整性的最重要一步。
第二系统在开发前一定要明确真正的目标。
瀑布模型是错误的,因为它假设任何软件都一次成功。
增量开发模型是值得提倡的。
信息隐藏是正确的,代码模块应该采用定义良好的接口来封装,编程人员被屏蔽而不是暴露在他人模块内部结构面前。
人就是一切。
下放权力给开发团队,就收获意料之外的好处。