焦油坑
过去几十年的大型系统开发就犹如这样一个焦油坑,很多大型和强壮的动物在其中剧烈地挣扎。
它们挣扎得越是猛烈,焦油纠缠得越紧,没有任何猛兽足够强壮或具有足够的技巧,能够挣脱束缚,它们最后都沉到了坑底。
人月神话
缺乏合理的时间进度是造成项目滞后的最主要原因:
- 对估算技术缺乏有效的研究
- 隐含地假设人和月可以互换
- 没有持续进行估算工作
- 对进度缺少跟踪和监督
- 进度偏移时,下意识的反应是增加人力。
乐观主义
系统编程的进度安排背后的第一个假设是:一切都将运作良好,每一项任务仅花费它所“应该”花费的时间。
但是进度正常的概率,在大型的编程工作中,细分到大大小小很多任务中,使得这个概率接近于无。
人月
用人月作为衡量一项工作的规模是一个危险和带有欺骗性的神话。它暗示着人员数量和时间是可以相互替换的。
- 人数和时间的互换仅仅适用于以下情况:某个任务可以分解给参与人员,并且他们之间不需要相互的交流。
- 次序上不能分解的任务,人手的添加对进度没有帮助。
- 可以分解,但子任务之间需要相互沟通和交流的任务,需要考虑沟通的工作量。
- 如果任务的每个部分必须分别和其他部分单独协作,则工作量按照 n(n-1)/2 递增。(这时就需要注意,人过多反而会拖慢进度)
系统测试
对于软件任务的进度安排:
- 1/3计划
- 1/6编码
- 1/4构件测试和早期系统测试
- 1/4系统测试,所有的构建已完成
没有足够时间进行全面细致的测试,会增加二次成本(上线使用之后维护以及用户出问题造成的损失)
空乏的估算
不应该为满足顾客期望日期而造成不合理进度安排
重复产生的进度灾难
当软件项目落后于进度时
- 是否要依据落后的进度(比如安排1个月,实际1个半月),重新评估后续进度(比如剩下3个月,是否调整为4.5个月)
- 在周期很短的开发任务中,增加人手反而比不加人耗时更长(新人需要老手去培训,导致老手没法进行开发)
Brooks法则:向进度落后的项目中增加人手,只会使进度更加落后。
外科手术队伍
问题
精英和普通程序员之间生产效率差别很大。
精英小队:效率更高,概念完整,耗时太长。
人海模式:效率低,沟通成本高
如何调和这两方面的矛盾?
Mills的建议
大型项目的每一个部分由一个团队解决,但是该队伍以类似外科手术的方式组建,而并非一拥而上。
- 外科医生。首席程序员,亲自定义功能和性能技术说明书,设计程序,编制源代码,测试以及书写技术文档。
- 副手。作为设计的思考者、讨论者和评估人员。但外科医生不受副手建议的限制。充当保险机制。
- 语言专家。大神,专治疑难杂症。可为多个外科医生服务。
如何运作
团队的扩建
- 总的系统架构师。从上至下地进行所有的设计,使系统具备概念上的完整性。
- 扩建过程的成功依赖于这样一个事实,即每个部分的概念完整性得到了彻底的提高——决定设计的人员是原来的七分之一或更少。所以,可以让 200 人去解决问题,而仅仅需要协调 20 个人,即那些“外科医生”的思路。
贵族专制、民主政治和系统设计
概念一致性
在系统设计中,概念完整性应该是最重要的考虑因素。也就是说为了反映一系列连贯的设计思路,宁可省略一些不规则的特性和改进,也不提倡独立和无法整合的系统,哪怕它们其实包含着许多很好的设计。
获得概念的完整性
由于目标是易用性,功能与理解上复杂程度的比值才是系统设计的最终测试标准。单是功能本身或者易于使用都无法成为一个好的设计评判标准
一旦以易用性作为衡量标准,单独的功能和易于使用都是不均衡的,都只达到了真正目标的一半。
用户使用是多个功能的复杂组合。
易用性实际上需要设计的一致性和概念上的完整性。
贵族专制统治和民主政治
概念的完整性要求设计必须由一个人,或者非常少数互有默契的人员来实现。
对于非常大型的项目,将设计方法、体系结构方面的工作与具体实现相分离是获得概念完整性的强有力方法。
结构师的工作,是运用专业技术知识来支持用户的真正利益,而不是维护销售人员所鼓吹的利益。
在等待时,实现人员应该做什么?
在说明快完成的时候,才雇用编程实现人员。
整个创造性活动包括了三个独立的阶段:
- 体系结构
- 设计实现 (体系结构快完成时进行???)
- 物理实现 (与设计实现并行???)
画蛇添足
结构师的交互准则和机制
- 牢记是开发人员承担创造性和发明性的实现责任,所以结构师只能建议,而不能支配
- 时刻准备着为所指定的说明建议一种实现的方法,同样准备接受其他任何能达到目标的方法
- 对上述的建议保持低调和平静
- 准备放弃坚持所作的改进建议
一般开发人员会反对体系结构上的修改建议。通常他是对的——当正在实现产品时,某些特性的修改会造成意料不到的成本开销。
自律——开发第二个系统所带来的后果
- 第二个系统是设计师们所设计的最危险的系统。
- 避免添加过多的修饰功能和想法
- 项目经理如何避免画蛇添足(second-system effect)?他必须坚持至少拥有两个系统以上开发经验结构师的决定。
贯彻执行
如何保证工作、系统概念完整性的有效执行?
文档化的规格说明—手册
- 文档是非常必要的,它描述和规定了用户所见的每一个细节,也是结构师主要的工作产物。
- 架构师须为功能准备一种实现方法,但不应该试图去支配具体的实现过程。
- 架构师可多,但文档编写人员宜少,这样能保持文字和产品之间的一致性。
会议和大会
会议室必要的,分两级:周例会和年度大会。
周例会是每周半天的会议,成员提前整理好问题和修改意见。周例会的决策会给出迅捷的结论,允许工作继续进行。
年度大会建议八年一次,用于处理周例会没能解决的问题以及各种堆积起来的问题。
多重实现
当存在多重实现时,如实地遵从手册更新机器所造成的延迟和成本的消耗,比根据机器调整手册要低。
产品测试
测试小组是使设计决策得以贯彻执行的必要手段。应与设计同时实施。
为什么巴比伦塔会失败?
巴比伦塔的管理教训
缺少交流以及交流的结果—组织
大型编程项目中的交流
团队之间的交流:非正式途径、会议、工作手册。
项目工作手册
保证文档改动的及时更新,并标注好改动位置与时间。
大型编程项目的组织架构
团队组织的目的是减少不必要交流和合作的数量。
减少交流的方法是人力划分和限定职责范围。
人员安排:
- 产品负责人和技术主管是同一个人。
小型队伍可行。要求会技术又会管理,这很难。
-
产品负责人为主,技术主管当左右手。
大型团队建议
-
技术主管为主,产品负责人当左右手。
小型团队建议
提纲挈领
计算机产品的文档
- 目标
- 技术说明
- 进度、时间表
- 预算
- 组织机构图
- 工作空间的分配
- 报价、预测、价格
为什么要有正式的文档?
- 从记录中整理分歧与矛盾
- 作为沟通渠道
- 作为数据基础和检查列表
未雨绸缪
唯一不变的就是变化本身
- 开发人员交付的是用户满意度,而不是实际的产品,用户的需求和感觉会变化;
- 事先为它们做准备总比假设它们不会出现要好得多;
为变更计划系统
为所有的需求变更指定版本和时间
前进两步,后退一步
程序维护中的一个基本问题是——缺陷修复总会以(20-50)%的机率引入新的 bug。所以整个过程是前进两步,后退一步。
前进一步,后退一步
所有修改都倾向于破坏系统的架构,增加了系统的混乱程度。用在修复原有设计上瑕疵的工作量越来越少,而早期维护活动本身的漏洞所引起修复工作越来越多。
最后,就是开发新系统
整体部分
剔除bug的设计
- 防范bug的定义
保证概念完整性。先设计,再实施,尽量减少需求改动。
-
测试规格说明???
设计完成就出测试规格说明?然后再开发?
-
自顶向下的设计
高内聚,低耦合。先设计好功能模块再开发
-
结构化编程
多实用逻辑判断if while switch等,别用go to
构件单元调试
祸起萧墙
论项目进度的延迟
里程碑还是沉重的负担?
- 如何根据一个严格的进度表来控制项目?第一个步骤是制订进度表。进度表上的每一件事,被称为“里程碑”,它们都有一个日期。
- 里程碑必须是具体的、特定的、可度量的事件,能够进行清晰定义
- 里程碑时间必须合理
其他的部分反正会落后
PERT图
确定项目的关键模块以及对其他模块进度的影响。
地毯的下面
当项目出现计划偏离,项目经理往往不会及时报告给老板,除非问题无法解决。
解决方法:
- 减少角色的冲突。老板不对项目经理能解决的问题进行干预。
- 猛地拉开地毯。老板参与进来,定期对PERT 图以及里程碑进行确认。
另外一面
如何写好一篇优秀的文档
需要什么样的文档
使用程序
- 目的。主要功能、开发原因。
- 运行环境。(系统、配置要求等)
- 范围。输入范围、返回范围。
- 实现功能和使用的算法。
- 输入-输出格式。
- 操作指令。正常和异常反馈。
- 选项。
- 运行时间。
- 精度和校验。
验证程序
测试用例
修改程序
- 流程图、结构图
- 开发者预留的可扩充的地方
流程图
流程图被鼓吹的过于重要(不是很理解???)
没有银弹-软件工程中的根本和次要问题
是否一定那么困难呢?— 根本困难
- 复杂度
复杂度导致团队成员之间的沟通困难,导致产品瑕疵、成本超支和进度延迟
-
一致性
保持与其他接口的一致以及兼容
-
可变性
产品的迭代和变更比其他行业更频繁
-
不可见性
很难用图形来展示详细的架构
以往解决次要困难的一些突破
- 高级语言
-
分时
硬件层面的提升带来的开发速度提升
-
统一编程环境
统一ide和系统
针对概念上根本问题的颇具前途的方法
- 购买更好的工具,而非自己造轮子
- 更精炼的需求和快速原型
-
增量开发——增长,而非搭建系统
应该使用增量开发,指的是系统应该能够运行,即使还没完成所有的功能。然后系统一点一点被充实,子系统再开发
-
卓越的设计人员
尽可能早地识别优秀的设计人员
为设计人员指派一位职业导师,负责他们的技术成长
为各方面制定和维护一份职业计划
为成长中的设计人员提供互相交流和激励的机会
再论《没有银弹》
存在着银弹-就在这里!
如果开发的次要部分少于整个工作的 9/10,那么即使不占用任何时间(除非出现奇迹),也不会给生产率带来数量级的提高。因此,必须着手解决开发的根本问题。
解决根本困难的办法:
- 层次化,通过分层的模块或者对象
- 增量化,从而系统可以持续地运行
人月神话的观点
第1章 焦油坑
- 人们通常期望项目在接近结束时,(bug、工作时间)能收敛的快一些,然而软件项目的情况却是越接近完成,收敛得越慢
- 产品在即将完成时总面临着陈旧过时的威胁
第2章 人月神话
- 关于进度安排,我的经验是为 1/3 计划、1/6 编码、1/4 构件测试以及 1/4 系统测
试 - Brook 法则:向进度落后的项目中增加人手,只会使进度更加落后
- 向软件项目中增派人手从三个方面增加了项目必要的总体工作量:任务重新分
配本身和所造成的工作中断;培训新人员;额外的相互沟通
第4章 贵族专制、民主政治和系统设计
- 对于非常大型的项目,将设计方法、体系结构方面的工作与具体实现相分离是获
得概念完整性的强有力方法。”[同样适用于小型项目。]
第7章 为什么巴比伦塔会失败?
论工作手册的重要性
工作手册应随版本迭代,实时更新。
每个人不需要看完全部文档,但需要了解自己相关的那块
第10章 提纲挈领
- 计算机硬件开发项目,关键文档是目标、手册、进度、预算、组织机构图、
空间分配、以及机器本身的报价、预测和价格 - 软件项目,关键文档:目标、用户手册、内部文档、进度、预算、组
织机构图和工作空间分配。
第11章 未雨绸缪
- 为变更组建团队比为变更进行设计更加困难
- 产品生命期中每月 bug 数的有趣曲线,它先是下降,然后攀升
- 缺陷修复总会以(20-50)%的机率引入新的 bug
第14章 祸起萧墙
论计划与里程碑的重要性