外观
07.没有银弹-软件工程中的根本和次要问题、20 年后的人月神话
约 4211 字大约 14 分钟
人月神话项目管理算法devops
2022-06-05
第16章 没有银弹-软件工程中的根本和次要问题
没有任何技术或管理上的进展,能够独立地许诺十年内使生产率、可靠性或简洁性获得数量级上的进步。
Part 1 摘要
所有软件活动包括根本任务—打造由抽象软件实体构成的复杂概念结构,次要任务—使用编程语言表达这些抽象实体,在空间和时间限制内将它们映射成机器语言。
现在是已关注软件任务中的必要活动的时候了,也就是那些和构造异常复杂的抽象概念结构有关的部分。
建议:
- 仔细地进行市场调研,避免开发已上市的产品。
- 在获取和制订软件需求时,将快速原型开发作为迭代计划的一部分。
- 有机地更新软件,随着系统的运行、使用和测试,逐渐添加越来越多的功能。
- 不断挑选和培养杰出的概念设计人员。
Part 2 介绍
本章中,我们试图通过分析软件问题的本质和很多候选银弹的特征,来探索其原因。
Part 3 是否一定那么困难呢?——根本困难
① 提高软件的生产率、可靠性和简洁程度。我们甚至不能期望每两年有一倍的增长。
② 根本的—软件特性中固有的困难,次要的——出现在目前生产上的,但并非那些与生俱来的困难。
③ 一个相互牵制关联的概念结构,是软件实体必不可少的部分,它包括:数据集合、数据条目之间的关系、算法、功能调用等等。
④ 软件开发中困难的部分是规格化、设计和测试这些概念上的结构,而不是对概念进行表达和对实现逼真程度进行验证。
⑤ 现代软件系统中这些无法规避的内在特性:复杂度、一致性、可变性和不可见性。
复杂度:
- 软件实体可能比任何由人类创造的其他实体要复杂,因为没有任何两个软件部分是相同的。
- 计算机拥有大量的状态,这使得构思、描述和测试都非常困难。软件系统的状态又比计算机系统状态多若干个数量级。
- 软件实体的扩展也不仅仅是相同元素重复添加, 而必须是不同元素实体的添加。
- 软件的复杂度是必要属性,不是次要因素。
- 复杂度不仅仅导致技术上的困难,还引发了很多管理上的问题。
一致性:
- 某些情况下,因为是开发最新的软件,所以它必须遵循各种接口。
- 很多复杂性来自保持与其他接口的一致,对软件的任何再设计,都无法简化这些复杂特性。
可变性:
- 软件实体经常会遭受到持续的变更压力。
- 软件可以很容易地进行修改——它是纯粹思维活动的产物, 可以无限扩展。
- 所有成功的软件都会发生变更。
- 功能扩展的压力主要来自那些喜欢基本功能,又对软件提出了很多新用法的用户们。
不可见性:
- 软件是不可见的和无法可视化的。
- 软件的客观存在不具有空间的形体特征。
- 这些图形可能描绘控制流程、数据流、依赖关系、时间序列、名字空间的相互关系等等。
Part 4 以往解决次要困难的一些突破
①高级语言:
- 勿庸置疑,软件生产率、可靠性和简洁性上最有力的突破是使用高级语言编程。
- 高级语言取得了一些进展:首先,它减轻了一些次要的软件复杂度。抽象程序包含了很多概念上的要素:操作、数据类型、流程和相互通讯,而具体的机器语言程序则关心位、寄存器、条件、分支、通道、磁盘等等。
- 高级语言在某种程度上增加而不是减少了脑力劳动上的负担。
②分时:
- 大多数观察者相信分时提高了程序员的生产率和产品的质量,尽管它带来的进步不如高级语言。
- 较长的周转时间和机器语言的复杂度一样,是软件开发过程的次要困难,而不是本质困难。分时所起作用也非常有限。主要效果是缩短了系统的响应时间。
③统一编程环境:
- 主要通过提供集成库、统一文件格式、管道和过滤器,解决了共同使用程序的次要困难。
Part 5 银弹的希望
Ada 和其他高级编程语言。
面向对象编程。
人工智能。
专家系统。
“自动”编程。
图形化编程。
程序验证。
环境和工具。
工作站。
Part 6 针对概念上根本问题的颇具前途的方法
①购买和自行开发。
- 构建软件最可能的彻底解决方案是不开发任何软件。
②需求精炼和快速原型。
- 软件开发人员为客户所承担的最重要的职能是不断重复地抽取和细化产品的需求。
- 在计划任何软件活动时,要让客户和设计人员之间进行多次广泛的交流沟通,并将其作为系统定义的一部分。
- 原型的目的是明确实际的概念结构,从而客户可以测试一致性和可用性。
③增量开发——增长,而非搭建系统。
- 首先系统应该能够运行,即使未完成任何有用功能,只能正确调用一系列伪子系统。接着,系统一点一点被充实,子系统轮流被开发,或者是在更低的层次调用程序、模块、子系统的占位符(伪程序)等。
- 要求自顶向下设计,因为它本身是一种自顶向下增长的软件。增量化开发使逆向跟踪很方便,并非常容易进行原型开发。每一项新增功能,以及针对更加复杂数据或情况的新模块,从已经规划的系统中有机地增长。
④卓越的设计人员。
现在的技术转移和开发技能的传授,最重要工作是寻求培养卓越设计人员的途径
卓越的管理人员和设计人员都是非常缺乏的。
如何培养杰出的设计人员?
尽可能早地、有系统地识别顶级的设计人员。最好的通常不是那些最有经验的人员。
为设计人员指派一位职业导师,负责他们技术方面的成长,仔细地为他们规划职业生涯。
为每个方面制订和维护一份职业计划,包括与设计大师的、经过仔细挑选的学习过程、正式的高级教育和以及短期的课程——所有这些都穿插在设计和技术领导能力的培养安排中。
为成长中的设计人员提供相互交流和学习的机会。
第17章 没有银弹-软件工程中的根本和次要问题
第18章 20 年后的人月神话
Part 1 核心观点:概念完整性和结构师
① 概念完整性
一个整洁、优雅的编程产品必须向它的每个用户提供一个条理分明的概念模型,这个模型描述了应用、实现应用的方法以及用来指明操作和各种参数的用户界面使用策略,用户所感受到的产品概念完整性是易用性中最重要的因素。
② 结构师
负责产品所有方面的概念完整性,这些是用户能实际感受到的。结构师开发用于向用户解释使用的产品概念模型,概念模型包括所有功能的详细说明以及调用和控制的方法。结构师是这些模型的所有者,同时也是用户的代理。在不可避免地对功能、性能、规模、成本和进度进行平衡时,卓有成效地体现用户的利益。
③ 将体系结构和设计实现、物理实现相分离
为了使结构师的关键任务更加可行,有必要将用户所感知的产品定义—体系结构,与它的实现相分离。
④ 体系结构的递归
个人无法完成所有的体系结构工作。有必要由一位主结构师把系统分解成子系统,系统边界应该划分在使子系统间接口最小化和最容易严格定义的地方。
⑤ 今天,我比以往更加确信
概念完整性是产品质量的核心。
Part 2 开发第二个系统所引起的后果:盲目的功能和频率猜测
① 为大型用户群设计
a.源厂商支持性软件的系统结构师必须不断地为大型的不确定用户群,而不是为某个公司的单一、可定义的应用进行设计。
b.设计通用工具比设计专用工具更加困难,这是因为必须为不同用户的各种需要分配权重。
② 盲目的功能
a.以性能甚至是可用性的代价,过多地向产品添加边界实用功能。
③ 定义用户群
用户群越大和越不确定,就越有必要明确地定义用户群,以获得概念完整性。
他们是谁
他们需要(need)什么
他们认为自己需要(need)什么
他们想要(want)的是什么
④ 频率
a.对于软件产品,任何用户群属性实际上都是一种概率分布,每个属性具有若干可能的值,每个值有自己的发生频率。
b.经过很多年,确信:为了得到完整、明确和共有的用户群描述,结构师应该猜测,或者假设完整的一系列属性和频率值。
c.这种不是很可靠的过程有很多好处:
首先,仔细猜测频率的过程会使结构师非常细致地考虑对象用户群。
其次,把它们写下来一般会引发讨论,这能起到解释的作用,以及澄清不同设计人员对用户图像认识上的差异。
另外,明确地列举频率能帮助大家认识到哪些决策依赖于哪些用户群属性。这种非正式的敏感性分析也是颇有价值的。当某些非常重要的决策需要取决于一些特殊的猜测时,很值得为那些数值花费精力来取得更好的估计。
d.清晰和错误都比模糊不清好得多。
Part 3 没有构建舍弃原型——瀑布模型是错误的!
① 瀑布模型把系统测试,以及潜在地把用户测试放在构件过程的末尾。因此,只有在投入了全部开发投资之后,才能发现无法接受的性能问题、笨拙功能以及察觉用户的错误或不当企图。
② 假设整个系统一次性地被构建,在所有的设计、大部分编码、部分单元测试完成之后,才为闭环的系统测试合并各个部分。
③ 重大缺陷:不存在逆向移动。
Part 4 增量开发模型更佳——渐进地精化
① 构建闭环的框架系统
在每个阶段,都拥有一个可运行的系统。 每个阶段都会有一个经过调试和测试的系统。
② Parnas 产品族

③ 增量式开发和快速原型
增量开发过程能使真正的用户较早地参与测试。
Part 5 关于信息隐藏, Parnas 是正确的,我是错误的
① 编程是个开放性的公共过程。把所有工作都暴露在每个人的凝视之下,能够帮助质量控制,这既源于其他人优秀工作的压力,也由于同伴能直接发现缺陷和 bug。
② 代码模块应该采用定义良好的接口来封装,这些模块的内部结构应该是程序员的私有财产,外部是不可见的。编程人员被屏蔽而不是暴露在他人模块内部结构面前。这种情况下,工作效率最高。
Part 6 放弃权力的力量
① 创造力来自于个人,而不是组织架构或者开发过程,那么项目管理面对的中心问题是如何设计架构和流程,来提高而不是压制主动性和创造力。
② 将权力向下委派。改进的质量、提高的生产率、高涨的士气。
Part 7 全新的软件产业——塑料薄膜包装的成品软件
- 计算机提供商:提供操作系统、编译器和一些实用程序 应用程序用户:如公共事业、银行、保险、政府机构等,为自己使用的软件开发应用程序包。
- 定制程序开发者:为用户承包开发私用软件包,需求、标准和行销步骤都是与众不同的。
- 商业包开发者:那个时候是为专业市场开发大型应用,如统计分析和 CAD 系统等。
Part 8 买来开发——使用塑料包装的成品软件包作为构件
识别出四个层次的软件用成品户:
- 直接使用用户。他们以简便直接的方式来操作,对设计者提供的功能和接口感到满意。
- 元程序员。在单个应用程序的基础上,使用已提供的接口来开发模板或者函数, 主要为最终用户节省工作量。
- 外部功能作者,向应用程序中添加自行编制的功能。这些功能本质上是新应用语言原语,调用通用语言编写的独立模块。这往往需要命令中断、回调或者重载函数技术,向原接口添加新功能。
- 元程序员,使用一个和多个特殊的应用程序,作为更大型系统的构件。他们是需求并没有得到满足的用户群。同时,这也是能在构建新应用程序方面获得较大收获的用法。
Part 9 软件工程的状态和未来
软件工程的一些特殊问题:
- 如何把一系列程序设计和构建成系统
- 如何把程序或者系统设计成健壮的、经过测试的、文档化的、可支持的产品
- 如何维持对大量的复杂性的控制
软件工程的焦油坑在将来很长一段时间内会继续地使人们举步维艰,无法自拔。软件系统可能是人类创造中最错综复杂的事物, 只能期待人们在力所能及的或者刚刚超越力所能及的范围内进行探索和尝试。这个复杂的行业需要:进行持续的发展;学习使用更大的要素来开发;新工具的最佳使用;经论证的管理方法的最佳应用;良好判断的自由发挥;以及能够使我们认识到自己不足和容易犯错的——上帝所赐予的谦卑。
