开篇
在未来的十年内,无论是技术还是管理方法上,都看不出任何突破性的进步,能够保证在十年内大幅度的提高软件的生产率、可靠性和简洁性。
软件工作的根本任务:打造构成抽象软件实体的复杂概念结构
次要任务:使用编程语言表达这些抽象实体,在空间和时间限制下将它们映射成机器语言
- 看似简单明了的东西,却有可能变成一个落后进度、超出预算、存在大量缺陷的怪物。因此,人们一直在寻求一枚银弹。
- 十年来,这个问题一直没有突破,并且认为这种银弹的实质是与软件的内在特性相违背的。
- 但我们看到了某些方法的规范化、持续化开拓、发展和传播确实可以使生产率数量级提高,虽然没有通天大道,但路就在脚下。
- 虽然没有巨大的提升,但软件行业每一次微小的发展,都预示着寻找一蹴而就的解决方案可能本身就是错误的。
- 工作者的进步是逐步取得的,要伴随着辛勤的劳动,和对规范化过程的不写努力。这才是现代的软件工程。
根本困难
- 软件本身的特性决定了不可能有任何发明创新能够使得本行业,像计算机工业那样取得数量级的生产率提升。我们甚至不能期望明年有100%的增长。
软件开发中的根本困难:
一个相互牵制的关联的概念结构是软件实体必不可少的部分,包括:数据集合,关系,功能调用。这些要素本身是抽象的,尽管概念是相同的,但仍然有丰富的内容和高精确度。
软件开发中最困难的部分是规格说明、设计和测试这些概念上的结构,而不是对概念进行表达和对表达完整程度进行验证。语法错误与系统中的概念错误相比是微不足道的。所以软件开发天生就没有银弹。
现代软件开发中无法规避的内在特性:
1. 复杂度。
软件比人类创造的其他任何实体更复杂,没有任何两个软件是相同的。如有有部分相同,我们会选择共用那些部分,但与建筑或汽车行业大量重复的部分想象比,是远远比不上的。
计算机存在多种状态,软件系统的状态又比计算机状态多多个数量级,这使得构思、描述和测试都非常困难。
软件实体的扩展不仅仅是相同元素的重复叠加,必须是不同实体的叠加。大多数情况下,这些元素以非线性递增的方式交互,因此整个软件的复杂程度比非线性增长还要快的多。
软件的复杂度是根本属性,不是次要因素。因此某些抽象的研究方法是行不通的。
- 由于复杂度,团队成员之间的沟通非常困难,导致了产品瑕疵、成本超支和进度延迟;
- 由于复杂度,使列举所有可能的状态变得十分困难,更不用说理解了,影响了产品的可靠新。
- 由于函数的复杂度,函数调用变得困难,导致程序难以使用;
- 由于结构性复杂度,程序难以在不产生副作用的情况下用新函数扩充;
- 由于结构性复杂度,还造成很多安全机制状态上的不可见性。
复杂度不仅仅导致技术生产的困难,还引发了很多管理上的问题。
- 使得全面理解变得困难,从而妨碍了概念上的完整性;
- 使得所有离散的出口难以寻找和控制;
- 引起了大量学习和理解上的负担,开发慢慢变成了一场灾难;
2. 一致性
物理学家坚信,一定存在某种底层逻辑可以统一整个物理体系。软件工程师却无法从类似的信念中得到安慰,软件的复杂度随心所欲、毫无规则可言,他们随着接口的不同而变化,随着时间的推移而变化,而且这些变化的根本原因仅仅是他们是不同的人设计的结果。对任何软件的再设计都无法简化这些复杂性。
3. 可变现
软件实体经常会受到持续的变更压力。建筑、汽车、计算机产业也是如此,但他们的产品出产后不会去修改之前的设计,而是会被后续的产品取代。可是对软件的调整可谓是司空见惯。
其原因无非是:
- 系统中包含了很多功能,功能是最容易受到变更压力的部分;
- 软件可以很容易的进行修改,它是纯粹思维活动的产物,可以无限扩展。建筑也有可能发生变化,但建筑的修改成本很高,从而打消了那些提出修改的念头。
所有成功的软件都会发生变更。功能扩展的压力主要来自于那些喜欢基本功能,又对软件提出了很多新用法的用户们。
4. 不可见性
软件是不可见的和无法可视化的。例如,建筑平面图能帮助建筑师和客户一起评估空间布局,这样矛盾变得突出,遗漏的地方可以捕捉到。同样,机械制图、化学分子式等抽象模型都起到了相同的作用。
软件的客观存在不具有空间和形体特征。因此,没有几何表达方式,当我们试图用图形来描述软件结构时,发现他是很多相互关联、重叠在一起的图形。他们通常不具有减少层次的扁平结构。除非是强制进行拆分,直到可以层次化一个或多个图形。
以往解决问题的一些突破
回顾一下软件领域中取的成效的三次进步,每一次都解决了软件构建上的巨大困难,但这些只是次要困难,不是本质属性,也不是本质困难。
1. 高级语言
高级语言减轻了一些次要的软件复杂度。他所达到的抽象程度体现了抽象程序所需的要素,避免了更低级的元素,他消除的并不是程序所固有的整个级别的复杂度。
2. 分时
(不具备参考价值,作者略过)
3. 统一编程环境
现在已经广泛应用,他们主要通过集成库、统一文件格式,解决了共同使用程序的次要困难。这样,概念性结构理论上的相互调用变得非常容易实现。因为每个新工具可以通过标准格式在统一环境中应用,这种突破又激励着整个工具库的开发。
由于上述的这三点成功,环境开发是当今软件工程的主要研究题目。
银弹的希望
1. 更高级的编程语言
使用更加抽象的语句来开发,降低了机器的次要复杂度。
高级语言更重要的贡献在于对编程人员培训方式的转变,新的工程师将会更专注于解决软件的根本问题。
2. 面向对象编程
它的出现消除了开发过程中的非本质困难,允许设计人员表达自己设计的内在特性,而不需要表达大量语法上的内容。
3. 人工智能
人工智能可以应用到:建议接口规则、指定测试策略、记录各种bug产生的评率和提供优化建议,等等。
(到今天我们仍然不知道人工智能对软件开发到底意味着什么)
4. 自动编程
将问题通过相对较少的参数迅速的描述特征
存在很多已知的解决方案,提供了可供选择的库
在给定问题参数的前提下,大量广泛的分析,为解决方案选择提供建议
(是IDE+Google的意思么)
5. 图形化编程
图形化编程可行,但没有什么令人信服的进步。我确定将来也不会出现。流程图已经被证明是一种完全不必要的设计,且是一种差劲的软件结构表达方式。
6. 程序验证
有没有可能在设计阶段、源码阶段就消除bug?通过某种深奥的策略,在投入生产和测试之前就能证实设计的正确性,彻底的提高软件的生产率和产品的可靠性?
(四十年过去了,没有这种东西)
7. 环境和工具
8. 工作站
针对根本问题的颇具前途的方法
工作的创造性部分占据了大部分时间,那些仅仅是表达概念的活动并不能很大程度上影响生产率。因此我们必须考虑解决必要困难,即准确地表达复杂的概念结构。幸运的是,其中一些问题非常有希望被解决。
1. 购买和自行开发
构建软件最彻底的解决方案可能就是不开发任何软件,而是买一个来。任何软件,购买都要比重新开发廉价的多。而且立即可用,甚至还有良好的文档。
(现在成品软件市场确实已经很发达了)
2. 需求精炼和快速原型
开发过程中最困难的部分是确切的决定搭建什么样的系统。概念性工作中,没有其他任何一个部分比确定详细的技术需求更加困难。详细的需求包括了所有人机界面,与其他软件系统的接口。如果失误了,需求工作对系统的影响比其他任何一个部分都大,当然纠正需求的困难也比其他任何一个部分都要大。
因此,软件开发人员为客户所承担的最重要的职能是不断重复的抽取和细化产品的需求。事实上,客户不知道自己需要什么。他们通常不知道哪些问题是必须回答的。并且,连必须确定的问题细节常常根本不予考虑,甚至只是简单的回答“开发一个类似于**的新系统”,实际上都过于简单了。客户绝不会仅仅只要求这些。复杂的软件往往是活动的、变化的系统。活动的动态部分是很难想象的。所以,在计划任何软件活动时,要让客户和设计人员之间进行多次广泛的交流沟通,并将其作为系统定义的一部分,这是非常必要的。
这里,我向前走一步,下一个定论。在尝试和开发一些客户定制的系统之前,即使他们和软件工程师一起工作,想要完整、精确、正确的抽取软件产品的需求,这是不可能的。
因此,现在的技术中最有希望的,并且解决了软件根本问题的技术,是开发快速原型化系统的方法和工具。
软件系统的快速原型对重要的系统界面进行模拟,并演示待开发系统的主要功能。原型通常展示了应用程序的功能主线,但不处理任何无效输入等异常。原型的目的是明确实际的概念结构,使客户可以测试一致性和可用性。
软件开发流程的假设是荒谬的,有效的改进方式就是,对产品和原型不断反复的进行开发和规格化。
3. 增量开发——搭建而非编写系统。
研究一下生物的复杂性,他们的复杂程度是令人敬畏的,仅仅是大脑本身就比任何对他的描述都要复杂,他的多样性、自我保护和自我更新能力异常丰富和有力。其中的秘密就是逐步发育成长,而不是一次性编写。所以我们的系统也必须如此。
在过去的几十年中,没有任何方法和技术能如此彻底的改变我自己的实践。这种方法迫切的要求自上而下的设计,增量化的开发使逆向跟踪变得方便,并且非常容易进行原型开发。每新增一项功能,都需要从已经规划的系统中有机的增长。
这种开发模式对士气的推动是令人震惊的。当一个可运行的系统(即使非常简单)出现时,开发人员的热情就迸发出来了。在开发过程的每个阶段,总有可运行的系统。我发现开发团队可以在相同时间内,搭建出复杂得多的系统。
4. 卓越的设计人员
软件行业的核心、关键问题,一如既往的是人员。
我们可以通过遵循优秀的实践,来得到良好的设计。优秀的设计是可以传授的!程序员的周围往往是最出色的人员,因此他们可以学习到良好的实践。推出新课程、新文献,都是为了把我们的实践从不足提升到更高的水平,其正确性是毋庸置疑的!
从普通到优秀之间的区别可能在于设计方法的完善性,而优秀和卓越之间的差距肯定不是如此。卓越的设计来自于卓越的设计人员。软件开发是一个创造性过程。完备的方法论可以培养和释放创造性的思维,但它无法孕育出卓越。
尽管我强烈的支持开发技能的传授,但我认为我们最重要的工作是寻求和培养卓越的设计人员。
设计人员和管理人员同样重要,他们应该得到相同的培养和回报,不仅仅是薪资,还包括各方面的认可:办公室规模、家具、个人设备、差旅费和人员支持等,必须完全一致。
至于如何培养出卓越的设计人员,有些步骤是显而易见的:
- 尽可能早的、系统的识别顶级设计人员,最好的通常不是最有经验的。
- 为设计人员指派一位职业导师,负责他们技术方面的成长,仔细地为他们规划职业生涯。
- 制定和维护一份职业计划,包括与设计大师的学习过程,正式的高级教育和短期课程。所有这些都穿插在设计和技术领导能力的培养安排中。
- 为成长中的设计人员提供相互交流和激励的机会。
以上就是《人月神话》第16章——没有银弹的全部内容
本章是全书倒数第二章,也是全书的结论性部分。我读完之后是异常激动、溢于言表,40年前竟有如此洞见,令人叹服,整章内容都具有很好的现世参考价值。
作者想要表达的核心观点总结下来无非就是两点:
- 软件开发的困难是决定做什么,而不是如何做。
- 软件领域真正需要的是不那么引人注意的平稳进步。