本文绝大多数是直接从《人月神话》中摘录而来,去掉了一些认为与项目管理及团队相关的描述。
焦油坑
编程的乐趣与苦恼
思维创造性活动的特性注定在这个创造活动中有太多的困难与不确定因素,每个细小的偏离的累积都会象焦油坑一样使你举步维艰。
一 人月神话
编程,一个许多人痛苦挣扎的焦油坑以及一种乐趣和苦恼共存的创造性活动。对于许多人而言,其中的乐趣远大于苦恼。而本书的剩余部分将试图搭建一些桥梁,为通过这样的焦油坑提供一些指导。
在众多软件项目中,缺乏合理的时间进度是造成项目滞后的最主要原因,它比其它所有因素加起来的影响还大。导致这种普通性灾难的原因是什么呢?
首先,我们对估算技术缺乏有效的研究,更加严肃地说,它反映了一种悄无声息,但并不真实的假设--一切都将运作良好。
第二,我们采用的估算技术隐含地假设人和月可以互换,错误地将进度与工作量相互混淆。
第三,由于对自己的估算缺乏信心,软件经理通常不会有耐心持续地进行估算这项工作。
第四,对进度缺少跟踪和监督,其它工程领域中,经过验证的跟踪技术和常规监督程序,在软件工程中常常被认为是无谓的举动。
第五, 当意识到进度偏移时,下意识(以及传统)的反应就是增加人力。这就像用汽油灭火一样,只会使事情更糟。越来越大的火势需要更多的汽油,从而进入了一场注定会导致灾难的手环。
对于软件任务的进度安排,以下是我使用了很多年的经验法则:
1/3 计划
1/6 编码
1/4 构件测试和早期系统测试
1/4 系统测试,所有的构件已完成
项目的时间依赖顺序上的限制,人员的数量依赖于单个子任务的数量。
注:这句话怎么理解的呢,顺序是指在软件开发周期中几个大步骤是有相对严格的时间顺序的,只有一个一个地完成才可以进行后续步骤。
在某个时间段的能进行的任务可以分派多少人由这个任务可以分解成多少个子任务而定。因为这些子任务可以由多人并行地完成。如果某个任务只能由一人来完成,这时安排再多的人也
没有用,下个步骤也只能等待这个任务完成。
二 外科手术队伍
传统的外科手术型队伍(外科医生,副手,管理员,编辑,两个秘书,程序职员,工具维护人员,测试人员,语言专家)
不同的开发人员体现在生产率上的差距还是非常大的
如果是小的系统则由一个精干的外科手术型的队伍则更为不效,对大型系统来说也可以依此来组建团队,大的系统分成小的部分,每个部分由这样的小型团队来完成。
在这种团队中由少数内个精干的人员组成,各司其职,角色职责明确,这样可以减少沟通等其它的成本。最大化提高生产率。
如此结构的好处是既然获得上少数头脑产生的产品完整性,又能得到多位协助人员的总体生产率。还彻底减少了沟通的工作量。
三 贵族专制,民主政治和系统设计
概念完整性是系统设计中最重要的考虑因素。
为了获得概念完整性,设计必须由一个人或者具有共识的小型团队来完成。
“对于非常大型的项目,将设计方法、体系结构方面的工作与具体实现相分离是获得概念完整性的强有力方法。”( 同样适用于小型项目。)
“如果要得到系统概念上的完整性,那么必须控制这些概念。这实际上是一种无需
任何歉意的贵族专制统治。”
四 画蛇添足
尽早交流和持续沟通能使结构师有较好的成本意识,以及使开发人员获得对设计的信心,并且不会混淆各自的责任分工。
结构师的交互准则和机制
面对估算过高的难题,结构师有两个选择:消减设计或建议成本更低的实现方法--挑战估算的结果。后者是固有的主观感性反应。此时结构师是在向开发人员的做事方式
提现挑战,想要成功,结构师必须
1 牢记是开发人员承担创造性和发明性的实现责任,所以结构师只能建议,而不能支配;
2 时刻准备着为所指定的说明建议一种实现的方法,同样准备接受其它任何能达到目标的方法。
3 对上述的建议保持低调和平静。
4 准备放弃坚持所作的改进建议
一般开发人员会反对酸体系结构上的修改建议。通常他是对的,当正在实现产品时,某些特性的修改会造成意料不到的成本开销。
第二个系统是人们所设计的最危险的系统,通常的倾向是过分地进行设计。
五 贯彻执行
1 即使是大型的设计团队,设计结果也必须由一个或两个人来完成,以确保这些决定是一致的。
2 必须明确定义体系结构中与先前定义不同的地方,重新定义的详细程度应该与原先的说明一致。
3 出于精确性的考虑,我们需要形式化的设计定义,同样,我们需要记叙性定义来加深理解。
4 必须采用形式化定义和记叙性定义中的一种作为标准,另一种作为辅助措施;它们都可以作为表达的标准。
5 设计实现,包括模拟仿真,可以充当一种形式化定义的方法;这种方法有一些严重的缺点。
6 直接整合是一种强制推行软件的结构性标准的方法。[ 硬件上也是如此——考虑内建在ROM 中的Mac WIMP接口。]
7 “如果起初至少有两种以上的实现,那么(体系结构)定义会更加整洁,会更加规范。”
8 允许体系结构师对实现人员的询问做出电话应答解释是非常重要的,并且必须进行日志记录和整理发布。[ 电子邮件是一种可选的介质。]
9 “项目经理最好的朋友就是他每天要面对的敌人——独立的产品测试机构/ 小组。”
六 为什么巴比伦塔会失败
缺乏交流及交流的结果-组织。
1 “因为左手不知道右手在做什么,从而进度灾难、功能的不合理和系统缺陷纷纷出现。”由于对其他人的各种假设,团队成员之间的理解开始出现偏差
2 团队应该以尽可能多的方式进行相互之间的交流:非正式、常规项目会议,会上进行简要的技术陈述、共享的正式项目工作手册。(以及电子邮件。)
项目工作手册
4 项目工作手册“不是独立的一篇文档,它是对项目必须产生的一系列文档进行组织的一种结构。”
5 “项目所有的文档都必须是该(工作手册)结构的一部分。”
6 需要尽早和仔细地设计工作手册结构。
7 事先制订了良好结构的工作手册“可以将后来书写的文字放置在合适的章节中”,并且可以提高产品手册的质量。
8 “每一个团队成员应该了解所有的材料(工作手册)。”[ 我想说的是,每个团队成员应该能够看到所有材料,网页即可满足要求。]
9 实时更新是至关重要的。
组织架构
16 团队组织的目标是为了减少必要的交流和协作量。
17 为了减少交流,组织结构包括了人力划分(di vi si on of lab or )和限定职责范围(specialization of function)。
18 传统的树状组织结构反映了权力的结构原理——不允许双重领导。
19 组织中的交流是网状,而不是树状结构,因而所有的特殊组织机制(往往体现成组织结构图中的虚线部分)都是为了进行调整,以克服树状组织结构中交流缺乏的困难。
20 每个子项目具有两个领导角色——产品负责人、技术主管或结构师。这两个角色的职能有着很大的区别,需要不同的技能。
21 两种角色中的任意组合可以是非常有效的:
? 产品负责人和技术主管是同一个人。
? 产品负责人作为总指挥,技术主管充当其左右手。
? 技术主管作为总指挥,产品负责人充当其左右手。
七 胸有成竹
1 仅仅通过对编码部分的估计,然后乘以任务其他部分的相对系数,是无法得出对整项工作的精确估计的。
2 构建独立小型程序的数据不适用于编程系统项目
3 在基本语句级别,生产率看上去是个常数。
4 当使用适当的高级语言时,程序编制的生产率可以提高5 倍。
八 削足适履
1 软件开发人员必须设立规模目标,控制规模,发明一些减少规模的方法——就如同硬件开发人员为减少元器件所做的一样。
2 规模预算必须与分配的功能相关联;在指明模块大小的同时,确切定义模块的功能。
3 在大型的团队中,各个小组倾向于不断地局部优化,以满足自己的目标,而较少考虑队用户的整体影响。这种方向性的问题是大型项目的主要危险。
4 在整个实现的过程期间,系统结构师必须保持持续的警觉,确保连贯的系统完整性。
5 培养开发人员从系统整体出发、面向用户的态度是软件编程管理人员最重要的职能。
九 提纲挈领
少数文档形成了关键的枢纽
计算机产品的文档:
目标
技术说明
进度,时间表
工作空间的分配
预算
组织结构图
为什么要有正式的文档?
首先,书面记录决策是必要的,只有记录下来,分歧才会明朗,矛盾才会突出。
第二,文档能够作为同其他人沟通的渠道。
第三,项目经理的文档可以作为数据基础和检查列表。通过周期性的回顾,他能清楚项目所处的状态,以及哪些需要重点进行更改和调整。
项目经理的基本职责是使每个人都向着相同的方向前进。
项目经理的主要日常工作是沟通,而不是做出决定;文档使各项计划和决策在整个团队范围内得到交流。
十 未雨绸缪
普通的做法是,选择一种方法,试试看,如果失败了,没关系,再试试别的,不管怎么样,重要的是先尝试。
唯一不变的就是变化本身。
为变更计划系统。
为变更计划组织架构。
“开发人员交付的是用户满意程度,而不仅仅是实际的产品。”(Cosgrove)
1 用户的实际需要和用户感觉会随着程序的构建、测试和使用而变化。
2 软件产品易于掌握的特性和不可见性,导致了它的构建人员(特别容易)面临着永恒的需求变更。
3 目标上(和开发策略上)的一些正常变化无可避免,事先为它们做准备总比假设它们不会出现要好得多。
4 缺陷修复总会以(20-50)% 的机率引入新的bug 。
5 在每次修复之后,必须重新运行先前所有的测试用例,从而确保系统不会以更隐蔽的方式被破坏。
十一 干将莫邪
选择好的工具,工具库并合理有效分配公用资源。
十二 整体部分
自顶向下设计:先出主框架,再各个部分填充
1 在编写任何代码之前,规格说明必须提交给测试小组,以详细地检查说明的完整性和明确性。开发人员自己不会完成这项工作。
2 有时必须回退,推翻顶层设计,重新开始。
3 必须有人对变更进行控制和文档化,团队成员应使用开发库的各种受控拷贝来工作。
十三 祸起萧墙
里程碑还是沉重的负担?
如何根据一个严格的进度表来控制项目?第一个步骤是制订进度表。进度表上的每件事,被称为“里程碑”,它们都有一个日期,选择日期是一个估计技术上的问题。
它在很大程度上依赖以往的经验。
里程碑选择只有一个原则:那就是,里程碑必须是具体的,特定的,可度量的事件,能够进行清晰定义。
对计划和控制职能进行适度的技术人力投资是非常值得赞赏的,它能明白地指出不易察觉的延迟。并强调关键因素。他们是早期的预警系统。防止项目以一次一天的方式延迟一年。
1 慢性进度偏离是士气杀手。[Microsoft 的Jim Mc Ca rthy 说:“如果你错过了一个最终期限(deadline),确保制订下一条deadline。
2 进取对于杰出的软件开发团队,同优秀的棒球队伍一样,是不可缺少的必要品德。
3 状态的获取是困难的,因为下属经理有充分的理由不提供信息共享。
4 老板的不良反应肯定会对信息的完全公开造成压制;相反,仔细区分状态报告、毫无惊慌地接收报告、决不越俎代庖,将能鼓励诚实的汇报。
5 必须有评审的机制,从而所有成员可以通过它了解真正的状态。出于这个目的,里程碑的计划和完成文档是关键。
十四 另外一面
1 对于软件编程产品来说,程序向用户所呈现的面貌与提供给机器识别的内容同样重要。
2 即使对于完全开发给自己使用的程序,描述性文字也是必须的,因为它们会被用户-作者所遗忘。
3 培训和管理人员基本上没有能向编程人员成功地灌输对待文档的积极态度—
4 文档能在整个生命周期对克服懒惰和进度的压力起促进激励作用。 这样的失败并不都是因为缺乏热情或者说服力,而是没能正确地展示如何有效和经济地编制文档。
5 大多数文档只提供了很少的总结性内容。必须放慢脚步,稳妥地进行。
6 由于关键的用户文档包含了跟软件相关的基本决策,所以它的绝大部分需要在程序编制之前书写,它包括了9 项内容(参见相应章节)。
7 每一份发布的程序拷贝应该包括一些测试用例,其中一部分用于校验输入数据,一部分用于边界输入数据,另一部分用于无效的输入数据。
8 对于必须修改程序的人而言,他们所需要程序内部结构文档,同样要求一份清晰明了的概述,它包括了5 项内容(参见相应章节)。
9 流程图是被吹捧得最过分的一种程序文档。详细逐一记录的流程图是一件令人生厌的事情,而且高级语言的出现使它显得陈旧过时。(流程图是图形化的高级语言。)
10 如果这样,很少有程序需要一页纸以上的流程图。[ 在这一点上,MILSP EC 军用标准实在错得很厉害。]
11 即使的确需要一张程序结构图,也并不需要遵照ANSI的流程图标准。
12 为了使文档易于维护,将它们合并至源程序是至关重要的,而不是作为独立文档进行保存。
13 最小化文档负担的3 个关键思路:
? 借助那些必须存在的语句,如名称和声明等,来附加尽可能多的“文档”信息。
? 使用空格和格式来表现从属和嵌套关系,提高程序的可读性。
? 以段落注释,特别是模块标题的形式,向程序中插入必要的记叙性文字。
14 程序修改人员所使用的文档中,除了描述事情如何以外,还应阐述它为什么那样。对于加深理解,目的是非常关键的,但即使是高级语言的语法,也不能表达目的。
15 在线系统的高级语言(应该使用的工具)中,自文档化技术发现了它的绝佳应用和强大功能。
十五 没有银弹-软件工程中的根本和次要问题
所有软件活动包括根本任务--打造由抽象软件实体构成的复杂概念结构。
次要任务:使用编程语言表达这些抽象实体。在空间和时间限制内将它们映射成机器语言。
因此,现在是关注软件任务中的必要活动的时候了,也就是那些和构造异常的抽象概念结构有关的部分。我建议:
1 仔细地进行市场调研,避免开发已上市的产品。
2 在获取和制订软件需求时,将快速原型开发为作迭代计划的一部分。
3 有机地更新软件,随着系统的运行、使用和测试,逐渐添加越来越多的功能。
4 不断挑选和培养杰出的概念设计人员。
现代软件系统的内在特性,复杂度、一致性、可变性和不可见性。
十六 再论没有银弹
对于解决软件工程中主要问题的方法,工具从一定程度上提高了生产率,但都没有从根本性上改变这个问题的本质。
十六 人月神话的观点:是或非?
核心观点:概念完整性和结构师
概念完整性。一个整洁、优雅的编程产品必须向它的每个用户提供一个条理分明的概念模型,这个模型描述了应用、实现应用的方法以及用来指明操作和各种参数的用户界面使
用策略,。用户所感受到的产品概念完整性是易用性中最重要的因素。
结构师。我一直不断地在表达一个观点——委派一名产品结构师是最重要的行动。结构师负责产品所有方面的概念完整性,这些是用户能实际感受到的。结构师开发用于向用户
解释使用的产品概念模型,概念模型包括所有功能的详细说明以及调用和控制的方法。结构师是这些模型的所有者,同时也是用户的代理。在不可避免地对功能、性能、规模、
成本和进度进行平衡时,卓有成效地体现用户的利益。这个角色是全职工作,只有在最小的团队中,才能和团队经理的角色合并。结构师就像电影的导演,而经理类似于制片人。
将体系结构和设计实现、物理实现相分离。为了使结构师的关键任务更加可行,有必要将用户所感知的产品定义——体系结构,与它的实现相分离。体系结构和实现的划分在各
个设计任务中形成了清晰的边界,边界两边都有大量的工作。
体系结构的递归。对于大型系统,即使所有实现方面的内容都被分离出去,一个人也无法完成所有的体系结构工作。所以,有必要由一位主结构师把系统分解成子系统,系统边
界应该划分在使子系统间接口最小化和最容易严格定义的地方。每个部分拥有自己的结构师,他必须就体系结构向主结构师汇报。显然,这个过程可以根据需要重复递归地进行。
概念完整性是产品质量的核心。拥有一位结构师是迈向概念完整性的最重要一步。这个原理决不仅限于软件系统,它适用于所有的复杂事物