序
《人月神话》虽成书于四十余年前,其真知灼见至今仍具有强大的现实意义。作为 IBM OS/360 项目的项目经理,布鲁克斯将其丰富的项目管理经验和深刻思考凝结成这部经典著作,旨在探讨如何提升软件开发效率并降低缺陷率。
布鲁克斯巧妙地借用民间传说中最为可怖的"人狼"来比喻软件工程中的困境。正如一位挚友可能在月圆之夜突然化身为狼,一个运行顺畅的项目也可能在某个节点突然失控。而能够制服这些"人狼"的方法,则被比作"银弹"。
在布鲁克斯的分析中,软件工程面临着四个根本性的困难:
1、复杂度
软件系统的复杂性是其本质特征,而非表象。这与物理学或数学中可以通过模型简化的复杂性不同。在软件工程中,即便是看似相似的功能,其实现细节往往也各不相同,如果存在相同的情况,我们也会将它们合并成供调用的子函数。而且软件实体的扩展也不是相同元素的添加,而必须是不同元素的添加,同时元素的添加往往以非线性递增的方式交互,因此整个系统的复杂度会比非线性增长要多得多。
2、一致性
开发团队需要持续处理各种人为造成的不一致性。这些不一致往往源于不同人员、不同时期对需求的理解差异,以及在确保业务逻辑和技术实现一致性方面的挑战。
3、可变性
不同于建筑或汽车制造业,软件系统的变更成本相对较低,同时软件系统包含了很多功能,而功能是最容易感受到变更压力的部分,这导致用户倾向于不断提出新的需求。一个成功的软件产品往往需要持续演进,以适应用户不断增长的需求。
4、不可见性
软件系统缺乏物理形态,难以像建筑设计图或电路图那样直观地展现其结构。软件系统往往是多个维度的抽象概念的叠加,这种特性限制了我们使用可视化工具来辅助软件设计和开发。假如我们一定要用图形来描述软件结构时、会发现它是很多相互关联、重叠到一起的的图形,软件无法可视化的固定特征,剥夺了一些具有强大功能的概念工具的构造创意。
接下来我会根据我在田界智航18周的开发经历和我对书中的内容的理解分享我的见解。
一、焦油坑
史前史中,没有别的场景比巨兽们在焦油坑中垂死挣扎的场面更令人震撼。上帝见证着恐龙、猛犸象、剑齿虎在焦油中挣扎。它们挣扎地越猛烈,焦油纠缠得就越紧,没有哪种猛兽足够强壮或具有足够的技巧,能够挣脱束缚,它们最后都沉到了坑底。
在软件开发中,一个bug的修复可能引起引起更多的bug,最后逐渐在挣扎中死去
我在田界智航开发中就遇到了这个问题,当时是在做换绑手机号的时候,因为其他与用户关联的表如地块、轨迹等因为所关联的不是用户id而是用户的username,这就导致换绑手机号后,上一个手机号所关联的数据都将查询不出来,为此大动干戈地修改了所有表的代码,但也正是这个问题和很多问题纠缠在了一起,导致问题的规模越来越大。耗费了我3个人日来修复这些bug。
1.1 编程系统产品的演进
软件开发可以分为四个层次,每上升一个层次都需要付出更多的努力:
-
程序:单个开发者可完成的独立代码
-
编程系统:需要 3 倍于程序开发的工作量,实现多个组件的协同
-
编程产品:需要 3 倍于程序开发的工作量,确保可测试性、可维护性和完整文档
-
编程系统产品:需要 9 倍于程序开发的工作量,是真正能在生产环境中发挥价值的完整解决方案
而只有编程系统产品是真正有用的东西,也是大多数系统开发的目标
1.2 职业的乐趣和苦恼
乐趣
对我而言,编程的乐趣在于创造和被人认可,正如马斯洛需要层次理论中的最高层次–自我实现。
田界智航是我参与的第一个的项目,当第一次将项目跑起来的时候和请求返回正确的结果的时候,这一刻的喜悦和成就感满满。
而关于书中的学习的快乐我认为不能单独仅仅理解为学习是快乐的,我认为如果仅仅是为了学习知识而学习的话,学习是枯燥无聊的。但是如果和项目中遇到困难后主动学习,那么这个学习后解决问题的结果肯定是快乐的。
在初期遇到的问题都有是有成熟的解决方案的,所以只要照抄即可,但是到了中后期,所遇到的问题可能是综合问题,没有一种标准的处理方法解决你的问题,所以你提高自己的学习能力和分析问题的能力(也就是所谓的瓶颈)。
苦恼
而程序开发的的苦恼也是十分苦恼的,如使用别人代码但是因为版本不一致导致的各种错误,又或者他们给自己设定了目标但是并非是自己喜欢的内容,又或者干很多重复性的枯燥的没有挑战性的工作,这样的工作十分苦恼。
比如对于如数据校验,正则表达式对输入内容的限制等易容性而非创造性的工作,往往是十分苦恼的。
而且对于编程人员而言,对其他人的依赖也是十分苦恼的,就比如在前后端分离的项目中,如果数据格式不统一,那么对于两端的人员都十分的苦恼,但是软件工程本身就是团队型的工作,必须有人愿意依赖和帮助别人。
还有一个苦恼就是当投入大量时间开发完毕后,发现自己所开发的项目已经落后和过时了,自己的工作成果得不到认可。
这就是编程,一个许多人痛苦挣扎的焦油坑以及一种乐趣和苦恼共存的创新性活动。
二、人月神话
用人月作为衡量一项工作的规模是一个危险和带有欺骗性的神话
在项目进行过程中,进度的落后是由很多问题导致的。
比如
-
对任务时间的估算不合理
在开发初期我们往往会乐观的估算任务所需完成的时间,比如我们项目在做地块管理这一部门的时候,想的是不就是一个增删改查吗,一个晚上就能做完。但是在实际开发的过程中,会到踩在估算中设想不到的坑,但又因为有DeadLine的要求,我们就不得不加班,但是实际上,这个问题并不是因为不加班所造成的
-
潜意识中认为人和月是可以互换
当项目落后不得不延期的时候,在潜意识中总会认为,我们再几个开发人员一起分担任务,是不是就能够按时交付了。答案肯定是否定的,具体的原因我会在后面进行分析
-
对自己的估算缺少信心
再低一点中我们说到乐观的估算任务时间导致无法在deadline完成,那么后续可能造成消极的估算任务,或者就算自己任务完成了但是并没有汇报。
项目经理此时就无法准确的甚至没有耐心估算整个项目的时间范围
但是敏捷开发中又鼓励对自己的任务进行估算,为此我们将引出下面的对进度的跟踪和监督
-
对项目的跟踪和监督不合理
在软件开发中,大家都讨厌对自己任务的监督过于严格。但是过于松懈也肯定是不合理的,在敏捷开发中鼓励对任务进行估算,但是 每个人和每个人的能力、习惯甚至每天的状态都是不同的。假如小王今天感冒了,小李今天被拉去开了很多场会议。
久而久之和原本估算的计划就会有很大的偏差,因此在敏捷开发中,我们设有每日立会、燃尽图等一些列活动或者会议来帮助我们动态调整这个过程
2.1 落后的项目增加人手进度仍会落后
在《人月神话》这本书中,作者为我们举了一个简单的小例子,就是原本有一个12个人月的任务,分配给3个人在4个月的时间内完成,并在每个月的末尾安排了里程碑A、B、C、D
但是在两个月后第一个任务没有完成,如果必须按时完成的话
-
假设仅仅是第一个里程碑的内容估计的不恰当
我们还有9个人月的任务需要在2个月内完成,这样的原本3个人将会不够,现在需要4.5个开发人员
-
假设整个任务的估计都偏少了
那么原本的12个人月则需要估计为24个人月,这样还需要18个人月的工作量,需要在2个月内增加到9个人
但是还是即使按照人和月可以互换的情况下,我们在项目组中引入了新的开发人员,新的开发人员都至少需要接受一名有经验的员工的培训,在第一种情况中,如果培训一个月的时间,那么将会投入3个人月到原来进度以外的工作中。因此到了第3个月的月末,仍然残留着7个人月的工作,但现在有效的人月只剩了5个,项目依然会延期交付
因此,用人月作为衡量一项工作的规模是一个危险和带有欺骗性的神话。而这个问题一开始的假设,12个人月的任务分配给3个人在4个月的时间内完成本就是不合理的假设
2.2 因为系统测试的不及时导致的项目延期
田界智航开发于9月初,原本计划在10月初国庆假前后上架应用市场。原本在10月初第一版的开发内容已经完毕,但是因为乐观主义没有预想到缺陷的数量,导致系统测试接入的时候,大量缺陷被触发,而修复bug和一次次被应用市场打回造成了第一个里程碑的延期。
测试工作应该是要尽早介入,系统测试所牵连的缺陷更彻底,可以捕捉到单元测试中难以捕捉到的bug,而合理安排测试计划是保证项目按期交付的重要因素。
三、外科手术队伍
效率高和效率低的实施者之间个体差异非常大,经常能够达到数量级的水平
我们是否经常吐槽,为什么白天会有开不完的会,为什么领导不用写代码还一直打扰我们工作
但是如果仔细想一想的话,其实正是因为有项目经理,才能够保证我们能够专心工作。
项目经理召开每周例会可以帮助整个团队的交流沟通,而且正是有了项目经理向领导汇报工作,对客户沟通交流,开发人员测试人员才不会被这些外部事件所影响
十分庞大的项目如果给一个小型队伍,产品做出来已经落后了,如果给一个大型队伍,大型队伍中效率高、有能力的往往仅仅只有小型队伍的人数,如果把普通的人员全部踢掉,这些能力高的程序员依然可以完成,同样也会花费很长时间,做完依然会过时
那么什么样的队伍分工是合理的,书中给出了一种外科手术队伍
3.1 队伍分工
-
外科医生
在软件开发中,我认为是架构师的角色,他亲自定义功能和性能技术说明说,设计程序,编制源代码,测试以及书写技术文档
但是这样厉害的架构师或者首席程序员太难了,不妨放弃一点集权多一些民主
-
副手
在团队中主要负责沟通的角色,与其他团队的功能和接口讨论中代表自己的小组
-
管理员
充当与组织中其他管理机构的接口,我认为软件开发中敏捷教练很适合充当这个角色,确保团队能够正确地做事,控制财务、人员、工作地点
-
编辑
对文档进行分析重组、提供各种参考信息和书目,对多个版本进行维护以及监督文档生成的角色
-
两个秘书
管理员和编辑各需要一个秘书,秘书负责项目的协作一致和非产品文件(协调者)
-
程序职员
专门负责写代码的
-
工具维护人员
运维工程师或者测试开发工程师,维护测试平台或者维护系统平台
-
测试人员
给外科医生编写大量合适的测试用例(要求很高,因为要给架构师提供测试参考)
-
语言专家
CTO,技术专家,需要具备很强的组织和分享能力
这种专业分工化,使得程序员从无尽的杂事中解放出来,保证了工作的质量。而且这十个人中有七个专业人士在解决问题,而系统是一个人或者最多两个人思考的产物,客观上达到了概念的一致性
在敏捷中虽然提倡民主和平等,但是依然还是有主干系人和辅干系人的。在这个外科手术队伍中和现在敏捷开发团队其实是有很多共同之处的,如PO,SM, 开发人员,测试人员,文档管理人员或平台等
这个外科手术队伍给我们说明了小团队的优势,但因为时代不同,并不需要仿照这个角色进行划分定位。而需要根据时代需求动态调整,但是如果是一个5000人年的大项目,应该如何应用外科手术团队的概念,这就需要将系统进行分解,让每个部分的概念完整性得到彻底的提高
四、贵族专制、民主政治和系统设计
风格的一致性和完整性来自8代拥有自我约束和牺牲精神的建筑师们,他们每一个人牺牲了自己的一些创意,以获得纯粹的设计
在敏捷开发中,虽然十分推崇民主政治,但是也并拒绝做专制。
民主的前提是大家都具有相同的认知,能够有效的交流和讨论,假如一个团队有两个没有开发经验的实习生,如果没有某方面业务的认知和技术的储备,那么这俩实习生的意见将变得不那么重要
4.1 概念完整性
业务才是价值的体现,不管是开发人员还是测试人员,应该把核心放在业务,而非技术上。就像欧洲大教堂8代设计师他们每一个人牺牲了自己的一些创意,获得纯粹的设计
对于计算机系统而言,绝大多数系统体现出的概念差异和不一致性远远超过欧洲的大教堂,这通常并不是由不同时代的设计师们开发,而是由于设计被分成由若干人完成的若干任务
在系统设计中,概念完整性应该是最重要的考虑因素。为了反应一系列连贯的设计思路,宁可省略一些不规则的特性和改进,也不提倡独立和无法整合的系统,哪怕他们其实包含着很多很好的设计
4.2 如何获得概念完整性
软件设计中,概念完整性的实现方式一直是一个备受争议的话题:是应该由架构师独断专行,还是应该采取团队共同参与的方式?根据实践经验,这需要因地制宜。在团队开发经验不足时,由经验丰富的架构师主导可以确保系统的概念完整性;而当团队成员能力相近且都具有创新潜力时,采用民主协作的方式则能激发更多创造性思维。
在我刚进入田界智航开发组的时候,因为团队开发经验不足,概念完整性是由我们的架构师专治的,但我在做第二个项目式因为团队都是和我水平相近和刚进入软件行业的新人,概念完整性的获取则变成了民主政治。
无论采用哪种方式,确保概念完整性后的关键挑战在于如何提升系统易用性。
易用性包含两种
- 用户学习和使用的易用性
- 代码维护的易用性
在实现上,每个部分必须反应相同的原理、原则和一致的折衷机制。在语法上,每个部门应使用相同的技巧;在语义上,应具有相同的相似性。因此,易用性实际上需要设计的一致性和概念上的完整性
比如在写http接口的时候,风格应该遵循restful保持一致
比如http code和msg code
http code是服务器级别的状态提示,而msg code是应用级别的状态提示
4.3 贵族专制统治和民主政治
假设这样一个场景,我们采用职能型组织结构,大领导让我们统一使用公司开发的框架,这就如同谈一段恋爱,如果这个框架正好解决A部门的痛点,那A部门和这个框架之间的关系就像是亲密无间的小情侣。但是B部门并不是干系人,并且很抵触这个框架,任何一个软件系统或者产品都不会是Zero Bug,由于是大领导的专制,B部门职能和这个框架进行磨合,但是这个随着这个框架后期出现了各种各样的bug,造成了重大的影响,那么B部门和这个框架之间的关系就好比乖乖女和渣男,被狠狠地伤害
书中也明说了虽然概念的完整性要求设计必须由一个人,或者非常少数互有默契的人员来实现,但是进度压力却要求很多人员来开发系统
上一章我们谈论了小团队的优点,在外科手术队伍中实现民主政治很容易,但是在大团队中就很难通过民主政治实现概念完整性
人月神话中的这句话我很喜欢
系统的结构师,如同建筑的结构师一样,是用户的代言人。结构师的工作,是运用专业技术知识来支持用户的真正利益,而不是维护销售人员所鼓吹的利益
行文至此,会不会产生一个疑问
概念性设计这种富有创造性的工作都交给少数人做了,那么下面的实现人员是不是都是没有创造性的牛马?
实现人员和设计人员只是工作性质不同而已,两者都是一种创造性的工作,在易用程度上依赖于设计师的工作,但是在成本性能比上还是依赖于实现人员的工作
就比如在田界智航中我做的轨迹部分的工作,架构师选定好了轨迹这部分使用influxdb这个时序数据库,而我作为实现人员依然可以在算法工作上富有创造性,比如通过射线法判断轨迹点所属的地块,对轨迹面积去重算法的一步步优化
4.4 磨刀不误砍柴工
在书中提出了这样一个问题,就是在OS/360的外部技术说明的制作需要10个月的时间,但是这样的话这十个月实现人员将会是干等十个月无所事事,其队伍的体系结构经理的反应是如果将这个工作交给程序实现队伍,也不会按时完成,还会延期三个月,结果是布鲁克斯将工作交给了程序实现队伍,结果也确实如此。
但是当时这个大概是瀑布模型,在敏捷增量过程中是小模块的累加,但是敏捷并不能真正的解决这个问题,敏捷因为迭代目标小,周期短,能够让我们意识到缺乏统一架构带来的缺点。
五、画蛇添足
第二个系统是设计师们所设计的最危险的系统
5.1 结构师的交互准则和机制
我十分认可书中所说的给结构师的建议
- 牢记是开发人员承担创造性和发明性的实现责任,所以结构师只能建议,而不能支配
- 时刻准备着为所指定的说明建议一种实现的方法,同样准备接受其他任何能达到目标的方法
- 对上述的建议保持低调和不公开
- 准备放弃坚持所作的改进建议
5.2 开发第二个系统所带来的后果
结构师在做第一个项目时,因为对自己要做的任务不够了解,所以会谨慎仔细的工作,更倾向于设计的精炼和简介。
但是在做第一个项目的时候会不断产生装饰和润色功能的想法,但往往会被搁置下来。
直到开始第二个项目时,结构师感觉第一个项目做的不错,那么会在第二个项目中添加这些想法,会大量引入新特性,新功能。因此第二个项目会是设计师们所设计的最危险的系统。
反而第三个第四个项目时,先前的经验会相互验证,会帮助结构师识别出经验中不够通用的部分。
5.3 避免画蛇添足–开发第二个项目时的危险
所有结构师都无法跳过第二个系统,但他可以有意识关注那些系统的特殊危险,运用自我约束准则来避免那些功能上的修饰;
或者根据系统基本理念及变更的目的,舍弃一些功能
六、贯彻执行
passing the word
6.1 文档
虽然敏捷宣言中有一句话“工作的软件高于详尽的文档”,但是现在对于手册的要求依旧是很强的,例如每个产品的新手指导、入门教程。都是把死气沉沉的文档变成了可执行的文档。
而田界智航app在前两个版本中并没有考虑到这个问题,新用户注册账号进入软件之后,只会看到一些没有文字标注的按钮,这些按钮的功能只能通过用户尝试之后才能了解。
同时随着用户和实现人员的增加,软件规格说明书中难以使用和难以构建实现的地方不断被指出,规格说明书也不断地被重复准备和修改。
在写文档(不管是正式文档还是可执行文档)时风格必须清晰、完整和准确,每条说明都必须重复所有的基本要素,所有文字都要相互一致,这是因为精确比生动更加重要。
要做到文档的一致性必须由一个或两个人来完成将其结论转换成书面规格说明的工作,在第三章时我们提到了一个外科手术队伍,其中的编辑正是专门做书写和维护文档这一工作的。
6.2 形式化定义
任何的人类语言从根本上说,都不是一种能精确表述上述定义的手段,手册的作者必须主要自己的思路和语言达到需要的精确程度 (对于不同的用户,精确的级别也是不同的)
形式化的优点
- 定义精确
- 更加完整
- 差异明显
- 可以更快完成
形式化的缺点
- 不易理解
- 结构性差
而记叙性文字则可以显示结构性的原则,描述阶段上或层次上的结构,以及提供例子
那么在书写文档的时候,应该如何选择?
有一句古老的格言很有意思
“绝不要携带两个时钟出海,带一个或三个”,同样在书写文档的时候,必须以一个作为标准,另外一个作为辅助描述,敏捷过程中以用户故事为核心,辅助验收标准作为形式化
在定义的过程中,当尖锐的问题被提及时,实现有时会给出未在计划中的意外答案,这些答案中,真正被定义的常常是粗糙的,因为他们从来没有被仔细考虑过。这些粗糙的功能在其他的设计实现中,往往是抵消或者代价高昂的。
在我刚进入田界智航项目组时,我和我的组长在实现某个功能之前,一直思考这样实现会不会造成什么未来的后果,如果用户后续有了其他需求怎么办之类的导致实现一直进行不下去,而我的恩师苏老师教给了我MVP原则及最小可行性产品,用最小的成本开发出可用并且表达出核心理念的产品,在获取到用户反馈后持续迭代优化产品不断适应市场环境。
6.3 直接整合
这部分内容我希望用一句话概括,即尽可能多的做持续集成
6.4 会议
会议这部分书中将会议分成了两个级别,周例会和年度大会
但我认为敏捷中会议还需要包括每日立会、回顾会
周例会更像是迭代会议,在这个会议中PO讲解用户故事,Team将PBI拆解成Task
每日立会交流每个人工作进度、暴露开发困难
回顾会则是在反思总结在敏捷过程中遇到的困难和经验
6.5 测试
项目经理最好的朋友就是他每天要面对的敌人–产品测试小组
产品测试小组告诉产品经理软件还有什么不足
任何一个无法重现的缺陷用户一定会用到,如何尽早的预防缺陷,如何发现更多的缺陷?
七、为什么巴比伦塔会失败
他们只是一个种族,使用一种语言,如果他们一开始就能建造城市和高塔,那以后就没有什么难得倒他们了。来,让我们下去,在他们语言里制造一些混淆,让他们相互之间不能听懂
巴比伦塔是人类继诺亚方舟之后的第二大工程壮举,同时也是第一个彻底失败的工程
7.1 巴比伦塔失败的原因
失败的原因既不是因为人力不够,也不是因为技术不足。而是缺少交流以及交流的结果及组织
在《三体》这部科幻小说中,我们都知道三体人的思维是透明的,所有三体人都知道互相在想什么,群体中没有猜忌和说谎。虽然用科幻小说中的内容类比不太合适,但是交流却是软件工程成功的必然要素。
7.2 大型项目中的交流
-
面对面沟通
足够多的会议室或者开放环境
这18周我们小组是在501办公室工作的,这个办公室的构造是那种面对面的桌子,交流起来十分的方便,而在教室做实训项目的小组因为是上课那种课桌式的环境,交流和移动位置需要大动干戈,因此教室氛围不如办公室活跃,但相反的是,办公室因为时时刻刻都有人在交流沟通导致很难找到一个安静的时间段专注自己的事情。因此在办公室这种环境下配备一个降噪耳机是必不可少的。
-
会议
在团队中,会议是一件很重要的事情,开会的过程正是同步的过程,能澄清成百上千的细小误解
-
工作手册
在敏捷过程中,文档不一定是传统意义上的文档,可以是大家对技术的认知、提升,将其代码化。
比如swagger通过注解生成的接口文档
-
确保信息发布达到所有需要它的人的手中
比如使用邮件或者钉钉通知到所有需要的人,并且使得信息留痕
7.3 大型项目的组织架构
如果项目有n个工作人员,则有(n²-n)/ 2个相互交流的接口
其实就是握手问题,假如一共有n个人
第一个人需要握手(n-1)次
第二个人需要握手(n-2)次,因为和第一个人已经握过手了
...
倒数第二个人只需要握手一次
如果每个人都相互握手一次,一共n个人,每个人握手n-1次,去除重复握手 ==> 结果是n(n-1) / 2
也就是(n²-n)/ 2
减少交流的方法就是人力划分和限定职责范围
大到一定规模的工程,一个外科手术精英团队也是搞不定的,团队效率高但是没办法完成大的工程,所以现在都是小团队多协作
八、胸有成竹
实践是最好的老师,但是,如果不能从中学习,再多的时间也没有用
完成某个任务需要多长的时间?需要多少的工作量?如何进行估计?
在刚开始的时候估算是很困难的,认知和经验都会带来不同的结果,那么应该怎么避免这个问题?
大家肯定会想到,那些大厂不都有研发效能度量指标吗,我们根据那个估计不就可以了吗
但其实不是
首先就是项目不同、人不同
2b的业务和2c区别就很大,这也是为什么大多数2b的系统都在走预测性的系统架构(瀑布模型)
比如我在玩《原神》的时候,每个账号完成每日委托所需要的时间也会因为角色练度,队伍搭配,每日任务复杂程度而花费不同时间,但是我却可以根据大量的实践估算出一个上限和一个下限时间
接下来书中给出了各个公司项目的数据
我用几句话概括一下就是
- 进度落后一半,成本花两倍
- 研发效能度量不能按照数量而应该按照质量
九、削足适履
他应该瞪大眼睛紧盯着诺亚,然后…好好学习一下,看他们当时是怎么把那么多东西塞进一个小小的方舟上的
9.1 作为成本的程序空间
在40多年以前,空间成本是十分昂贵的,魂斗罗的大小只有128KB却包含了丰富的剧情音乐动画。
而现在随便找一款3A游戏都是80GB、100GB这种,那么为什么会这样呢。仔细想一想其实很好理解,现在空间成本占比其实是非常小的,而CPU成本要比空间成本高得多,只不过是用空间资源换CPU计算的时间
之前的程序员甚至会为了考虑资源而去做一些算法优化,现在的程序员则很少考虑这一点
如经典例题如何只用两个变量交换两个变量的值?
比如有两个变量 int a = 5, int b = 10
第一种方法直接用加减法运算实现
public static void main(String[] args) {
int a = 5, b = 10;
// 使用加减法交换
a = a + b; // a = 15
b = a - b; // b = 5
a = a - b; // a = 10
}
第二种方法是通过乘除法
public static void main(String[] args) {
int a = 5, b = 10;
// 使用乘除法交换
a = a * b; // a = 50
b = a / b; // b = 5
a = a / b; // a = 10
}
不过这两种种办法会有数值溢出的风险
第三种方法是使用异或运算
public static void main(String[] args) {
int a = 5, b = 10;
// 使用异或运算交换
a = a ^ b;
b = a ^ b;
a = a ^ b;
}
仅仅是交换两个变量的值就很值得思考,那么可见对于其他的内存的申请释放这些实现并不容易
及时是现在2024年的程序员,如果不考虑空间成本,往往性能会很差,就举一个很简单的例子,一个刚入职的程序员感觉资源很充足,于是写了一个select * 的sql,及时写完时能够撑得住,但是随着体量不断变大,一定会出现很大的问题
9.2 规模控制
对于项目经理而言,规模控制既是技术分工的一部门,也是管理工作的一部门。
所有的程序都应该遵循“高内聚、低耦合”的原则,随着程序的开发,复杂性会越来越大,如果不能做到高内聚低耦合,那么项目就是个不可维护的,难以优化的
我之前在看阿里规范手册(嵩山版)的时候一直有一个疑惑,为什么不能直接写存储过程?
直到我后续看了一些设计原则的文档之后才想明白,存储过程太大了,如果出现了性能问题,是难以优化的
和制定驻留空间的预算一样,应该制订总体规模的预算,制订存储访问的预算
为了满足目标,每个人都在局部优化自己的程序,很少会有人停下来考虑一下对客户的整体影响,系统架构师必须时刻保持持续的警觉,确保连贯的系统完整性
9.3 算法优化
技艺改进的结果往往是战略上的突破,这种战略上突破有时是一种新的算法,如快速傅里叶变换,或者是将比较算法的复杂度从n²降低到nlogn
十、提纲挈领
文档的追踪维护是项目监督和预警和机制
文档的追踪维护是项目监督和预警和机制。文档本身可以作为检查列表、状态控制,也可以作为汇报的数据基础
我们开发小组在开发的过程中并没有重视文档的书写,以至于在开发任务完成后需要补写文档,及时在补写文档的过程中我们团队依旧对编写文档的任务没有激情
我之前问过我的同事,你怎么看待编码和编写文档的重要性,我的同事回答让我感觉十分思议,他的回答是写文档对自己的提升没有意义
10.1 软件项目的文档
软件项目的文档需要的内容
- 目标
- 技术说明
- 进度
- 预算
- 组织结构图
- 工作空间的分配
- 报价、预测、价格
当然这都是该书提到的
在我们实际开发中产生的文档有《技术架构图》、《项目章程》、《核心团队说明》、《干系人登记册》、《里程碑进度计划》、《资源需求说明》、《用户分析》、《问题描述》、《界面原型图》、《技术分析》、《风险估计》、《产品愿景和商业机会》、《产品构思》、《用户手册》、《数据库设计文档》、《接口文档》
10.2 为什么要有正式的文档
首先,书面的记录决策是必要的。只有记录下来,分歧才会明朗,矛盾才会突出。
第二,文档能够作为同其他人的沟通渠道
最后,项目经理的文档可以作为数据基础和检查列表
因此不管对于一个项目、团队、还是个人来说,文档都是必要的
十一、未雨绸缪
唯一不变的就是变化本身
11.1 实验性工厂
当我们面对一个新的项目、或者新的技术,在不确定的情况下唯一能做的就是不断试错
(比如要使用一个全新的技术,项目组中没有一个人会用这个技术,那么可以先写一个Demo再给他放大)
对于大多数项目项目,第一个开发的系统并不合用,他可能太慢、太大,而且难以使用,或者三者兼而有之。要解决所有问题,除了开发一个更灵巧或更好用的系统以外没有其他办法,随着新的系统概念和新技术的出现,开发的难用的系统必须被抛弃
正如“做加法很容易,做减法很难”,要不要舍弃系统,是不是要舍弃一部分功能?
11.2 唯一不变别就是变化本身
变化是与生俱来的,实验性工厂只能帮我们进行初步探索,一定是要推翻重做的。同时开发人员交付的是用户满意程度,即用户价值被实现了,不仅仅是实际的产品。随着每一次交付,用户的实际需求和用户感觉会随着程序的构建、测试和使用而变化。
对于硬件而言,一旦发布就很难改变的性质,但是软件由于可变性(在序中提到的软件四个根本困难之一)导致软件需求一直发生变化,构建人员面临永恒的需求变更。
11.3 为变化计划系统
如何为上述变化设计系统,是个非常著名的问题
这部分我认为现在开发中的版本控制、分支模式就是解决这个问题的一种方法
(如dev分支,release分支,master分支,test分支以及版本号)
11.4 为变化计划组织架构
设计人员通常不愿意提交尝试性的设计决策,再为他们进行辩解。通过设计文档化,设计人员将自己暴露在每个人的批评之下,他必须能够为每个结果进行辩护。
为变更组件团队比变更进行设计更加困难,因为每个人都不愿意修改自己原本的和其他人原本的设计。
当系统发生变化时,管理结构也需要进行调整。这意味着,只要管理人员和技术人才的天赋允许,老板必须对他们的能力培养给予极大地关注,使管理人员和技术人才具有互换性。
管理人员和技术人才具有互换性,这句话十分认可,技术解决不了一切问题,但是管理人员不懂技术也很难完成需求做出管理
这其中的障碍是社会性的,人们必须同顽固的戒心做斗争,管理人员不能认为高级人员太“有价值”而舍不得让他们从事实际的编程工作,每个专业人士都是技术人员中的一员
在我原本的认知中,技术路线和管理路线是两条不同的发展路线,但是当我看到这个本中的晋升路线时,我觉得这个才是合理的晋升路线,不管是技术路线还是管理路线,最后发展成为的都是高级程序员
管理人员需要参加技术课程,高级技术人才需要进行管理培训,只要能力允许,高层人员必须时刻做好技术和感情上的准备,以管理团队或者亲自开发工作。工作量很大,但很值得!
11.5 前进两步,后退一步
对于程序发布后的维护成本通常是高于开发成本的,一个好用的软件随着用户变多,提出的缺陷也会变多,在修复缺陷中也会出现更多的缺陷
因此整个过程是前进两步,后退一步
那么为什么缺陷不能更彻底地被修复?首先,某些看上去很轻微的错误,似乎仅仅是局部操作上的失败,实际上是系统级别的问题,维护人员尝尝不是编写代码的开发人员,而是一些初级程序员或新手,而且每次修复bug之后要进行回归测试,而这整个过程成本就非常高了。
11.6 前进一步,后退一步
新版本发布的模块数量随版本号的增加呈线性增长,但受到影响的模块以版本号指数级别增长,所有的修改都倾向于破坏版本的架构,增加了系统的混乱程度,逐渐在焦油坑中挣扎着死去。
系统软件开发是减少混乱度的过程,它本身处于亚稳态的,软件维护是提高混乱度的过程,即使是最熟悉的软件维护工作,也只是放缓了系统退化到亚稳态的进程。
十二、干将莫邪
巧匠因为他的工具而出名
每位程序员都仔细地保管着自己工作生涯中搜集的一套工具,这些工具成为个人技能的直观证明。
但是项目的关键是沟通,个性化的工具妨碍而不是促进沟通,一个项目应该使用一套通用的工具,开发和维护公共的通用编程工具的效率更高。(这里强调的是有一套通用工具,和后文在有一套通用工具的基础下也要维护专业工具是不冲突的)
比如接口测试工具,在我们团队后期,有的使用的是postman,还有的使用的是Bruno,虽然我同事使用Bruno是为了解决postman不付费的情况下无法突破三人小队的限制的困难,但是因为转换工具的学习成本和转移成本导致并没有使Bruno成本通用工具,维护两个工具最后比仅使用和维护一个postman效率更低了。
不过仅有通用工具是不够的。专业需要和个人偏好同样需要很多专业工具,所以每个团队配备一名工具管理人员,他的职责是管理所有的通用工具,知道客户和老板使用工具并且编制老板需要好的专业工具。
12.1 目标机器
书中将机器分为了目标机器和辅助机器
目标机器也就是部署环境,需要有运维人员操作和管理目标机器,保证机器上的标准支持是即时更新和实时可用的
辅助机器是那些在开发系统中提供服务的机器,比如测试环境
在40多年前使用的还是批处理的操作系统,软件过程使用瀑布模型,所以对于机器使用时间的安排也是一个困难,因为不能够及时的进行测试,这就导致机器在初期是日复一日处于空闲状态,但是突然有一天大量系统上线,这时候资源分配就是一个严重的问题
而现在通过敏捷、MVP尽早就将资源使用,或者是将模块分离出来而不是一下子将所有模块同时占用资源。
12.2 为什么程序员都喜欢在夜间工作
在12.1中我们说到40多年前使用的是批处理操作系统,系统调试总是夜班性质的工作,尽管现在技术完全改变了,然而大家喜好的工作方式没有改变,这种工作方式的延续,是因为他的生产效率最高。
我们在做创造性工作的时候是不希望被别人打断的,在第七章中我讲述了我们501办公室白天时时刻刻都在讨论,那种氛围并不适合专注开发,白天开会讨论,而到了深夜,所有人都在家中安睡时。
这个时候我们可以尽情享受夜的寂静,让自己能够连续进行创造性工作。
12.3 辅助机器和数据服务
如果目标机器是新产品,则需要一个目标机器的逻辑仿真装置。这样,在生产出新机器之前,就有辅助的调试平台可供使用
12.4 编程工具
在资源有限的情况下尽可能提高编程工具的价值,比如买一个好点的电脑,真的可以提高开发效率。
也就是俗话说的“电脑越好,头发越少”,电脑太好了,打包构建的时间会很快,大脑在不停地思考,摸鱼的时间同样也会变少(我瞎说的)
12.5 文档工具
在田界智航开发中,我们是用来了一个公共文档编辑系统,团队所有人员都能登陆进来进行文档的书写和维护。
在所有的工具中,最能节省劳动力的,就是运行在可靠平台上的、计算机化的文本编辑系统,如何维护文档,避免出现文档太多了,看不过来的情况,也是一个值得思考的问题
十三、整体部分
如何开发一个可以运行的系统?如何测试系统?如何将经过测试的一系列构建集成到已测试过、可以依赖的系统?
13.1 剔除bug的设计
在设计环节上,是无法考虑到所有问题的,许许多多的失败完全与那些产品未精确定义的的地方。
因此我们不能在将产品所有细节定义清楚后再做,而是经过一次次迭代不断完善,否则所做的产品只会过时。
测试规格说明
在编写任何代码之前,规格说明必须提交给测试小组,以便他们详细检查说明的完整性和明确性。
在开发过程中,用户故事可能会有模糊之处,但验收标准必须明确且完整,测试小组需要的是清晰的验证标准。
自顶向下的设计
自顶向下设计的优点在于它允许从高层次的抽象出发,逐步细化到具体的实现,从而有助于确保系统的完整性和一致性。
然而,这种方法也存在一些缺点。如果在最高层设计阶段出现错误,下层结构必然也会受到影响。此外,在设计过程中需要不断验证下级细节的正确性(以避免考虑不周的情况),并且这种方法在扩展时灵活性不足,可能导致扩展困难。
书中说“我确信在十年内,自顶向下进行设计会是重要的新型形式化软件开发方法”
这句话现在已然过时,如果整个系统使用自顶向下的设计方法,那对于测试来说,除了写测试用例以外什么也做不了,所以现在的自顶向下的设计应该是在小模块下的垂直设计
13.2 系统集成测试
系统调试花费的时间会比预料的更长,需要一种完备化和可计划的方法来降低它的困难程度
使用经过调试的构建单元
使用系统的各个部分进行相互测试,比如尽早地进行前后端的联调
田界智航最后交付时遇到的问题就是因为没有尽早的进行系统测试造成的,因为我们小组中测试人员是在中后期才介入的,这就导致快到交付的时候遇到了各种奇奇怪怪的问题,这也是我感觉田界智航最失败的地方。
文档化的bug
文档化的bug就是指构建单元的缺陷已经被发现,还没有被修复,但已经做好了系统调试的准备。在系统调试期间,测试人员知道这些缺陷的后果从而可以忽略他们
但是因为没有经过系统测试,测试人员只是知道它存在着A问题,但是会不会造成B问题,这就是未知的了,这会对接下来系统测试造成困惑
搭建充分的测试平台
测试平台可能会有相当于测试对象一半的代码量,但这也是很正常的。有时还需要用伪构建,就是指的存根测试,比如一个程序被测程序还没开发完成时,但是可以根据输入给出输出(这里的输出是直接return的,没有实现业务逻辑),这样不会影响接下来的系统测试
控制变更
之前是有专门的人员做版本变更控制工作的,但是现在有了git等工具后,版本控制不再需要专人来做了,而是交给了规则,由开发自己决定在哪个分支上进行修改
一次添加一个构件
这样做的好处显而易见,但是乐观主义和惰性常常诱使我们破坏这个规则。虽然一次性添加很多构件会提高效率,但是这样会造成很多问题,我们必须假设系统中存在着许多错误,并需要计划一个有序的过程把它们都找出来。
每次添加新的构件之后要对系统进行回归测试,这就要求我们必须要有完整的测试用例
十四、祸起萧墙
项目进度经常以一种难以察觉,但是残酷无情的方式慢慢落后
当一个项目延迟了,往往不是重大灾难造成的,因为重大灾难往往与重大的压力、彻底的重组、新技术的出现有关,整个项目组通过可以应付自如的,但是每天落后的进度是难以识别、不容易防范和难以弥补的。比如昨天某个人生病了,今天设备坏了,明天又有很多突发的会议等等
14.1 制定里程碑计划
为了解决这一问题,可以制定一个严格的进度表来控制项目,比如九月初项目开始,十月初开发完毕量地轨迹测量
而这属于估算技术,估算很大程度上依赖于以往的经验,很多时候我们安装一个软件,安装到99%的时候那最后的1%可能比以往任何时候花费时间都要多,这是因为不同电脑的编译注册时间是各不相同的,无法估计的。
然而具体的里程碑是百分之百的事,里程碑有明显边界和没有歧义,如果里程碑定义得非常明确,以致于无法自欺欺人时,很少会有人就里程碑的进展弄虚作假。
书中提到的这三点经验真的让我十分震撼,40多年以前就已经提出了敏捷迭代的观点
- 如果在某项活动开始之前就着手估计,并且每两周进行一次仔细的修订。这样,随着开始时间的临近,无论最后情况会变得如何的糟糕,它都不会有太大的变化
- 活动期间,对时间长短的过高估计,会随着活动的进行持续下降
- 过低的估计在活动中不会有太大的变化,一直到计划的结束日期之前大约三周左右
14.2 “其他的部分反正会落后”
小a:我今天晚一天就晚一天吧,反正别人也会晚
小b:反正小a都晚了一天,我晚一天又怎样,何况跟我有关的其他部分已经落后了
如果每个人都在想的话,那么这个项目就一定会落后了,在软件开发中进取心同样重要,进取提供了缓冲和储备
14.3 毯子之下
当一线经理发现自己的队伍出现了计划偏差时,他肯定不会马上赶到老板那里去汇报这个令人沮丧的消息。团队可以弥补进度偏差,他应该可以相处应对方法或者重新安排进度以解决问题。
但是每个老板都需要两种信息:需要采取行动计划方面的问题,用来进行分析的状态数据,因此需要了解所有开发队伍的情况,但是往往获得真相是很困难的。
项目经理有两种掀开毯子将污垢展现给老板面前的方法
-
减少角色的冲突
这种办法必须要求老板规范自己,不对项目经理可以解决的问题作出反应。当项目经理了解到老板收到状态报告后不会惊慌,或者不会越俎代庖时,他就会逐渐提交真实的结果
-
猛地拉开毯子
拥有能够了解状态真相的评审机制是必要的,可以通过任务看板或者项目协作平台。大型项目可能需要每周对某些部分进行评审,大约一个月进行整体评审。
十五、另外一面
不了解,就无法真正拥有
计算机程序是从人传递到机器的一些信息。为了将人的意图清晰地传到给不会说话的机器,程序采用了严格的语法和严谨的定义。
但是书面的计算机文档是十分必要的,即使是完全开发给自己使用的程序。因为记忆衰退的规律会使作者失去对程序的了解,于是他不得不重拾自己劳动的各个细节。
我之所以写博客写文档也是出于这个原因,我将犯过的错或者对某个知识点的积累写成文档或者做成视频是为了在之后再次遇到时能够回忆起当初的经验不至于重新学习拾起。
“面对那些文档‘’简约”的程度,我们中的大多数人都不免曾经暗骂那些远在其他地方的匿名作者“,哈哈,看到这句话真的很有意思,我想到当初我的同事写的没有注释的代码,想到接手的后辈会以什么样的心情看这份代码时我就很难憋住笑。
15.1 如何做大于为什么做
如果我只是告诉你要写文档,优秀的文档对于项目的维护很重要,但是你依然不会做这个任务。就像是你的boss告诉你投资很赚钱,但是你从没有投资过,你会选择投资吗?但是将其改为你的boss告诉你投资很重要并带着你投资了一次还赚到了钱,那是不是就完全不一样了
所以后面的的重点将放在“如何做”(才能产生一篇优秀的文章)上。
15.2 需要什么样的文档
-
目的
主要功能是什么?开发程序的原因是什么?
-
环境
程序运行在什么样的机器、硬件配置和操作系统上?
-
范围
输入的有效范围是什么?允许显示的合法输出范围是什么?
-
实现功能和使用的算法
精确的阐述他做了什么
-
输入–输出格式
必须是确切和完整的
-
操作指令
包括控制台及输出内容中正常和异常结束的行为
-
选项
用户的功能选项有哪些?如何在选项之间进行挑选
-
运行时间
在指定的配置下,解决特定规模问题所需要的时间
-
精度和校验
期望结果的精度程度(比如保留小数点后几位),如何进行精度的检测?
而且还需要验证程序,除了程序的使用方法,还必须附带一些程序正确运行的证明,即测试用例
用户对一个仅仅发行的软件包信心可能是不够的,一份拷贝的代码和完整的测试用例,以及缺陷跟踪也可能是用户所期望的。
完整的测试用例包括
- 针对遇到的大多数常规数据和程序主要功能进行测试的用例
- 数量相对较少的合法数据测试用例
- 数量相对较少的非法数据测试用例
15.3 自文档化
上述的文档都是将文档和代码分开的,但是我们能够用代码本身和注释做到文档的效果。
也就是将文档注释、变量名、方法名、行注释、缩进等利用起来,用代码实现“自文档”方法。
宏(也就是模版)可以在这一方面起到很大的帮助,比如生成注释文档模版,输入输出可以很方便地帮我们完成,我们仅仅需要提供描述就行
十六、没有银弹
没有任何技术或管理上的进展,能够独立地许诺十年内使生产率、可靠性或简洁性获得数量级上的进步
软件的根本困难不在于技术和所依赖的环境,而是软件抽象的业务才是根本困难。除非这些次要困难(如笨拙的编程语言、硬件的限制等等)能够占有所有工作的9/10,否则就算全部次要困难时间缩减到0,也不会给生产率带来数量级上的提升。
在序中我就提出了软件开发的四个根本困难,作为软件中的人狼,我们是否能找到消灭人狼的银弹,在这一章节中作者通过分析很多未来可能普及的技术,来探讨能否作为消灭人狼的银弹。
当然以40多年后的角度来说,我认为软件的根本性困难还是存在的
16.1 根本困难是否是真的那么困难
软件的特性本身导致了不大可能有任何的发明创新,软件开发中困难的部分是概念上的结构,而不是对概念进行实现。
我接下来再把我序中的四个根本困难拷贝过来
1、复杂度
软件系统的复杂性是其本质特征,而非表象。这与物理学或数学中可以通过模型简化的复杂性不同。在软件工程中,即便是看似相似的功能,其实现细节往往也各不相同,如果存在相同的情况,我们也会将它们合并成供调用的子函数。而且软件实体的扩展也不是相同元素的添加,而必须是不同元素的添加,同时元素的添加往往以非线性递增的方式交互,因此整个系统的复杂度会比非线性增长要多得多。
2、一致性
开发团队需要持续处理各种人为造成的不一致性。这些不一致往往源于不同人员、不同时期对需求的理解差异,以及在确保业务逻辑和技术实现一致性方面的挑战。
3、可变性
不同于建筑或汽车制造业,软件系统的变更成本相对较低,同时软件系统包含了很多功能,而功能是最容易感受到变更压力的部分,这导致用户倾向于不断提出新的需求。一个成功的软件产品往往需要持续演进,以适应用户不断增长的需求。
4、不可见性
软件系统缺乏物理形态,难以像建筑设计图或电路图那样直观地展现其结构。软件系统往往是多个维度的抽象概念的叠加,这种特性限制了我们使用可视化工具来辅助软件设计和开发。假如我们一定要用图形来描述软件结构时、会发现它是很多相互关联、重叠到一起的的图形,软件无法可视化的固定特征,剥夺了一些具有强大功能的概念工具的构造创意。
整本书和这个文档整篇都是在为了提高软件开发效率而从团队、概念、管理、执行、沟通、总结、做减法、变化、工具、测试等方面进行探讨,但最终还是将目光看向了软件的本质,软件本质上是价值的体现,而价值或者说是业务才是软件本质的困难
高级语言
使用高级语言和框架让编程人员更加轻松,提高开发效率,但也只是避免了低级的元素,而无法消除程序固有的复杂程度
分时
分时解决了当时批处理操作系统时要等待的过程,但是将系统响应时间压缩到无限接近于0,那么分时带来的好处就接近于无了,就比如从500ms优化到100ms,意义已经不大了
统一编程环境
统一编程环境可以解决配置不同环境的困难,但也没有解决本质的困难
16.2 银弹的希望
-
高级语言
-
面向对象编程
-
人工智能
- 2024年人工智能的发展十分的迅速并且恐怖,我们团队每个人都在使用cursor辅助编程,当我在写前端界面的时候,我只要描述出来我想要的效果,ai就能实现出来类似的效果。但是现在的大模型我认为还只能停留在自然界已经存在的知识体系里面,而无法做到创新,ai只能说和曾经的高级语言或者开发工具一样,也只是提高了效率,现在的大模型算是解决根本困难的银弹吗,我认为不是,比如我使用cursor,可以通过自然语言描述所需要的功能来编写代码,但是要写出高质量的和实现需求的代码,需要人工干预,比如我需要很了解这一部分业务的代码应该怎么编写,从而将具体实现过程转为提示词交给ai,ai才能够精确的写出符合规范的代码,在这一过程中我无法保证ai写的代码是正确的,依然没有解决软件的根本性困难,
-
专家系统
-
“自动”编程
-
图形化编程
上述这些希望能解决根本性困难吗,经过时间的验证,这些并不能担当银弹,但是这不妨碍软件行业的进步,我们考虑到软件上必要困难的活动,我们可以通过这些方式来减少根本困难带来的影响
购买和自行开发
构建软件最可能得彻底解决方案是不开发任何软件,软件成本一直是开发的成本,而不是复制的成本,我们可以在开发中使用已经开发好的软件包
需求精炼和快速原型
软件开发人员为客户所承担的最重要的职能是不断重复地抽取和细化产品的需求,事实上客户不知道自己需要什么。在计划任何软件活动时,要让客户和设计人员之间进行多次广泛的交流沟通,并将其作为系统定义的一部分
增量开发
增长,而非搭建系统。软件开发类似于其他的搭建过程,首先系统能够运行,即使未完成任何有用的功能,接着系统一点一点被充实,子系统轮流被开发。
十七、再论《没有银弹》
软件的根本困难是业务上的困难,不是技术上的困难
尽管现在有敏捷开发,快速原型等方法,但是随着业务的改变和复杂,开发效率是没有指数级的提升的,只是在相同业务中得到了效率提高(技术的进步和经验的积累)
经常会听到有人说,我们使用了什么什么技术,什么什么过程,让生产率提高了十倍。但我相信在小领域中提升十倍是可行的,但是在整个软件工程中还能提高十倍吗。
创造性工作是很难有银弹的,能够通过技术提高效率的工作只是简单的实现性工作
创造性工作包括
- 概念性结构形式的规格化
- 使用现实的介质来实现
- 在实际的使用中,与用户交互
随着技术的发展,编写编译不过的代码是很困难的,但是编写编译没问题的代码结果不对的确实经常发生的。而这也和软件的根本性困难时一样的,其困难体现在业务上,而不是技术实现上。
我们现在最缺的是有idea的人,而不是只会写代码的人。
重用和交互的构件是解决软件的根本困难吗,我认为不是,对代码和构件的重用还是在利用之前的东西,但是如果一个新的复杂的业务来了之后,如果不能再使用之前的经验技术的时候,依然无法提高生产率。
根本困难依然是软件的概念复杂性,无论是任何时间任何方法设计和实现软件的功能,它都一直存在。
直到现在为止
- 层次化,通过分层的模块或者对象
- 增量化,从而系统可以持续地运行
这两个方法都很有效果(微服务+小迭代)
没有银弹总体上看来是悲观的,就像是所有物体运动的速度都无法超过光速一样,十分令人悲伤