ISBN: 978-7-121-41997-3
作者:【美】Alan M. Davis
译者:叶王、马学翔、吴斌、王冰清
审定:章淼
页数:344页
阅读时间:2023-09-24
推荐指数:★★★★★
这本书可以说是集开发之大成者了,
如果你是开发或者管理人员没有看过这本书我觉得你还没到火候。
这些基本上都是上世纪七十、八十、九十年代总结出来的原则,
这些都是经得起时间考验的,虽然有些因为时代的原因都过时了,
但是还有很多宝贵的经验留存了下来,十分建议阅读回味。
这里是软件工程生命周期中的需求、设计、编码、测试、维护的全面覆盖。
软件质量的三要素:人、过程、工具。现在工具链成为了软件工程的管理核心了。
原则1:质量第一
质量必须量化、建立落地实施机制。
原则2:质量在每个人眼中都不同
确定优先级,并清晰的传递给每个相关方。
原则3:开发效率和质量密不可分
试图提高开发效率时,bug密度就会增加。
原则4:高质量软件是可以实现的
让客户参与,做原型设计,并保持简单。
原则5:不要试图通过改进软件实现高质量
质量无法从软件的改进获得。
原则6:低可靠性比低效率更糟糕
低可靠性问题不仅难以发现,而且难以修复。
原则7:尽早把产品交给用户
使用原型法
原则8:与客户、用户沟通
解决真正需求的唯一方法,就是去和真正有需求的人沟通。
原则9:促使开发者与客户的目标一致
原则10:做好抛弃的准备
原则11:开发正确的原型
一次性原型和演进式
原则12:构建合适功能的原型
原则13:要快速地开发一次性原型
原则14:渐进地扩展系统
是降低软件开发风险的最有效方法之一。
原则15:看到越多,需要越多
一旦用户看到产品,他们就会想要更多的东西。
原则16:开发过程中的变化是不可避免的
原则17:只要可能,购买而非开发
原则18:让软件只需简短的用户手册
衡量软件系统质量的一种方法是查看其用户手册内容的多少。
原则19:每个复杂问题都有一个解决方案
这是错误的。
原则20:记录你的假设
即使很荒谬也要记录
原则21:不同的阶段,使用不同的语言
原则22:技术优先于工具
自动化之前先手工验证。
原则23:使用工具,但要务实
原则24:把工具交给优秀的工程师
原则25:CASE工具是昂贵的
现在大部分工具都免费了
原则26:“知道何时”和“知道如何”同样重要
一个优秀的工程师需要了解很多不同种类的技术,知道每种技术适合那部分。
原则27:实现目标就停止
需要对整个软件过程都熟悉
原则28:了解形式化方法
先用自然语言描述,然后再用形式化方法描述。
自然语言:打电话给小吴。
形式化语言:开机、点击打电话、输入手机号、点击拨打。
原则29:和组织荣辱与共
产品中的缺陷是公司的耻辱;软件工程师引起的公司耻辱是工程师的耻辱。
当任何人发现你在产品中犯的错误时,应该心存感激,而不是试图辩解。
帮助其他工程师,避免同样的错误,对后续的错误修正,也可以不那么抵触。
原则30:跟风要小心
原则31:不要忽视技术
软件工程技术日新月异
原则32:使用文档标准
原则33:文档要有术语表
原则34:软件文档都要有索引
原则35:对相同的概念用相同的名字
原则36:研究再转化,不可行
研究者更愿意在越来越多的无实际意义的问题上演示他们的想法。
原则37:要承担责任
不要有任何借口。如果你是一个系统的开发者,把它做好是你的责任。要承担这个责任。要么做好,要么就压根不做。
原则38:低质量的需求分析,导致低质量的成本估算
原则39:先确定问题,再写需求
原则40:立即确定需求
原则41:立即修复需求规格说明中的错误
要在需求分析阶段修复错误
原则42:原型可降低选择用户界面的风险
可以给用户提供一个真实系统的印象
原则43:记录需求为什么被引入
原则44:确定子集
原则45:评审需求
原则46:避免在需求分析时进行系统设计
需求阶段的目标是明确系统的外部行为。
原则47:使用正确的方法
没有任何一种需求分析方法适合所有软件。
原则48:使用多角度的需求视图
原则49:合理地组织需求
原则50:给需求排列优先级
原则51:书写要简洁
原则52:给每个需求单独编号
原则53:减少需求中的歧义
自然语言存在固有的歧义问题。
原则54:对自然语言辅助增强,而非替换
原则55:在更形式化的模型前,先写自然语言
原则56:保持需求规格说明的可读性
用户、客户、市场营销人员、需求作者、设计师、测试人员、管理人员等都需要清楚需求文档。
原则57:明确规定可靠性
原则58:应明确环境超出预期时的系统行为
原则59:自毁的待定项
到何时为止,由谁处理这个待定项。
原则60:将需求保存到数据库
需求是复杂和非常不稳定的。
原则61:从需求到设计的转换并不容易
设计的最终产出是设计规格说明。
设计的第一步,是综合形成一个理想的软件架构。
从外部视角到内部最优设计的转换,从根本上说是一个难题。
原则62:将设计追溯至需求
当选择软件架构时,重要的是所有需求都能被覆盖。
原则63:评估备选方案
详细列出多种方法,在这些方法之间权衡分析,并最终采用一种。
原则64:没有文档的设计不是设计
我已经完成了你新家的设计,剩下的工作就是把它画出来。
我已经完成了这不小说,剩下的工作就是把它写下来。
原则65:封装
信息隐藏,是一个简单且经过验证的概念,它使软件更容易测试和维护。
原则66:不要重复造轮子
复用,而不是工程。
原则67:保持简单
构建软件设计有两种方法。
一种方法是使它简单到明显没有缺陷。
另一种方法是使它复杂到没有明显的缺陷。
KISS原则。
原则68:避免大量的特殊案例
如果你发现有太多的特殊案例,那么你可能设计了一个不合适的算法。
原则69:缩小智力距离
不同的人在审视同一个现实世界时,往往会感知到不同的结构。
原则70:将设计置于知识控制之下
如果设计是以能使其创建者和维护者完全理解的方式创建和记录的,那么这个设计就是在知识可控范围内的。
原则71:保持概念一致
概念一致是高质量设计的一个特点。
当设计完成后,设计应该看起来是一个人做的。
原则72:概念性错误比语法错误更严重
不管你有多优秀,都会犯概念性错误。
需求阶段:这是客户想要的吗?
设计阶段:这个架构在压力下可以正常工作吗?这个算法真的适用于各种场景吗?
编码阶段:这段代码的执行和我想的一样吗?是否实现了这个算法?
测试阶段:执行这段测试让我确信什么?
原则73:使用耦合和内聚
高内聚低耦合
原则74:为变化而设计
模块化、可移植性、可塑性、保证最小智力距离、在智力可控范围内。
原则75:为维护而设计
对于非软件产品,设计后的最大成本风险是制造。
对于软件产品,设计后的最大成本风险是维护。
原则76:为防备出现错误而设计
不引入错误、尽可能预想不可能的情况并制定恢复策略。
原则77:在软件中植入通用性
一个软件组件的通用性体现在,它在不同的场景下不做任何修改就能执行预期功能。
原则78:在软件中植入灵活性
一个软件组件的灵活性体现在,他很容易被修改,以在不同的场景下执行其功能。
原则79:使用高效的算法
了解算法复杂度理论是成为一名优秀设计者的必要前提。
原则80:模块规格说明只提供用户需要的所有信息
设计过程中的一个关键部分,是对系统中每个软件组件的精确定义。
原则81:设计是多维的
打包方案、依赖层次、调用关系、进程组织
原则82:优秀的设计出自优秀的设计师
优秀的设计是:简洁、简单、优雅、快速、可维护、易于实现
原则83:理解你的应用场景
无论需求文档写得多好,架构和算法的最优选择,都应主要基于对应用场景特质的理解。
原则84:无须太多投资,即可实现复用
复用软件组件最有效的方法是:从一个包含精心制作和挑选的组件的代码库开始,这些组件是专门为重用而定制的。
原则85:“错进错出”是不正确的
如果用户提供了非法的输入数据,程序应该返回一个好理解的提示,理解为什么这个输入是非法的。
原则86:软件可靠性可以通过冗余来实现
并行方式、冷备方式。软件的超高可靠性是非常昂贵的。
原则87:避免使用特殊技巧
程序员都非常聪明,他们想展示这种聪明。
底线:避免编写使用特殊技巧的代码,以向世界展示你有多聪明。
原则88:避免使用全局变量
全局意味着,任何人都可能错误地修改它的值。
原则89:编写可自上而下阅读的程序
原则90:避免副作用
副作用是软件中许多细微错误的来源
原则91:使用有意义的命名
优秀的程序员应该只花很少比例的时间敲代码(10~15%的时间),大部分时间应该花在思考上。
原则92:程序首先是写给人看的
现在最有价值的资源是人力:开发软件的人力、维护软件的人力和提高软件能力的人力。
原则93:使用最优的数据结构
如果你选择了正确的数据结构,算法将变得易于编写、阅读以及维护。
原则94:先确保正确,再提升性能
提供正常运行程序的性能,比“让高性能程序正常运行”容易很多。
原则95:在写完代码之前写注释
在写代码的同时写注释,这会让你更容易调试软件。
原则96:先写文档后写代码
一些读者对这个原则或许会感到奇怪,但当实践一段时间之后,你会认为这个原则是理所当然。
原则97:手动运行每个组件
手动执行一些简单的测试用例
原则98:代码审查
Code Review
原则99:你可以使用非结构化的语言
原则100:结构化的代码未必是好的代码
一个人可以写出异常晦涩的程序,虽然它是结构化的。
对高质量的程序,结构几乎是必要条件,但远不是充分条件。
原则101:不要嵌套太深
嵌套超过三层就会严重降低可理解性。
原则102:使用合适的语言
特定项目或产品的目标通常会指定合适的语言。
原则103:编程语言不是借口
如果你是一个好的程序员,对任何一种编程语言来说你都应该是一个好程序员。
原则104:编程语言的知识没那么重要
不管使用哪种语言,优秀的程序员都是优秀的。
不管使用哪种语言,糟糕的程序员仍然是糟糕的。
一个真正优秀的程序员应该可以很容易地学会一种新语言。
这是因为一个真正优秀的程序员很好地理解和赞赏高质量编程的概念,
而不只是了解某些编程语言的语法和语义特性。
原则105:格式化你的代码
代码缩进、编程规范
原则106:不要太早编码
编写软件和盖房子类似。这两者都需要做很多准备工作。
在设立基线前,要确认需求和设计是正确且合适的,在对最终产品编码前更要确认。
原则107:依据需求跟踪测试
理解哪些测试可以验证哪些需求是很重要的。
原则108:在测试之前早做测试计划
必须与产品开发同时进行,以便同步完成测试计划和初始开发活动。
原则109:不要测试自己开发的软件
软件开发人员永远不应成为自己的主要测试者。
1.在开始集成测试之前,检查单元测试是否足够。
2.所有集成测试
3.所有软件系统测试
原则110:不要为自己的软件做测试计划
你不仅不应该测试自己的软件,而且也不应该负责为软件生成测试数据、测试方案或测试计划。
原则111:测试只能揭示缺陷的存在
无论测试得多么彻底和深入,测试只能揭示程序中存在缺陷,而并不能确保程序没有缺陷。
原则112:虽然大量的错误可证明软件毫无价值,但是零错误并不能说明软件的价值
本原则的第一部分显然是正确的,第二部分则发人深省。
原则113:成功的测试应发现错误
假设你感觉生病了,医生把你的血样送到实验室。几天后,医生打电话告诉你,“好消息!你的血液正常”。这不是什么好消息。你病了,否则不会去看医生的。
原则114:半数的错误出现在15%的模块中
保守估算,在大型系统中,大约一半的软件错误出现在15%的模块中,80%的软件错误出现在50%的模块中。
原则115:使用黑盒测试和白盒测试
黑盒测试使用组件外部行为的定义作为唯一输入。白盒测试使用代码本身生成测试用例。
原则116:测试用例应包含期望的结果
一个测试用例的文档必须包含期望的正确结果的详细描述。
原则117:测试不正确的输入
为尽可能多的可接受的输入情况生成测试用例,是自然和常见的做法。
原则118:压力测试必不可少
在面对极限的负载时,他是否可以保持正常运行。
原则119:大爆炸理论不适用
在一个项目接近交付期限,而软件还没有准备好的时候,开发者往往充满绝望的情绪。
原则120:使用McCabe复杂度指标
圈复杂度。1976年提出来的。
原则121:使用有效的测试完成度标准
1.每周发现新错误的比率
2.暗中在软件中埋下已知的bug,然后bug到目前为止被发现的百分比。
原则122:达成有效的测试覆盖
1.语句覆盖率
2.分支覆盖率
3.路径覆盖率
原则123:不要在单元测试之前集成
原则124:测量你的软件
测试软件的时候,往往很难确定为何软件会失败。
原则125:分析错误的原因
如果一类错误的原因我们已经全面地分析和研究过了,那么就不那么容易再犯同类的错误了。
原则126:对“错”不对人
当你或他人在你的代码中发现错误时,公开坦诚地讨论它。与其责骂自己,不如将它当作自己和他人的学习经历。
原则127:好的管理比好的技术更重要
好的管理能够激励人们做到最好,糟糕的管理会打击人们的积极性。
原则128:使用恰当的方法
技术问题需要使用技术的方法。
管理问题需要使用管理的方法。
政治问题需要使用政治的方法。
原则129:不要相信你读到的一切
一般来讲,相信特定想法的人,会搜索支持这个想法的数据,而抛弃不支持的数据。
原则130:理解客户的优先级
如果客户能按时获得必需的10%的系统功能,那么他们可以忍受其余90%的功能延迟交付。
原则131:人是成功的关键
具备合适经验、才能、培训的能人,是在预算内按时完成满足用户需求的软件的关键。
原则132:几个好手要强过很多生手
你应该总是雇佣最好的工程师。
原则133:倾听你的员工
你必须信任那些为你工作的人。
原则134:信任你的员工
如果你不太信任他们,那么他们会给你不要去信任他们的理由。
原则135:期望优秀
如果你对员工有更高的期待,他们将表现得更好。
你期望的越多,获得的成就就越大。
原则136:沟通技巧是必要的
如果他/她不能沟通、说服、倾听和妥协,最好的设计师也可能会变成差劲的资产。
原则137:端茶送水
给他们惊喜!在午夜给他们带比萨。
原则138:人们的动机是不同的
能够打动员工的东西和打动我的东西是一样的。
原则139:让办公室保持安静
最有效率的员工和公司都拥有安静和私密的办公区。
原则140:人和时间是不可互换的
只用“人月”来衡量一个项目几乎没有任何意义。
原则141:软件工程师之间存在巨大的差异
研法效率(每人每月完成的代码行数)相差25倍之多,
质量(每千行代码中发现的bug量)相差10倍之多。
原则142:你可以优化任何你想要优化的
任何项目都可以优化任何要优化的“质量”因素。
在优化任何一个因素时,通常会弱化其他“质量”因素。
原则143:隐蔽地收集数据
数据收集在以下方面极为重要:
帮助进行未来的成本预测,评估项目或组织的当前状态,评估管理、过程或技术变更的影响等。
原则144:每行代码的成本是没用的
我们可以选择以多种语言中的任何一种来实现程序。
原则145:衡量开发效率没有完美的方法
将代码行数评估转换成功能点,人月等。
原则146:剪裁成本估算方法
每种方法都基于从大量已完成项目中收集的数据。
原则147:不要设定不切实际的截止时间
一个不切实际的截止日期将无法保证完成任务。
原则148:避免不可能
原则149:评估之前先要了解
在你可以评估任何事情之前,你必须先了解一些东西。
即使每个人都以同一种方式衡量某事,这种方式也并非一定适合你。
原则150:收集生产力数据
如果你尚未从过去的项目中收集详细的数据,那么今天你就无法剪裁你的成本估算模型。
原则151:不要忘记团队效率
优化所有个体的生产力并不一定会产出最佳的团队生产力。
原则152:LOC/PM与语言无关
语言的选择会极大地影响可维护性。
原则153:相信排期
一旦建立了可行的排期并分配了适当的资源,所有各方都必须相信排期。
原则154:精确的成本估算并不是万无一失的
你,假设,概率
原则155:定期重新评估排期
排期通常在项目启动时设定,其中包括中间期限和产品交付期限。
原则156:轻微的低估不总是坏事
对任何一个特定的项目,被轻微低估比被轻微高估,会花费更少的资源。
原则157:分配合适的资源
不管人员的质量如何,工具、语言或流程的可用性如何,认为强加的进度和不恰当的预算将会毁了一个项目。
原则158:制定详细的项目计划
每个软件项目都需要一个计划:
PERT表、甘特图、里程碑、标准、分配。
“如果你不知道要去哪里,那你也就无法到达那里!”
原则159:及时更新你的计划
有一个过时的计划比完全没有计划更糟糕。
所以无论任何时候情况发生变化,都要更新你的计划。
原则160:避免驻波
重新安排时间和重新计划需要采取行动,而不仅仅是承诺很快就能解决问题。
原则161:知晓十大风险
- 人员短缺
- 不切实际的排期
- 不理解需求
- 开发糟糕的用户界面
- 当用户并不需要时尝试镀金
- 没有控制需求变更
- 缺乏可重用的或者接口化的组件
- 外部执行任务部满足要求
- 糟糕的响应时间
10.试图超越当前计算机技术的能力
原则162:预先了解风险
对于每个风险,要量化其真正发生时会带来的破坏程度,并量化这种损失发生的可能性。
原则163:使用适当的流程模型
原则164:方法无法挽救你
作为一名管理者,要提防那些声称基于新的方法将大大提高质量或生产力的虚假的预言家。
原则165:没有奇迹般提升效率的秘密
软件开发行业充满了“推销员”,他们鼓吹通过使用这种工具或那种技术能够降低开发成本。
原则166:了解进度的含义
了解衡量进度的标准
原则167:按差异管理
原则168:不要过度使用你的硬件
当内存或CPU使用率接近90%时,软件开发成本将翻倍!
当接近95%时,成本将会增加两倍!
原则169:对硬件的演化要乐观
摩尔定律
原则170:对软件的进化要悲观
原则171:认为灾难是不可能的想法往往导致灾难
你决不能沾沾自喜地以为一切都在控制之中,并且会一直保持这样。
原则172:做项目总结
记录、分析所有不符合预期的事情并从中学习。
原则173:产品保证并不是奢侈品
产品保证包含软件配置管理,验证和确认。
原则174:尽早建立软件配置管理过程
- 怎么去报告一个软件问题
- 怎么去提出一个新的需求
- 所有利益相关方对于建议的改动都能知晓,且他们的意见都被考虑了
- 有一块看板用于展示变更请求的优先级和排期
- 所有基线化的中间产品或最终产品都在掌控之中
原则175:使软件配置管理适应软件过程
软件配置管理(SCM)并不是一套对所有项目一律使用的标准实践。
原则176:组织SCM独立于项目管理
SCM只有在独立于项目管理的情况下才能做好本职工作。
原则177:轮换人员到产品保证组织
每个优秀的工程师每隔两到三年,要投入六个月的时间到产品保证上。
原则178:给所有中间产品一个名称和版本
原则179:控制基准
原则180:保存所有内容
明智修补的首要原则是保存所有的零件
原则181:跟踪每一个变更
- 变更未解决预期要解决的问题
- 变更解决了问题,但导致了其他问题
- 在将来的某天变更被注意到时,没有人能弄清楚更改的原因
原则182:不要绕过变更控制
变更控制,每个人都会得到收益
原则183:对变更请求进行分级和排期
成立一个委员会,定期评审所有变更请求。
原则184:在大型开发项目中使用确认和验证(V&V)
原则185:软件会持续变化
原则186:软件的熵增加
任何经历持续变化的软件系统都会变得越来越复杂,并且变得越来越杂乱无章。
原则187:如果没有坏,就不要修理它
软件被认为是可塑的、易于修改的。不要误以为软件中的“失灵”很容易发现或修复。
在检查时,你觉得自己发现了另外一个错误。不要试图“修复”它。
很有可能你会引入而不是修复一个错误。
原则188:解决问题,而不是症状
当软件出错时,你的责任是彻底理解错误产生的原因,而不只是草草分析一下,并对你认为的原因进行一个快速的修复。
原则189:先变更需求
如果各方都同意对软件进行增强,那么第一件事就是变更软件的需求规格说明,并获得批准。
原则190:发布之前的错误也会在发布之后出现
不要花钱填坑。
原则191:一个程序越老,维护起来越困难
原则192:语言影响可维护性
开发所使用的编程语言,会极大地影响维护期间的开发效率。
原则193:有时重新开始会更好
原则194:首先翻新最差的
完全重新设计和重新编码“最差”的组件。
原则195:维护阶段比开发阶段产生的错误更多
维护期间有20%到50%的改动会引入更多的错误。
原则196:每次变更后都要进行回归测试
对所有之前测试过的功能进行再次测试。
原则197:“变更很容易”的想法,会是变更更容易出错
因为软件是很复杂的,要正确运行必须处于“完美”状态,所以必须认真考虑每一个改动可能带来的影响。
原则198:对非结构化代码进行结构化改造,并不一定会使它更好
原则199:在优化前先进行性能分析
请记住80%的CPU周期将被20%的代码消耗
原则200:保持熟悉
熟悉守恒定律:保持产品发布版本之间的改动量相对稳定。
原则201:系统的存在促进了演变
无论你认为自己多完美地实现了需求,都必须魏部署之后必要的变更做好计划。