《人月神话》摘要
一直相信存在某种方法论,能够让软件开发工作的进度能够得到很好的控制,并很大程度的提高生产率。读完本书后,我意识到,能够解决软件开发问题的不是某种方法论,而是一系列的方法、技术、和工具。也发现自己之前太局限于从“开发”角度去思考问题,以后还需多看书,多学习才是。
以上都是废话,对自己无知的惭愧。后面的内容将是书中各个章节的摘要,并可能还会有一些废话。对于废话,不必太过在意,但是也不介意吐槽~
个人建议:想读本书的朋友,到网上搜“没有银弹”读读即可。因为由于写作的年代与当今相距甚远,其中的多数方法和建议已很难应用,但是“没有银弹”绝对是亮点章节。
第一章、焦油坑
- 编程系统产品(Program System Product,我理解为软件)
演化进程:程序->编程系统(接口、系统集成)->编程系统产品;程序->编程产品(通用化、测试、文档、维护)->编程系统产品。这两条线都节约了成本。
2. 编程的乐趣
- 创建新事物;
- 开发的产物能够对别人有用;
- 编程的过程:各个组件按照相互协作完成预定功能;
- 不是重复的工作,需要持续的学习新的知识
- 工作再易于驾驭的介质上:自由的运用自己的想象,创建自己的城堡。
3. 编程的苦恼
- 追求完美:计算机要求精确的输入输出、完整的概念/逻辑,这比现实生活要严格许多;
- 目标、信息、资源都是由别人提供:即很多东西需要依赖别人(注:这就是为何沟通显得尤为重要);
- 重复琐碎的劳动:如处理琐碎的Bug;
- 调试和查错是线性收敛的,甚至是二次方的复杂度:越往后Bug越难以发现(后悔没好好学数学,只能这样理解了*_*);
- 辛勤付出得不到预想的回报:不是指工资,而是项目即将完成的时候,发现市场上已有类似的产品出现,而且好像比自己做得更好~
第二章、人月神话
项目滞后的主要原因是缺乏进度的合理安排:
- 对估算技术缺乏有效研究。乐观主义,通常假设一切都将运作良好;
- 混淆工作量和进度,以为人月可以互换;
- 对自己的估算缺乏信心,项目经理不会耐心持续的进行估算;
- 缺少进度跟踪和监督;
- 进度偏移时,第一反应是协调人力。
1. 乐观主义
乐观主义是程序员的职业病。
2. 人月
人员之间的需要沟通交流,新派人手可能成为负担;而且任务还有先后顺序。
3. 系统测试
过程时间占比经验:
计划(1/3):包含技术调研、概念设计(功能规格)
编码(1/6):最容易估计时间的部分
构件测试和早起系统测试(1/4):单元测试
系统测试(1/4):集成测试
4. 空泛的估算
在外部的压力下,项目经理在估算时容易屈服。
开发并推行生产率图表、缺陷率图表、估算规则等工具可以使得项目估计更有依据,相比经验也更能有说服力。
5. 重复产生的进度灾难
进度延迟后考虑的做法:
重新安排进度:注意在开发过程中及时重新估计和调整进度(不一定是延后,而是根据实际情况,部分任务缩减,部分任务延长),任务的粒度也需要注意,不需要太细,也不能太粗。
削减任务:讨论功能的重要性和优先级,考虑分版本发布,先完成重要、紧急的功能。
Brooks法则:想落后的项目中增加人手,只会使得进度更加落后。
第三章、外科手术队伍
软件开发队伍人员尽量少而精——
文艺程序员比普通程序员在生产率上的差异很大,甚至能达到一个数量级;
开发成本的主要组成部分是相互的沟通和交流,以及更正沟通不当所引起的不良结果;
更少的人数更容易保证概念完整性。
1. 问题
小型精干队伍的人数一般在10人以内。但是对于大型系统,比如需要1000人年,完成项目的进度显得太长~
对于大型系统,需要划分模块来完成。而且概念设计部分需要由少而精的人员完成。
2. Mills的建议(外科手术队伍)
- 外科医生(架构师):定义功能、性能技术说明书,设计程序,编写源代码,测试,写技术文档;
- 副手(开发组长):能完成任何一部分工作,但经验较少。设计的思考者、讨论者、评估人员;
- 管理员(项目经理):管理财务、人员、办公设备等,可以一个人管两个项目组;
- 编辑:组织文档;
- 两个文秘:管理员和编辑各一个(偶也想要啊)
- 程序职员:维护所有团队的技术记录
3. 如何运作
- 概念来自外科医生和副手,保证了完整性并节约了沟通成本
- 外科医生在金字塔顶端,可以统一分歧
- 其余人员分工专业化,更为高效
4. 团队的扩建
大型系统需要一个系统结构师自上而下的进行所有设计,也有利于协调。概念设计团队的人也要少而精。
第四章、贵族专制、明主政治和系统设计
1. 概念完整性
概念完整性应该是系统设计最重要的考虑因素。保证概念完整性最好的方法是由一个人来完成设计,对于后来的设计者,则要求他们牺牲一些创意,以获得纯粹的设计。
2. 获得概念完整性
系统设计的最终测试标准:易用性 = 功能 / 理解复杂度。
软件不仅要功能越多越好,而且需要简洁、直接。简洁和直白来自概念完整性。
设计的一致性是易用性的另一重要因素。设计一致性要求:每个部分必须反映相同的原理需求的一致平衡(语法上使用的技巧相同,语义上也要具有相似性)。
3. 贵族专制和民主政治
概念的完整性要求设计必须由一个人,或者少数互有默契的人员来实现。但进度压力要求系统要由很多人来开发。解决这一矛盾的方法有两个:仔细对设计方法/体系结构与具体实现进行分工;第三章所述的团队的组建方式。
系统的体系结构(achitecture)指的是完整和详细的用户接口说明。系统的结构师(架构师)需要运用专业技术知识来支持最终用户的利益。
体系结构师(架构师)的贵族专制统治:体系结构师代表最终用户的利益;其产物的生命周期比实现人员更长;为了概念完整性,系统设计必须由少数人(架构师)控制。
具体设计实现在创造性方面并不亚于体系结构设计工作:具体实现更大程度决定了产品的成本和性能;而结构设计偏向于易用性。但是具体实现需要依赖于结构设计。
4. 在等待时,实现人员应该做什么
软件开发的三个阶段(Blaauw):体系结构(achitecture)、设计实现(implementation)、物理实现(realization)。他们彼此存在依赖,但往往可以同时开始和并发进行。
上述的划分是水平的划分,实际中再进行垂直的(功能)划分并不会在概念完整性等方面造成不利影响。上述的三个阶段确实存在一定的向上依赖,但是垂直的划分使得工作可以并行进行;另外各个阶段中都有部分工作是不存在向上依赖的。
第五章、画蛇添足
结构师的主要职责在于只能功能规格说明,他没有产品开发时间、成本方面的责任。理论上结构师的创造性可以是无限的,那么如何来约束这种热情呢?
1. 结构师的交互准则和机制
今早的交流和持续沟通:使得结构师有成本意识,也让开发人员对设计有信心,不会混淆责任分工。
产生估算过高时,结构师有两个选择:削减设计;建议实现人员使用成本更低的实现方法。
交互准则:
牢记开发人员承担实现的责任,所以只能建议,不能支配;
时刻准备为所指定的功能建议一种实现方法,同样准备接受其他任何能够达到目标的方法;
对上述的建议保持低调和不公开;
准备放弃坚持所做的改进建议;
在体系结构上的修改往往会引起开发人员的反对——实现工作展开时,一些次要特性的修改会造成意想不到的成本开销。
2. 自律——开发第二个系统所带来的后果
结构师设计的第二个系统往往是最危险的。
由于对任务不够了解而产生的谨慎,结构师的第一个系统倾向于精炼和简洁;而第二个系统往往会被过分设计(太多的修饰功能、想法);后面的项目会在之前的经验上形成对比总结,所以在简洁性和功能方面,比较容易达到平衡。避免过分设计的方法在于:自律和程序经理的监督。
第六章、贯彻执行
1. 文档化的规格说明——手册
手册需要描述和规定用户所见的每一个细节,同时需要避免描述用户不可见的部分。结构师必须为自己描述的任何特性准备一种实现方法,但不应试图支配实现过程。
手册(规格说明)的风格必须清晰、完整和准确。一致性很重要。
2. 形式化定义
形式化(术语化、公式化)定义是精确的,倾向完整;但是不易理解,需要记叙性文字的辅助。注意在同一个手册中需要在谁主谁辅上保持一致。
实现可以作为一种形式化定义方法(如)。实现作为形式化定义的优点:所有问题可以通过试验清晰的得到答案,快捷迅速、无需争辩商讨;缺点:实现作为定义时,体现了过多的内容,即不但描述了系统必须做什么,同时还声明了自己做了些什么(多余的要求)。
3. 直接整合
设计好模块间接口的原型,要求在实现过程中按照原型开发。
4. 会议和大会
周例会:每周半天,由首席结构师主持,所有结构师参加、实现人员代表和市场计划人员(代表用户)参与。参与人员都可以提出问题和修改意见,但需要提前准备并分发书面建议书。 讨论通过的建议/问题解决方案由相关结构师进行修改,并纳入变更建议说明书中。问题结论由首席架构师发布。
周例会优点:相同人员数月内每周交流一次,对项目内容都比较了解,无需额外培训;参与人员与产品密切相关,深刻理解所面对的问题,每个人都承担义务;出现问题时,在界线内部和外部同时寻求解决方案;正式的书面建议集中了注意力,强制了决策的制定和执行;明确授予首席结构师决策权力,避免妥协拖延。
年度(或半年)大会,在功能规格制定前进行。出了周例会成员,程序经理、实现人员、市场人员都会参与,由项目经理主持。集中解决遗留的各种问题,耗时两周,每天需要通知前一天的各项决定。
年度大会优点:解决了部分决策上的问题,同时使决策更容易被接受和理解。
4. 多重实现
多重实现时,根据机器修改手册的消耗可能比根据手册修改机器要高。
5. 电话日志
实现人员对规格说明容易理解不当或规格说明本身描述就不够精确,所以结构师鼓励实现人员电话沟通。在此条件下,结构师需要保存电话日志,记录每个问题和相应的解答,并每周进行合并整理,分发给用户和实现人员。
6. 产品测试
测试组的工作是根据规格说明检查程序,需要由独立的技术监督部门完成,以保证公正性。
第七章、为什么巴比伦塔会失败
巴比伦塔(圣经中的典故):开始,人们使用的是同一种语言,他们建造房屋,并想着建造一个有高塔的城市,所有人都可以聚集在高塔里。上帝听说后,认为有必要让人类经历些挫折,于是他在人类的语言中制造了混淆,相互无法听懂。这样人类就不得不停止制造巴比伦塔。
1. 巴比伦塔的管理教训
人类有清晰的目标、人力充足、材料齐全、时间充裕、技术完备。但失败的原因在于:缺乏交流以及交流的结果(组织)。
2. 大型编程项目中的交流
团队之间的交流沟通需要利用所有可能的途径:
非正式途径:电话、口头、即时通讯、邮件等;
会议:各团队逐一进行简要的技术陈述。很容易澄清细小的误解;
工作手册:在项目开始阶段即应该准备
3. 项目工作手册。
定义:对项目必须产出的一系列文档进行组织的一种结构,而非独立的一篇文档。即定义各类文档存放在什么位置。
备忘录的管理:编号、整理,便于检索。
当编程人员仅了解自己负责的部分,而非整个系统的开发细节时,工作效率最高。此方法的先决条件在于精确完整的定义所有接口。
4. 大型变成项目的组织架构
团队组织的目的:减少所需的交流和合作的数量。
减少交流的方法:人力划分和限定职责范围。
树状组织架构是作为权力和责任的结构出现,不适合交流和沟通(网状)。
树状编程队伍中,每颗子树必备的基本要素:任务(mission);产品负责人(producer);技术主管或结构师(techenical director or architecture);进度(schedule);人力划分(division of labor);各部分间的接口定义(interface definitions among the parts)。
产品负责人:组建团队、划分工作、制定进度表。争取和保证必要的资源(外部向上或水平沟通);建立内部沟通/报告方式;确保进度目标的实现,根据环境变化调整资源和团队架构。
技术主管:对设计进行构思,识别系统的字部分,设计内部结构和外部功能;提供整个设计的一致性和概念完整性;控制系统的复杂程度。提供复杂问题的解决方案,或根据需要调整系统设计。
建议技术主管为主,产品负责人为辅的组织架构;产品负责人为主时需要预先声明技术主管在技术决策方面的权威(亦可通过办公条件等方面暗示)。
第八章、胸有成竹
系统编程的时间估计,工作量估计方法:比率估算法(不能仅用编码阶段估计);小型程序数据不适合编程系统产品。
1. Portman的数据
编程进度大约落后计划的1/2,每项工作花费的时间大约是估计的2倍。实际编程和调试的时间只有半个工作周,其他时间都在会议、文字、高优先级的琐碎工作、公司业务、病事假等。
第九章、削足适履
本章在内存资源非常昂贵时有意义,如今总结一句话:时间空间可互换、实现需要考虑性能标准,有时候从结果而非过程来考虑问题能够得到更好的解决方案。
第十章、提纲挈领
前提:在堆积如山的文档中,少数是关键枢纽,每一件项目管理工作都围绕着他们运转。这些文档是项目经理最重要的个人工具。
技术、周边组织机构、行业传统等因素定义了项目必须准备的一些文书工作。这些文书工作看起来令人厌烦,但是他们往往包含了一些管理方面的内容:每份文档的准备工作是集中考虑,并使各种讨论意见明朗化的主要时刻;文档有利于明确工作阶段;文档的跟踪维护是项目监督和预警机制;文档本身可以作为检查列表、状态控制,也可以作为汇报的数据基础。
任何管理任务的关注焦点都是:时间、地点、人员、项目内容、资金。
1. 软件项目文档
内容:目标。定义待完成的目标、迫切需要的资源、约束和优先级;
内容:产品技术说明。以建议书开始,用户手册和内部文档结束。性能说明是关键部分;
时间:进度;
资金:预算;
地点:工作空间分配;
人员:组织图。人员与接口说明相互依存。组织结构需要根据系统设计自由变化。
2. 为什么要有正式的文档
书面记录决策是必要的。记录
文档可以作为同其他人沟通的渠道。项目经理的基本职责是使每个人都想着相同的方向前进,其主要工作是沟通,非决定。
文档可以作为数据基础和检查列表。通过文档能够搞清项目所处状态,需要做的更改和调整。
文档非常重要,但是不存在“完全信息管理系统”。因为管理人员80%的时间都用在沟通上:倾听、报告、讲授、规劝、讨论和鼓励。
项目经理的任务是制定并实现计划,只有书面计划是精确和可沟通的。
第十一章、未雨绸缪
1. 试验性工厂和增大规模
必须为舍弃而计划。第一个版本必然会存在很多问题,所以做好把其当做一个试验品的准备。要注意试验品是否应当发布给用户。
2. 唯一不变的是变化本身
接受变化,但并非客户所有的需求变更都应该整合到设计中。
3. 为变更计划系统
技术手段:设计细致的模块化、可扩展的函数、精确完整的模块间接口设计和完备的文档。
变更的阶段化:版本号、日程表、冻结日期、变更内容。
4. 为变更计划组织架构
选择高效的技术人员,解决各种技术问题;对技术人员进行培训;废除职位头衔,让成员能够接受职务变更。
5. 前进两步,后退一步
缺陷修复总会以20%-50%的概率引入新的Bug;
回归测试的成本很高;
选择程序设计方法时,需要考虑其副作用,并指明。
6. 前进一步,后退一步
在系统维护过程中,更多关注的是功能实现,系统原有设计日益被忽略,每次的修改都可能导致潜在的新问题,修改成本日益增加。必要时,需要考虑代码重构或重新设计。
第十二章、干将莫邪(利器)
工具要通用化,个性化的工具妨碍沟通。建议每个团队一个工具管理人员,工具小组方式则相对效率更低。
考虑使用高级语言、成熟框架,性能测试工具,调试工具,测试用例生成工具等。
第十三章、整体与部分
1. 剔除Bug的设计
系统各个部分的开发者都会做出假设,这些假设的不匹配会导致致命或难以察觉的Bug。细致的功能定义、仔细的规格说明、规范化的功能描述说明很有必要。
测试规格说明:完整性和明确性
自上而下的设计,横向划分为:体系结构设计、设计实现、物理实现;纵向以模块划分,且模块从大到小不断细化。优点:
清晰的结构和表达方式更容易对需求和模块功能进行精确的描述;
模块分割和模块独立性避免了系统级Bug;
细节的抑制使得结构上的缺陷容易暴露出来;
设计在每个精化步骤上都是可测试的。
遇到极端问题时,可能需要考虑逆转过程,直至推翻顶层设计,重新开始。
2. 单元调试
略
3. 系统集成调试
需要在各个部分都能够正常运行之后开始。这个阶段耗费的时间往往比预计的要长。
使用伪构件(dummy component,包含接口、可能的伪数据和一些小的测试用例)。
控制变更。控制构件单元版本。
一次添加一个构件。能够有利于问题定位。
阶段化变更。定期进行大范围的构件更新等,周期不宜太短。
第十四章、祸起萧墙
通常灾祸来自白衣的肆虐,而非龙卷风的侵袭。
1. 里程碑还是沉重的负担
里程碑澄清了划分的比较模糊的阶段,定义了确定时间点需要的完整的产物。里程碑的边界需要是明显的,无歧义的。里程碑需要能够正确的反应损失的时间,避免慢性进度偏离影响士气。
建议活动之前开始估计,每两周对计划进行一次仔细的修订。
2. 关键路径法(Pert图)
那些任务的滞后会影响最终的完成日期。非关键任务允许一定的落后时间。
相对对每个任务估计完成时间,关键路径法更能够鼓励超前完成,也指明了补偿其他任务滞后时间的方法。
3. 地毯的下面
程序经理发现计划偏离时,存在于老板的利益冲突:老板需要行动计划,分析的状态数据;程序经理会认为非致命性的进度偏离是可通过团队内部解决的,老板的行动可能会影响计划或个人威信。冲突(让程序经理公开信息)的解决方法:
减少角色冲突:老板避免对程序经理能够解决的问题进行干预,绝不在检查状态报告时做安排。
猛地拉开地毯:评审机制。每周小屏,每月大评。项目经理需要解释延迟原因,并指出应对方案和需要的帮助。
第十五章、另外一面
对开发人员光是介绍文档的重要性,并讲解写文档的技巧和要点,还不如做一份给他们看。
1. 需要什么样的文档
使用程序的文档内容:
目的(程序的主要功能是什么,解决了什么问题);
环境(机器、硬件配置、操作系统等);
输入范围,输出范围;
实现功能和使用的算法;
输入-输出格式(必须是确切完整的);
操作指令;
功能选项;
运行时间;
精度和校验;
精度及如何校验精度。
验证程序的文档内容:
测试用例。给程序使用者提供信心。
修改程序文档内容:
流程图或子系统的结构图;
对所用算法的完整描述;
对所有文件规划的解释;
数据流处理的概要描述,以及每个处理过程中晚餐的操作;
初始设计中,对已遇见修改的讨论;特性、功能回调以及出口的位置;原作者对可能会修改的地方及可能处理方案的一些意见。
2. 流程图
从代码生成流程图非良好实践。
3. 自文档化的程序
维护文档和代码的一致性是费力不讨好的事情。建议将注释以文字记录到代码头部,注意格式。维护记录也可记录其中。
第十六章、没有银弹——软件工程中的根本和次要问题
本章节是精华,建议精读,这里简要列举
在未来十年内,无论是在技术还是管理方法上,都看不出有任何突破性的进步,能够独自保证在十年内大幅度地提高软件的生产率、可靠性和间接性。
软件活动包括:
根本任务,打造构成抽象软件实体的复杂概念结构
次要人物,使用编程语言表达这些抽象实体,在空间和时间限制内将它们映射成机器语言。作者出于必要任务考虑的四点建议:
仔细进行市场调研,避免开发已上市的产品;
获取和制定软件需求时,将快速原型开发作为迭代计划的一部分;
有机地更新软件,随着系统的运行、使用和测试,逐渐添加越来越多的功能;
不断挑选和培养杰出的概念设计人员。
1. 根本困难
软件开发困难的部分:规格说明、设计和测试这些概念结构,而非对概念进行表达和对实现逼真程度进行验证。
软件内在特性:复杂度、一致性、可变性和不可见性。
2. 次要问题上的突破
高级语言;
统一的编程环境。
3. 银弹的希望
高级语言;
面向对象编程;
人工智能;
专家系统;
“自动”编程;
图形化编程;
程序验证;
环境和工具。
4. 针对根本问题颇有前途的方法
购买而非自行开发
需求精炼和快速原型
增量开发——增长而非搭建系统。
卓越的设计人员
杰出设计人员的培养方法:
尽可能早的,有系统的识别顶级的设计人员;
为设计人员指派一位职业导师,负责他们技术方面的成长,仔细为他们规划职业生涯;
为每个方面制定和维护一份职业计划,包括设计大师的精挑细选的学习过程,正式的高级教育和短期的课程;
为成长中的设计人员提供相互交流和激励的机会。