1.3 什么是软件工程
面对软件开发与维护所面临的挑战和问题,人们开始探索把工程的方法应用于软件开发,即以价值为中心,用现代工程的概念、原理、技术和方法进行计算机软件的开发、运营和维护,把经过时间考验而证明正确的管理技术和当前能够得到的最好的技术方法结合起来,以经济地开发出高质量的软件并进行有效的维护,这就是软件工程。
1.3.1 软件工程的概念和知识体系
“软件工程”一词,最早是1968年北大西洋公约组织(NATO)在开创性软件工程主题会议上提出的,Fritz Bauer给出了如下的定义:“软件工程就是为了经济地获得可靠的且能在实际机器上高效运行的软件而建立和使用的工程原理”。1990年,ISO/IEC/IEEE系统和软件工程的术语标准给出一个更全面的定义:软件工程是将系统的、规范的、可量化的方法应用于软件的开发、运行和维护,即将工程化应用于软件。
1999年,ISO和IEC启动了软件工程知识体系(Software Engineering Body Of Knowledge,SWEBOK)指南的标准化项目,IEEE和ACM等联合承担了这一任务,几十个国家和地区的几百名软件工程专家共同参与了指南的制定。SWEBOK指南在2001年推出第一个版本,2004年和2014年分别推出了2.0版和3.0版,目前4.0版正在评审中,预计2023年推出。SWEBOK指南的目的是促进世界范围内对软件工程的一致观点,阐明软件工程相对其他学科(如计算机科学、项目管理、数学、工程学)的定位和分界,刻画软件工程学科的核心知识。更新后的SWEBOK指南4.0版把软件工程的知识域分为软件需求、软件架构、软件设计、软件构造、软件测试、软件工程运营、软件维护、软件配置管理、软件工程管理、软件工程模型与方法、软件工程过程、软件质量、软件安全、软件工程经济、软件工程职业实践、计算基础、数学基础和工程基础。其中前15个知识域涵盖软件工程专业知识,后3个知识域是通用的基础知识。
1.3.2 软件价值工程
软件工程是一门工程,因此其根本目标是创造价值。价值是“事物的作用、重要性或实用性”[4]。软件价值对不同的对象有不同的含义:对软件开发方来说,高价值就是低的开发成本;对软件开发投资方(sponsor)来说,价值是投资收益;对软件使用者来说,价值就是效益。因此要提高软件价值,就要提高效益、降低成本。而效益和成本之间没有固定的计算公式,这就是创新的动力之源。
UMLChina首席专家潘加宇提出一个很有趣也颇有道理的观点,他认为,软件需求的根本目标是创新,解决“提高效益”问题,即让“产品好卖”;而软件设计的根本目标是模块化与复用,致力于解决“降低成本”的问题。不仅仅是软件需求和设计,软件工程中的每一个环节和每一个活动都是为了价值交付。例如,智能编码、强调质量和测试而减少返工、进行成本的估算和控制、采用敏捷过程、构建DevOps工具链、关注软件服务的运维质量等,都是以价值为目标所提出的最佳实践。
软件工程是一项价值工程,其生产力是持续快速交付价值的能力,即以价值为中心,追求软件开发的质量、效率和速度,如图1-2所示。用最朴素直白的表达,就是“多快好省”地开发和运维有价值的软件。
图1-2 软件工程生产力
1.3.3 软件系统工程
软件总是处于复杂的系统中,其中包括网络、服务器、中间件、数据库等基础软硬件以及用户和软件所处的物理与社会环境。对用户及其他干系人(即与软件系统相关的人或组织)而言,真正有价值的是完整的系统而非其中的软件。因此,需要在这个更大的系统范围内思考软件的定位和作用,进行不同系统组成成分之间的职责分配和协同,明确软件的需求。
软件工程的系统思维分为四个方面:
1)全局思维。分析软件系统内各模块之间的关系,与外部系统交互,以及这些关系背后的运行逻辑。
2)综合思维。软件系统是社会系统和技术系统相互作用而形成的社会技术(social-tech)系统。
3)工程思维。软件工程应以资源有限、条件不足为前提,去实现“现实世界”的目标。
4)抽象思维。通过抽象提炼复杂软件系统的本质,对软件系统进行建模。
如何才能成功地开发出一个复杂的软件系统?有三条复杂性控制的基本准则——抽象、分解和迭代,这些方法能应用于几乎所有复杂事物的处理上。
(1)抽象
抽象(abstraction)是从众多的事物中抽取出共同的、本质性的特征,而舍弃其非本质的特征。共同特征是指那些能把一类事物与他类事物区分开来的特征,这些具有区分作用的特征又称本质特征。因此抽取事物的共同特征就是抽取事物的本质特征,舍弃非本质的特征。抽象也是一个裁剪的过程,它将不同的、非本质性的特征全部裁剪掉了。
共同特征是相对的,是指从某一个刻面(角度)看是共同的。比如,对于汽车和大米,从买卖的角度看都是商品,都有价格,这是它们的共同特征,而从其生物特性角度看,它们则是不同的。所以在抽象时,同与不同,决定于从什么角度上来抽象。抽象的角度取决于分析问题的目的。
抽象可应用于各领域中以降低问题的复杂度。普遍运用于程序设计中的抽象包括两种,一种是过程抽象(procedural abstraction),另一种是数据抽象(data abstraction)。对象(类)的抽象则通过操作和属性,组合了这两种抽象。
(2)分解
分解(decomposition),即分而治之,是指把一个复杂的问题分解成若干个简单的问题,然后逐个解决。我们把一个复杂的软件分解成多个模块,开发人员能够在不需要许多交流的情况下,开发不同的模块,最终把这些模块集成为一个软件系统。在分解问题时,应遵循以下原则:
● 每个子问题在细节上处于相同的级别。
● 每个子问题能够被独立解决。
● 每个子问题的解决方案综合起来可以解决原来的问题。
(3)迭代
复杂软件系统充满着很多不确定性和挑战,当我们对此缺少经验,无法对其进行正确的分解和抽象时,如何进行处理?采用迭代(iteration)开发!在软件系统全面构造之前,我们先针对不确定的问题做试验,以获得经验。如果问题很复杂,则再做试验,获得更多经验,直至我们有足够的经验进行正确的处理。每一轮尝试就是一个迭代,例如应对需求模糊的需求界面原型迭代,应对技术和架构风险的技术原型迭代,应对进度风险的构造迭代(重要的功能在前期迭代中完成,可以提前交付),等等。前一个迭代中获得的知识将为后期迭代提供指导。
1.3.4 软件工程的发展趋势
在互联网和人工智能等技术的影响下,软件工程正在经历一场深刻的变革,呈现出敏捷化、智能化和全球化的发展趋势。
(1)敏捷化
面临在需求和技术不断变化的场景下快速实现软件开发和维护的挑战,软件的开发和运维呈敏捷化趋势,Scrum和DevOps等敏捷过程应运而生。敏捷过程强调以人为本,快速响应需求和变化,高效地交付产品,它基于适应而非预测,通过快速、短迭代的开发,不断产出和演化软件。敏捷过程高度注重人员间的协作和交流,而非命令和控制,充分发挥工程师的能动性和创造力,同时通过工具链来提升工作的效率和质量。
(2)智能化
软件工程正在进入智能化时代,Codex、ChatGPT和GPT-4等人工智能技术极大地赋能于软件开发和运维,成为软件工程师强大的智能助手,可用于软件需求分析、设计方案推荐、根据上下文自动生成代码、自动生成测试脚本、自动诊断和修复缺陷、辅助理解代码等环节。智能化软件工程不仅能提升软件工程的效率和质量,使软件工程师能更多地关注创造性工作,而且将极大地推动最终用户参与到软件开发中,最终实现“人人都是程序员”。
(3)全球化
互联网为人类个体之间的交互和协作提供了一种全新的基础设施,促进了社会化、全球化的软件工程实践的出现。这种新型软件工程被称为群体软件工程,它利用互联网将全球各地的开发者和用户协同起来,合作创新,“集众智、采众长”,快速开发出高质量的软件系统。这不仅有利于软件开发和运维的全球化,同时也推动了软件生态的建立和产业创新。目前群体软件工程主要形态有三种,即开源软件、软件众包,以及应用程序商店。