前言
在分享这本书籍主要讲解的什么内容之前,我想先来简单介绍一下作者,为了让大家更直观的了解这本书有多牛。
Freder ick P.Brooks,曾荣获美国计算机领域最具声望的图灵奖(A.M.TURINGAWARD)桂冠。美国计算机协会(ACM)称赞他“对计算机体系结构、操作系统和软件工程作出了里程碑式的贡献”。
图灵奖什么呢?
图灵奖(Turing Award),全称A.M.图灵奖(ACM A.M Turing Award),是由美国计算机协会(ACM)于1966年设立的计算机奖项,名称取自艾伦·麦席森·图灵(Alan M. Turing),旨在奖励对计算机事业作出重要贡献的个人 。图灵奖对获奖条件要求极高,评奖程序极严,一般每年仅授予一名计算机科学家(博主百度百科查询了一下,从1966年开始到2021年,共56年,其中有16个年份,获奖的科学家不是一名而是多名,为啥科普这个呢,主要是博主无聊🙈)。图灵奖是计算机领域的国际最高奖项,被誉为“计算机界的诺贝尔奖”。
Brooks博士是北卡罗莱纳大学KENAN-FLAGLER商学院的计算机科学教授。他被认为是“IBM 360系统之父”,曾担任360系统的项目经理,以及360系统项目设计阶段的经理。凭借在此项目中的杰出贡献,他与BobEvarls和Erich BIocll在1985年荣获了美国国家技术奖(NationalMedal of TecPlnoIogy)。Brooks博士早期曾担任IBM公司stretcPl和Harvest计算机的体系结构设计师。
Brooks博士创立了北卡罗莱纳大学的计算机科学系,并在1964-1984年期间担任系主任。他还曾任职于美国国家科技局和国防科学技术委员会。Brooks博士 的教学和研究方向是计算机体系结构、分子模型绘图和虚拟环境设计。
作者写这本书的原因?
作者Brooks,在1964年,担任操作系统OS/360的项目经理。正如现在开发大型项目一样,Brooks在接受System 360任务后,在工作中也同样遇到了许多困难,诸如人员安排(外科手术队伍
),时间排期(人月很难同等替换
),沟通交流的成本(为什么巴比伦塔会失败
),产品概念性的完整性,没有银弹
,任务延期,导致项目最终成为焦油坑
(陷阱)。作者将这些问题分不同的章节,以文集的形式体现出来,时至今日,这些实践、思考及结论大多都被成功的证实了它的正确性,比如:
- 高级语言的出现可以提高生产率;
- 应该一块块的丢弃和重新设计系统,而不是一次性的完成替换(重构发生在每一次代码提交);
但是也有一些观点,作者也明确承认自己错了,比如:
- 关于信息隐藏,David Parnas是正确的,我是错误的。
代码模块应该采用定义良好的接口来封装,这些模块的内部结构应该是程序员的私有财产,外部是不可见的。也就是我们常说的开闭原则。作者认同,信息隐藏——常内建于面向对象的编程中——是唯一提高软件设计水平的途径。在面对变更时更健硕,更加适合作为变更设计水平的途径。
这本书发版于1975年,经过时间的洗礼沉淀,足以证明此书价值。一本好书对于作者而言,就如同年金一样,年复一年的分红,我相信《人月神话》做到了,毕竟,这是一本每年稳定卖出1w+的精华文集。
其实我觉得这本书,很多理论实践在现在工作中,已经非常常见,那为什么我还要去读呢,我觉得作者里面的很多思想很前卫,最开始知道这本书,也是闲暇无聊的时候搜集计算机书籍推荐,发现了这本书。整体读完这本书,我回过头来反思,作者提倡的这些建议,不就是我们一直在工作中追求的高效、如何编写优雅的代码,如何使团队的信息一致透明化(作者反复提到的文档、沟通、工具、自动化等)。这本书发版于40多年前,也就是,40多年前就存在难题,经过了40年,才慢慢有所改善,这和计算机硬件设备比起来,计算机软件发展的确慢,而且还年轻,这就导致我们不停的在重复试错。
一、焦油坑
作者首先用了一个形象的比如,将大型系统开发比作 焦油坑,很多大型和强壮的动物都在其中剧烈的挣扎,挣扎的越猛烈,焦油纠缠的就越紧,最后没有哪个猛兽足够强壮或者有足够的技巧能够摆脱束缚,最终它们都沉入坑底。
程序员在开发大型项目的时候,也是每天都在和各种困难以及陷阱斗争抵抗。表面上看起来好像任何一个单独的问题都会被解决,不会导致困难,但是当所有都相互纠缠累积在一起的时候,团队的行动就会变得缓慢,而且会越来越慢,最后项目就会变成焦油坑(烫手山芋),身处其中跳不出来,不在其中不想接手。
项目并不是一开始就是焦油坑,是哪些因素导致项目最终变成焦油坑呢?
-
项目的持续时间
项目的持续时间越长,项目就越容易成为“焦油坑”。 -
项目的背景
项目的背景越神秘,越复杂,越难以理解,这个项目就越容易成为“焦油坑”。 -
项目的资源
主要指的是人员构成。如果项目的资源出现问题,这项目肯定会成为“焦油坑”。
做项目最普遍最常见的就是,识别出了风险,看到一个大坑在眼前,我们还不得不跳下去,然后再看着“焦油”从天而降,这是很可悲也是很无奈的一件事情。有时候能做的,只能是自我安慰而已:“看看,我早就说这里有个坑了吧!”我想,还是要努力提高自身水平,在被逼迫跳坑的时候,有底气选择不跳。
程序编程人员的工作是一个极具挑战和创造性的工作,即使项目像焦油坑一样,但当我置身于创造性的工作时,充实的编码工作会使我忘记时间,忘却苦恼。
二、人月神话
人月神话 这一章节重点讲述了人、时间、项目进度之间三者之间复杂的关系。有的时候,项目进度滞后,PM盲目的增添人手,可能会使项目滞后更加严重,为什么会这么说呢?
下面有一个很恰当的比喻。
美食的烹调需要时间;片刻等待,更多美味,更多享受。——新奥尔良市安托万餐厅的菜单
这句话很形象的描述了软件开发和美食制作的相似之处,那就是都需要合理的时间安排。我想这一章就是Brooks想要表达的精华所在,《人月神话》的核心为 人月,那么在了解人月之前,我们先来聊一聊程序员的·优点·——积极乐观的心态。
1、程序员大部分都是乐观的

计算机还很年轻,程序员更加年轻(场外话:很多35岁的都被市场优化掉了,公司美其言为老白兔——公司价值观好,但是绩效产出差,没有功劳有苦劳),而年轻人满怀激情,总是乐观主义者,“我刚刚找到bug的原因,这次一定行”、“一切都会正常,良好的运行”。技术人员或多或少有属于自己独有的自信及荣誉感,对这种弥漫在编程人员中的乐观主义,越是要慎重的分析。
博主曾就职于一家saas运营相关电商公司(杭州的一家公司:wr),其中一个项目是营销相关的。2021年,电商行业大面积裁员,我们公司当然首当其中,成为了裁员大军的一个,大批量裁员,很多核心业务的人都选择主动被裁,拿到赔偿离开公司,虽然自己眼馋了一下,不过自己最终还是选择留下来(不要以为我是对公司有多忠诚,纯粹是因为面试还没有准备好,没有勇气离职)。因为公司大面积裁员,最后留下来的人接手的项目多了起来,刚好营销相关的项目就被分到了我的手里,哎~说白了就是没人愿意维护的小的业务。

而当时自己就因为绝对的自信,想着营销相关的业务,自己自从进入公司就一直在做相关项目,那我就来吧。很不凑巧,刚接手没多久,运营同学就反馈有一个功能有问题,当时的功能是 幸运大转盘 ,这个功能其实就是根据会员等级以及签到天数,在不同时间周期可以重复 抽取奖品,商家最终发奖品,很普遍的一个功能,当时反馈的问题就是:时间周期判断有问题,自己很快就定位到了问题,进行发版修复,但就是因为过于自信,提交代码的时候,居然手误写错了单位,原本单位分 日、周、月,原本代码只是天数都差了一个1,比如配置了7天,实际生效是6天,如果是周的话,转换为天数再换算,月与周同理,所以就导致最后天数都有差距,至于为什么这么设计,因为人员离职,已经无法追踪原因了,原本的产品没了,原本的测试没了,原本的开发没了。

而运营反馈这个问题,是希望天数归整为自然周自然月,说商家希望改成这样的实现方式,甲方爸爸提的需求,而且还和TL反馈过,那就改呗。自己非常自信,三下五除二就修改完毕,由于过于自信,只测试了自然日,其他周和月甚至自测都没有,直接就提测了,然后打脸的就来了。自己过于自信,都改成了自然日的代码,其他的代码,忘记修改单位为周、月,大家想必一定经历过CV大法带来的便捷吧,但一定要记得cv后修改到符合自己业务的逻辑哈,别像博主那么自信乐观,幸亏只是提测,不是自测保证上线,这要是…

原本只是修复一个bug却引入了另外一个新bug;原本只是一个简单的数学运算错误,一个上午或一个下午,更甚至一整天就被debug消耗掉了这些类似的场景发生,背后有一个错误的假设。
“ 一切都将运作良好,每一项任务仅花费它所 应该 花费的时间 ”,一旦任意一个任务出了意外,就会很自然导致后面的任务被延期。
这就引入了另外的一个概念—— 人月,也是最为重要的一个部分。
二、 人月
人月也就是人员和时间之间的关系。理想的情况,任务无交集,无互相依赖,无需交流沟通,可拆分为独立的小任务,那么
1人3天
和3人1天
是可以实现互换的。但现实情况呢,很多项目,尤其是大型项目中,任务是互相依赖纠缠在一起的,那么1人3天可以完成的工作量,不代表3人1天就可以完成,可能3人2天,如果项目复杂,可能3人3天+都会发生,因为这里面涉及到了后面作者说的产品概念的完成性。每个开发人员的理解不同,后加入的人员还需要培训,追赶项目进度,原本在项目中的人就必然需要额外分配出来一部分时间为新加入的同学答疑解惑,那么为了能够达成一致的产品概念,就无疑增加了解决误会的成本,也就是沟通成本随着人数的增加也随之提高。
所以有的时候,项目延期,盲目的增添人手,不一定是个明智的决定。软件开发本质上是一项系统工作——错综复杂的关系下的一种实践,沟通、交流的工作量非常大,它很快就会消耗掉任务分解所节省下来的个人时间。有的时候,添加人手,实际上延长了而不是缩短了时间进度。
1、沟通的成本如何解?
- 业务、技术培训;
- 相互交流;
无论哪一种都势必会带来时间的延长问题,而且随着人力的增加,还可能会产生重复的进度灾难,也就是难免会有些方法被或相同或类似的重复实现。
2、如何衡量应该投入多少人力进来呢?
去除人月神话的的神话色彩,只考虑人月问题,这里需要关注两点:
- 项目的时间 依赖于顺序上的限制;
- 人员的最大数量 依赖于独立子任务数量;
3、如何衡量应该投入多少人力进来呢?
应避免以下几点:
- 对估算技术缺乏有效地研究;
- 进度与工作量相互混淆;
- 对自己估算缺乏信心;
- 对进度缺少跟踪和监督;
三、外科手术队伍
如何在有意义的进度安排内创建大型的系统?
一个开发队伍越小,沟通和交流就会较少,风险控制就会成本更低,那是不是,我们创建一个小型精干的队伍是不是就可以实现合理安排呢?是滴,的确会,但这毕竟是理想情况,在实际大型项目的进度安排中,往往我们都面临的倒排期的问题,这就意味着:抢占市场,超越竞品,是我们的BOSS更加在乎的问题。而这种小型精干的队伍,对于大型系统来说,它实在是太慢了。
作者给出了一个例子🌰:在OS/360项目顶峰的时候,有超出1000人在为它工作——程序员、文档编制人员、秘书、管理人员、支持小组等,从1963 ~ 1966年,编码和文档工作花费了5000人/年,假设人月可以同等置换,那就意味着 如果是小型精干队伍,假设200人,就至少需要 5000➗200=25年,才会达到1966年产品所达到的水平。这个时间仔细一想真的太夸张了。
那么如何调和这两者的矛盾呢?
- 对于开发效率和产品概念的完整性来说,少数干练的人员设计开发最好(沟通成本低,误会少,歧义少);
- 对于大型系统,我们需要大量的人手,才能满足产能在时间上的要求;
外科手术的队伍 —— 构建10人程序开发队伍的沟通模式
由外科医生主导,不同的人负责不同的职能,将手术快速有效地运转下去。
外科医生
的角色定义:
- 系统架构师 —— CTO;
- 从上至下地进行所有设计;
- 使工作易于管理;
- 清晰划分体系结构设计和实现之间的界限;
- 必须一丝不苟的专注于体系结构;
四、贵族专制、民主政治和系统设计
建筑大师要首尾融会贯通其前辈建筑师的成果,同时也要完全掌握他们那个时代的建筑技术,并在运用这些技术时做到恰如其分。
建筑大师的工作仿佛和程序编程人员相似,都需要有一定的专业技能知识储备,所以我们才不会不断在学习新的语言的同时,深挖技能,学习底层技术,理解前人的设计思想。建筑大师和编程人员还有一点很相似,那就是都喜欢在自己的设计产品里面增加属于自己的特色设计(编码风格)。那么如何保证在同一个项目中,任务拆分到不同的开发人员手中, 概念完整性(代码设计思路) 一致呢?
获得概念的完整性
目标是 易用性 ,使用一个程序,只有当这些功能说明节省下来的时间,比花费在学习、记忆和搜索手册上的实践要多时,易用性才会提高,这个思考方法同样适用于我们在系统搭建之初,对技术选型的参考。
简洁 和 直白 来自概念的完整性。
概念的完整性:要求设计必须由一个/非常少数,互有默契的人员来实现。
在大型项目中,迫于进度压力,往往需要大量的人员一起来开发系统,那么就需要我们在以下两点下花费更多的关注:
-
仔细对设计方法和具体实现进行分工;
也就是模块划分要合理,尽量做到解耦,降低服务之间的互相依赖。 -
组建类似外科医生的崭新的编程开发团队;
有效快速的沟通。
贵族专制统治和民主政治 —— 结构师 和 开发人员 的比率
这个比喻就好似 。
这里再次明确 结构师 的职责:
是用户的代言人,结构师的工作,是运用专业技术知识来支持用户的真正利益,而不是维护销售人员、制作者所鼓吹的利益(技术+业务的双层结合)。
产品的成本性能比 —— 依靠实现人员;
易用性 —— 依赖结构师;
结构师关注点:
系统的体系架构:完整和详细的用户接口说明。
计算机:编程手册;
编译器:语言手册;
控制程序:语言和函数调用手册;
整个系统:它是用户要完成自己全部工作所需参考的手册集合;
在等待时,实现人员应该做什么?
再聊大型项目,参与的人员众多,那么是不是会有大部分人员在项目初期处于等待中呢?其实不然,很多工作工作是可以同时并发进行的。
- 体系结构设计
- 设计实现
- 物理实现
这三个阶段互相独立,是可以同时进行的,那么如何进行呢?
设计实现人员:
在外部说明的系统功能的雏形期,就可以设计模块的边界,表结构,路径,阶段分解,算法以及所有的工具。不过这里需要设计实现人员注意,要与体系结构师沟通,毕竟是雏形期,要随便变更,应变不明确或变化的需求。
物理实现:
库的调整,系统的管理以及搜索和排序算法。
五、画蛇添足
结构师的交互准则和机制
- 尽早交流、持续沟通,形成良好的成本意识。
- 与开发人员共同商讨(切忌不能支配)如何降低成本,若无法达成一致,做好准备放弃坚持所作的改进建议。
自律 —— 开发第二个系统所带来的的后果
这里需要注意,第二个系统指的并不是第二个新的系统,而是我们的软件项目上线后,后续添加新的功能,即后续的软件系统的维护升级过程。
为什么会这么说系统的二次升级是最危险的呢?前面我们也说可,程序员大部分都是乐观的,尤其经历了一次项目成功部署上线,这个时候,为了追求功能的多样性,会更容易不加取舍的往系统软件中增加很多不必要的功能,而每一次的改动,都使项目的熵不断的增加,也就是复杂度和混乱度增加。最终系统之间的差异越来越明显,越来越不受控制,最初满足功能的部分也变得越来越不够通用。
勿忘初心 —— 避免升级系统带来的危害
- 运用特别的自我约束准则。
避免功能上的过于修饰,根据系统基本理念及目的变更,舍弃一些功能。 - 保持对特殊诱惑的警觉。
确保原则上的概念和目标在详细设计中得到完整的体现,如果当时不能解决,想着后续解决,很多时候后续就没有了,破窗户 就一直留在了项目代码中,无人维护。
六、贯彻执行
这一章着重描述了文档手册记录的重要性。
文档化的规格说明 —— 手册
修改的的阶段化是很重要的(进度表上应有带日期的版本信息,参考jdk发版)。
手册不仅要描述包括所有界面在内的用户可见的一切,还要避免描述用户看不见的事物。
后者是编程实现人员的工作范畴,其设计和创造性不应该被限制。
每次修改文档,包括但不限于:需求PRD,技术方案文档,修改的时候要有变更的说明对比信息。另外涉及到编程实现的需求描述,应该不限定实现方式,这样会限制编程人员的发挥和创造。只描述需求最终呈现的效果即可,而编程实现人员应留有一定的代码扩展实现的空间,避免后续需求扩展时被束缚手脚。
文档形式化定义
如果同时具有两种方式,则必须以一种为标准,另一种作为辅助,描述,并照此明确地进行划分。一定要分清主次标准,记叙式文式 还是 形式化定义。而且所有的定义问题都要可以通过测试来验证解决。
当遇到一些尖锐的问题时,实现往往会给出计划外的答案,因为在定义的时候,这些没有被仔细考虑过。举个🌰,这是prettyEagle博主自己的理解,Java GC分代的升级,永久代的取消,元空间和本地内存的出现。详细可以看博主写的另外一篇读书笔记:Java内存区域 关于永久代的历史介绍。
多重实现
如果起初至少哟两种以上的实现,那么定义会更加整洁和规范。
多种实现,好的接口定义会使我们更加高效的接入,对于不同的功能扩展也会更加灵活自由,这就需要我们 良好的运用技能技巧,开闭原则,单一职责等。
七、为什么巴比伦塔会失败
现在整个大地都采用一种语言,只包括为数不多的单词。再一次从东方往西方迁徙的过程中,人们发现了苏美尔
地区的一处平原,并在那里定居下来。接着他们奔走相告说:“让我们制造砖块🧱,并把他们烧好🔥。”于是,
他们用砖块🧱代替石头,用沥青代替灰泥(建造房屋)。然后,他们又说:“来,让我们搭建一座带有高塔的城
市🏙,这个高塔将高达云霄🌧,也将让我们声名远望;同时,有了这个城市,我们就可以居在这里,再也不会分
散在广阔的大地上了。”于是上帝决定下来看看人们建造的城市🏙和高塔。看了以后,上帝说:“他们只是一种
种族,使用一种语言,如果他们一开始就能建造城市🏙和高塔,那么以后就没有什么能难得倒他们了。来,让我
们下去,在他们的语言里制造一些混淆,让他们相互之间不能听懂👂🏻。”这样,上帝把人们分散到世界各地,于
是他们不得不停止建造那座城市🏙。
—— 《创世纪》
为什么巴比伦塔会失败呢?这其实背后有一个隐含的教训,也可以称呼为 管理教训。
管理教训
当我们开始一项任务的时候,我们主要会关注的以下几点,也就是 目标是否明确、是否有充足的人员、资源是否足够、时间是否足够、技术是否足够的成熟,那么对应到巴比伦塔事件我们再来分析下:
- 清晰的目标 —— 建筑城市和高塔;
- 人力 —— 只有一个种族,只需要建立自己种族的即可,自供自足;
- 材料(资源) —— 砖块,石头,灰泥,沥青;
- 时间 —— 没有限制;
- 技术 —— 有足够的技术支撑;
那为什么还是会失败了❓
到底忽略了什么,导致最终失败呢?
我们回到故事里面,上帝说:“他们只是一种 种族,使用一种语言,如果他们一开始就能建造城市🏙和高塔,那么以后就没有什么能难得倒他们了。来,让我 们下去,在他们的语言里制造一些混淆,让他们相互之间不能听懂👂🏻。”
虽然只有一个种族,但是上帝却制造了很多混淆,也就是说 听不懂对方的话,那么也就无法交流,无法交流,也就无法合作,无法合作共赢,就无法形成组织。那么我们总结一下,最终巴比伦塔的失败,是因为缺少以下两点:
- 交流;
- 组织 —— 交流产生的结果;
缺少交流会导致什么呢,争辩、沮丧、群体猜疑,合作无法进行,团队开始分裂,最后大家选择孤立,而不是互相争吵。
如何交流通过呢?以项目交流为例:
项目交流方式
- 非正式途径(电话或者工位面对面);
- 会议(晨会、周会、月会…);
- 工作手册;
项目的工作手册需要包含哪些呢?
- 目的;
- 外部规格说明;
- 接口说明;
- 技术标准;
- 内部说明;
- 管理备忘录;
项目的工作手册好处:
- 保证文档结构本身规范;
后续的文字可以放在合适的章节中,现在我们可以通过网页实现。 - 控制信息发布;
所有信息都能到达需要的人手中,需要时申请权限即可。 - 对所有备忘录编号;
检索需要此信息,树状索引,检索更方便。
工作手册本身不会有变化,它是所有项目文档的集合。
唯一发生变化的是查询方式,可能重新分类,可能重新归档。
大型编程项目的组织架构,
减少交流的成本:
- 人力划分;
- 限定职责范围;
组织
- 任务;
- 产品负责人;
- 技术主管或者架构师;
- 进度;
- 人力的划分;
- 各部分之间的接口定义;
其中产品负责人的角色为:组件团队、划分工作、制定进度表、保证资源(团队内部向上 和 水平沟通)。
组织中存在两个关键的角色,产品负责人和技术主管,这两个角色如何设定呢?
三种场景
- 产品负责人和技术主管为同一人(小型项目);
- 产品负责人为总指挥,技术主管为左右手(大型项目,多跨团队跨公司的合作);
需注意,产品负责人需帮助技术主管梳理威信,技术问题出现时,先私下讨论,再会议。产品负责人应需表现对技术的尊重。 - 技术主管总指挥,产品负责人左右手(小型创业公司,此种应用最多,沟通成本低,类似外科手术队伍);
八、胸有成竹
这一章节,作者通过不同的例子论证了一点:生产率似乎是固定的,使用适当的高级语言(如Java、Go、Python),编程的生产率可以提高5倍,但这属于编程里面的次要问题,根本问题后续章节会在讨论,尤其在没有银弹
这一章节中。
九、削足适履
开发软件系统过程中,总是面临各种选择,时间❓空间(效率❓空间),如何更好的平衡。这背后有一个隐藏的成本概念,紧密的软硬件设计集成与软件系统规模,二者冲突。
规模控制
- 预留空间;
权衡 “ 规模 —— 速度 ”方案,每一个方案设计都要详细了解,并在工作推行时间分配的时候预留空间,同时在工作进展的同时,也需要我们总是往前赶一赶进度,为意外留有处理时间。 - 制定总体规模;
避免拆分过重,模块过多。应明确模块多大,并确切定义模块的功能。规模的控制,需要管理和沟通,这就需要系统架构师时刻敏感,保持持续的警觉,确保连贯的系统完整性。并不断培养开发人员从系统整体出发,面向用户的态度。
空间技能
前提:需要 一些创造性和技能。
问题1:速度(效率)不变,越多的功能,更多的空间❗️❗️
方案:功能交换尺寸。可配置的功能应用,根据功能选项,剪裁程序。
难点:程序设计人员必须决定用户可选的项目粗细程度。
问题1:内存受限,常驻空间(交换页面或暂存去过多过大),从而降低性能❗️❗️(我们面试中也会经常被问到内存泄漏的场景:造成内存泄露的本质原因只有一个,就是应当回收的对象没有正常被回收,变成了老生代中的常驻对象。)
方案:空间 —— 时间 折中,平衡。
难点:① 培训,使编程技能提升;② 技术积累,对比不同实现,选择最优方法,不断挑战。
如何突破挑战
进步不仅仅是技巧上的提高,往往是战略上的突破。
战略上突破变现为 —— 数据或表的重新表达 —— 程序的核心。这也就是诞生诸多算法的原因,战略上的突破往往就是一种新的算法。
十、提纲掣领
这一章主要描述了计算机文档如何编写,应该包含哪些内容。作者解释:文档本身可以作为检查列表(checkList),状态控制,也可以作为汇报的数据基础。
计算机产品的文档
- 目标;
定义需要、目标、资源、约束、优先级。 - 技术说明;
第一个产生,最后完成。手册和性能规格说明。 - 进度;
①预算:不仅仅是约束,还是最有用的文档之一,迫使制定技术决策,不会被忽略,促进策略决定。
②组织架构图:工作空间的分配。
③报价、预测、价格:三者互相牵制,决定项目成败。
管理任务焦点
- 时间——进度
- 地点——工作空间的分配
- 人员——组织图
- 项目内容——目标、产品技术说明
- 资金——预算
十一、未雨绸缪
开发人员交付的是用户满意程度,而不仅仅是有形的产品。用户的实际需要和用户感觉会随着程序的构建、测试和使用而变化。因此,为舍弃而计划,一定要这样做(第二个程序最危险,会不停的添加功能,从而增加软件熵值混乱度)。实际上,抛弃原型概念本身就是对事实的接受 —— 随着学习的过程更改设计。
那么如何让自己设计的软件合用,轻量化,达到用户满意的程度呢?
作者给出以下几个建议:
一、为变更设计系统
- 细致的模块化;(架构设计+技术选型+服务划分)
- 可扩展的函数;(这个太熟悉了)
- 精确完整的模块间接口设计;(架构设计合理,接口规定定义,明确服务功能边界)
- 完备的文档;(产品文档+api文档+技术方案文档+需求文档+用户使用说明文档等等)
- 调用队列;(是不是模块之间调用的时序图)
- 表驱动;(现在服务商也有很多)
- 减少变更引起的错误(①使用高级语言,现在这个已经很普遍,作者那个时候高级语言还很少,且没有现在智能;②自文档技术,这一点现在做得也比较好了,javadoc等)
注意: 变更的阶段化是一种必要的技术。为什么这么说呢?
每个产品都应该有数字版本号,每个版本都应该有自己的日程表和冻结日期,再次之后的变更属于下一个版本的范畴。参考JDK升级发布版本计划。
二、为变更计划组织架构
系统发生变化时,管理结构也需要进行调整。这意味着如何使管理人员和技术人员互换成为了难点。管理结构的变更,存在以下2点障碍:
- 管理人员自己常认为高级人员太 “ 有价值 ” ,而舍不得让他们从事编程工作。
- 管理人员剧透更高的威信。
那么针对这两点障碍,如何破解难题呢?
那就是 培养不同的晋升线。
管理人员人员参与技术课程,高级技术人员需进行管理培训。项目目标、进展和管理问题必须在这些高级人员中得到共享。
接下来作者讲的一个观点特别的有意思,博主自己是深有感触,不知道大家感触如何。
三、为什么缺陷不能更彻底的修复?
程序维护(设计缺陷的修复,这些软件的变更通常包含了更多的功能新增)中一个基本问题 —— bug修复总会固定在 20% ~ 50% 的几率引入新的bug。所以整个过程是前进两步,后退一步。
麻省理工学院核科学实验室 Betty Campbell 指出,特定版本的软件发布生命周期有一个有趣的循环。起初,上一个版本中被发现和修复的bug,在新的版本中仍会出现。新版本的新功能会产生新的bug。解决了这些问题之后,程序会正常运行几个月。接着,错误率会重新攀升。Betty 认为,这是因为用户的使用达到了新的熟练水平,他们开始运用新的功能,这种高强度的考验查出了新功能中的很多不易察觉的问题。
那具体是❓什么❓导致bug不能被彻底修复呢?
- bug看似是局部的,实际上是系统级别的,范围更大。局部的修复量往往不大,很快就被解决,但是更大范围的修复往往会被忽略。
- 维护人员往往是新手或初级开发人员,不是最初编写的人员。
四、前进两步,后退一步 ⏩ 最终演变为 ⏩ 前进一步,后退一步
系统软件开发是减少系统混乱度(减少熵)的过程,所以它本身是出于亚稳定的状态。
软件维护是提高混乱度(增加熵)的过程,所有的修改都倾向与破坏系统的架构,增加了系统的混乱度(熵),即使是最熟练的软件维护工作,也只是放缓了系统退化到非稳态的过程。
而且,机器在变化,配置在变化,用户的需求在变化,总会有那么一个时间点,崭新的,基于原有系统的重新设计。(这时,就到了我们展现自己的技能,通过前人大佬们的设计模式:工厂模式、单例模式、单一职责模式等等,大厂总结出来的原则:最小可用|快速接入 原则、经济原则——成本问题、代码复用原则——方案复用或代码库的复用、奥卡姆剃刀原则——在系统设计和代码编写过程中要求:一个功能模块如非必要,就不要;一段代码如非必写,就不写。遵循以往的经验,我们能够知道,所有的系统设计,最初的时候总是最好的。请记住作者的这句话: 请一定要为了舍弃而设计 )
十二、干将莫邪
工具集:
1️⃣ 项目的关键问题是沟通,个性化的工具会妨碍沟通而非促进沟通。
2️⃣ 所有的工具生命周期都很短。当机器和工作语言发生变化时,技术也会随之变化。
3️⃣ 开发和维护公共的通用的编程工具,效率会更高。
(自动化文档,自动化生成代码,快捷键唤醒各种便捷操作,代码补全提示,代码错误检查,代码快速格式化,各种GUI(用户可视化操作界面)操作工具,使编写的代码更加规范,使执行命令更加方便,如今这些都习以为常。作者的40多年前的想法如今都得到了实现,而且技术发展的都很成熟,忍不住赞叹一句,🐂🍺)
因为这一章节讲述的内容,在如今互联网时代,都已经得到了验证,且技术发展很成熟,不过多阐述,简单记录📝下作者描述,当时那个年代,大家急需的编程工具有哪些。
开发系统所需的编程工具
随着新调试技术的出现,旧方法的使用减少,但并没有消失,还需要内存转储、源文件编辑、快照转储、甚至跟踪等工具。
(于此类似,开发新功能,接口需向下🔽兼容,并有较好的版本控制管理。这是博主的扩散想法)
十三、整体部分
这一章节着重讲解了:
1️⃣ 如何开发可运行的系统 ❓
2️⃣ 如何测试系统 ❓
一、剔除bug -> 的设计
- 测试规格说明;
结合我们当下互联网的快速发展,这个阶段我理解为就是规范的测试用例输出,测试覆盖的场景以及最终的预期结果,其中可能还包括:测试集成、接口压测等。 - 自上而下的设计;
① 清晰的结构和表达方式更容易对需求和模块功能进行精确的描述。
② 模块分割和模块的独立性避免了系统级bug。
③ 细节的抑制使结构上的缺陷更加容易识别。
④ 设计在每个精华步骤上都是可以测试的。 - 结构化编程;
也就是规范我们的代码,例如: if - else 的结构化,避免了 go - to语句不加限制的分支跳转,产生的自身逻辑错误。
二、测试系统
- 阶段化(量化)、定期变更;
版本发布、紧急的打补丁解决。 - 控制变更;
有人负责和替换,也就是owner不同的环境进行调试验证,记录变更(如Git)。
十四、祸起萧墙
如何控制项目一点点的延期意外,导致最终灾难性的偏离。
1、制定进度表
每一个进度表描述的事,都可以成为“ 里程碑 ”,所有的事情(“ 里程碑 ”)的描述都必须是具体的、特定的、可度量的事件,能够进行清晰的定义。
如果里程碑描述的是模糊的,那么老板(上级领导)就会得到一份与实际情况不符的报告,毕竟,没人愿意承担坏消息,这种做法并不是可以欺骗,只是为了缓和。
2、REST图的准备
合理使用REST技术,对关键路径计划细化,不断进行努力,制定下一份REST图,并不是每一天的滞后都会带来灾难性的偏离,团队内部可以互补,补偿其他部分失去的时间。
3、一线经理发现计划偏离?怎么处理合适呢
一般来说,一线经理发现自己团队计划偏离是,并不会向老板汇报,都会先尝试自己去解决。原因有如下:
- 老板处理的事情比较多,减少打搅。
- 经理的利益和老板的利益内在冲突,如果汇报了问题,老板介入,后续行动会取代经理的作用,经理的威信会被降低,计划会被打乱。
但是有些时候,这些计划的偏离,项目的滞后还是需要向老板汇报,因为老板需要这些数据,来进行数据状态的分析,那如何避免上述2种情况呢?
1、减少角色冲突
老板必须会区分行动信息和状态信息,规范自己,不对项目经理可以解决的问题作出反应,决不在检查状态报告的时候作出安排,接过“ 皮球 ”前请先三思。
2、REST图
定期对部分进行评审(可以每周)
对整体进行评审(每月 | 每个季度)
最后REST图的制定、变更、修订、更新等最好有一个专门的小组(1~3人),这个小组可看做老板的延伸,这样,产品经理负担将会减少,因为只需要做好决策就好,文字工作有专门的小组去处理。
十五、另外一面
文档的重要性 =》如何写出一篇优秀的文档。记忆会会衰退,作者会失去程序的了解。对软件编程来讲,程序向用户所呈现的和提供给机器识别的内容同等重要。
1、流程图
作者建议一页,过多的流程会破坏整体结构。
2、自动化的文档程序
加注释,命名规范,把源程序作为文档介质,强制推行一些约束。(我的理解是javaDoc文档)
十五、没有银弹——软件工程中的根本和次要问题
软件活动:分为根本任务和次要任务。
根本任务:打造构成抽象软件实体的复杂概念结构。
次要任务:使用编程语言表达这些抽象实体,在空间和时间的限制下将他们映射成机器语言。
根本困难
Brooks认为软件开发最困难的部分是规格说明、设计和测试这些概念上的结构,而不是对概念进行表达和实现逼真程度进行验证。
由于软件开发的(复杂度、一致性、可变性和不可见性)使得开发总是非常困难,为什么会这么说?
1、复杂度
首先两个软件,没有在语句级别上的相同,如果相同,我们往往会合并成可供调用的子函数。同时,计算机存在多种状态,这使构思、描述、测试都变得困难,而软件系统盘的状态又比计算机状态多若干个数量级。
其次,软件实体的扩展,是以不同元素实体的方式添加,这些元素以非线性递增方式交互,这使得整个软件的复杂度以非线性增长要多的多。
PS:软件复杂度是根本困难,不是次要因素
2、一致性
复杂性引申出来的延伸,由于不同人开发,使得复杂度随心所欲,毫无规则可言。
因此很多复杂性来自保持与其他接口的一致性,对软件的任何再开发,再设计,都无法简化这些复杂的特性。这就使得软件的开发目标,很多情况是为了兼容性,必须遵循各种接口,这也就造成了复杂。
3、可变性
软件实体经常会遭受到持续的变更压力。
软件产品扎根与文化的母体中,如各种应用、用户、自然及社会规律、计算机硬件等。后者持续不断地变化着,这些变化无情的强迫这软件也随之变化。
没有做不完的需求,只有永远在变化的需求。
4、不可见性
软件是不可见的和无法可视化的,他的客观存在不具有空间的形体特征。
次要困难
解决软件构建上的困难。
使用高级语言可以提高开发效率,生产率会被提高。有了高级语言,我们会更多的把经理放在数据结构,数据类型和操作的复杂度(时间复杂度或空间复杂度),程序开发也就会越来越接近用户复杂度。