什么是软件工程
定义
软件工程是一门工程学科,涉及软件生产的各个方面,从最初的系统描述一直到投入使用后的系统维护,都属于其学科范畴。
软件工程定义的关键词有二:
- 工程学科:他要求工程人员选择性利用一定的理论、方法和工具,或者在机构或财政状况所允许的限度下,寻找解决问题的方法。
- 软件生产的各个方面:软件工程不仅涉及软件开发的技术过程,也涉及诸如软件项目管理以及哪些支持软件生产的工具、方法和理论的开发等活动。
软件过程(生命周期)
定义
软件过程是一组引发软件产品生产的活动。虽然软件过程各不相同,但总体可分为以下几个部分:
- 软件描述:必须定义软件的功能以及软件操作上的约束
- 软件设计和实现:必须生产符合描述的软件
- 软件有效性验证:软件必须得到有效性验证,确保软件是客户所想要的
- 软件进化:软件必须进化以满足不断变化的客户需要
当然在传统的定义里,软件过程(生命周期)是指软件从需求提出、开发、投入使用,直到最终被淘汰或废弃的整个时期。它通常包括可行性研究与计划、需求分析、概要设计、详细设计、编码实现、测试、运行维护等阶段。
两种定义里都强调把软件开发划分为若干阶段,每个阶段有明确的任务、文档和评审标准,从而便于项目管理、质量控制和成本控制。
过程模型
下面提到的一般模型不是软件过程的唯一性描述,而是对软件过程一种有用的抽象,能用来解释软件开发的不同方法。
瀑布模型
定义
瀑布模型是计划驱动的软件过程的一个经典例子,在开始工作前,必须对所有的过程活动指定计划并给出进度安排。一般过程如下图所示:

详解:
- 需求分析和定义:通过咨询系统用户建立系统的服务、约束和目标。并对其详细定义形成系统描述。
- 系统和软件设计:系统设计过程通过建立系统的总体体系结构将需求区分为硬件需求和软件需求。软件设计包括识别和描述一些基本的软件系统抽象及其之间的关系。
- 实现和单元测试:在此阶段,将软件设计实现为一组程序或程序单元。单元测试就是检验每个单元是否符合其描述。
- 集成和系统测试:集成单个的程序单元或一组程序,并对系统整体进行测试以确保其满足了软件的需求。在测试之后,软件系统将交付给客户使用。
- 运行和维护:正常情况下(虽然不是必须的),这是一个具有最长生命周期的阶段。系统被安装并且投入实际的使用中。维护包括改正那些在早期各阶段未被发现的错误,改善系统各个单元的实现,并当新的需求出现时提高系统的服务能力。
适用场景
原则上,每个阶段的结果是一个或多个经过核准的文档。直到上一个阶段完成,下一阶段才能启动。因为生成和确认文档的成本很高,因而反复是昂贵的而且十分费时。
这意味着,为了效率,必须适时冻结部分开发过程,才能顺利继续进行后面的开发阶段。然而,当外部因素变得复杂,如需求变化、财政限制等,因冻结带来的问题一览无遗。
留着以后解决,或者忽略掉、或者在编程中想办法绕过去是几种解决方式。可是这种对需求的冻结会使需求相当不成熟,不能满足用户的需要。当设计上的问题通过一些编程的小技巧来解决时,系统的良好结构又会遭到破坏。
为数不多的优点是,使用该模型开发时过程是可见的,项目经理能够根据项目计划监控项目的过程。它的主要问题在于它将项目生硬地分解成这些清晰的阶段。关于需求的责任和义务一定要在过程的早期阶段清晰界定,而这又意味它对用户需求变更的响应较困难。
瀑布模型的一种变形是形式化系统开发:用数学模型描述系统,再通过保持一致性的数学变换逐步生成可执行代码。变换正确即可证明代码与描述一致。仅用于安全性/信息安全要求极高的系统,需要极专业技能。
所以只有在对需求了解得好,而且在系统开发过程中不太可能发生重大改变的时候,适合采用瀑布模型。毕竟,瀑布模型反映了在其他工程项目中使用的一类过程的模型。由于在整个项目中它很容易结合通用的管理模式进行管理,基于该方法的软件过程仍然广泛应用于软件开发。对于大多数系统,在系统开发中应用这一过程不会比其他方法带来明显的成本优势。
增量式开发
定义
增量式开发的思想是先开发出一个初始的实现,给用户使用并听取用户的使用意见和建议,通过对多个版本的不断修改直到产生一个充分的系统。描述、开发和有效性验证等活动不是分离的而是交织在一起。同时让这些活动之间都能得到快速的反馈信息传递。

适用场景
对于商务、电子商务和个人系统来说,增量式软件开发更加适合。有些情况下我们很少能提前制定出完整的问题解决方案。更一般来说,我们是逐步地逼近解决方案,当意识到错误的时候进行回溯。
通过增量式地开发软件,在开发过程中可以更经济、更容易对软件变更做出响应:系统的每一个增量或版本包括用户需要的一部分功能,这就意味着在早期开发阶段,用户可以在相对早地评估系统,看它是否满足需要。假如不满足需要,只有目前的增量需要改变,或许,有新的功能被发现并为下个增量做准备。
增量式开发较之瀑布模型有3个重要优点:
- 降低了适应用户需求变更的成本。重新分析和修改文档的工作量较之瀑布模型要少很多。
- 在开发过程中更容易得到用户对于已做的开发工作的反馈意见。用户可以评价软件的现实版本,并可以看到已经实现了多少。这比让用户从软件设计文档中判断工程进度要好很多。
- 使更快地交付和部署有用的软件到客户方变成了可能,虽然不是所有的功能都已经包含在内。相比于瀑布模型,用户可以更早地使用软件并创造商业价值。
增量式开发的问题
尽管增量式开发有很多优点,但它也不是没有问题。它的困难的主要原因是,大型机构的官僚办事程序随着时间的推移已经根深蒂固,有可能这些办事程序与更加非形式化的迭代和敏捷过程不匹配。
有时,这些办事程序是有其存在的充分理由的,如,可能有些程序是为了确保在软件开发过程中能正确执行外部法规。不可能改变这些程序,因此过程冲突是不可避免的。
从管理的角度来看,增量式方法存在两个问题:
- 过程不可见。管理者需要通过经常性的可交付文档来把握进度,如果系统开发速度太快,要产生反映系统每个版本的文档就很不划算。
- 伴随着新的增量的添加,系统结构在逐渐退化。除非投人时间和金钱用在重构系统结构上以改善软件,否则定期的变更会损坏系统的结构。随着时间的推移,越往后变更系统越困难,而且成本也将逐渐上升。
面向复用的软件工程
定义
在大多数的软件项目中,都存在一定程度的软件复用。当人们注意到某项目中的设计或代码是与当前项目中所需要的部分相像的时候,复用就自然地发生了。人们搜寻这些东西,而后根据需要修改它们,再将其纳入自己的系统中来。面向复用的方法依赖于存在大量可复用的软件组件以及能组合这些组件的集成框架。有时,这些组件本身就是一个系统(COTS 即商业现货系统),能提供专门的功能,例如字处理或制表软件。

这些阶段是:
- 组件分析:给出需求描述,然后搜寻能满足需求的组件。通常情况是,没有正好合适的组件以供选择,能得到的组件往往只提供所需要的部分功能。
- 需求修改: 在这个阶段,根据得到的组件信息分析需求,然后修改需求以反映可得到的组件。当需求修改无法做到的时候,就需要重新进入组件分析活动以搜索其他可能的替代方案。
- 使用复用的系统设计: 在这个阶段,设计系统的框架或者重复使用一个已存在的框架。设计者分析那些将被重复使用的组件,并组织框架使之适应这些组件。当某些可复用的组件不能得到时,必须重新设计一些新的软件。
- 开发和集成: 当组件不能买到时就需要自己开发,然后集成这些自己开发的组件和现成组件,使之成为一个整体。在这个模型中,系统集成与其说是一个独立的活动,不如说已经成为开发过程的一部分,贯穿于组件选取、适配和组装的全过程。
适用场景
面向复用的模型的明显优势是它减少了需要开发的软件数量,从而降低了软件开发成本,同时也降低了开发中的风险。通常也可使软件快速地交付。
然而,需求妥协是不可避免的,而且这可能又导致一个不符合用户真正需要的系统。此外,对系统进化的控制也将失效,因为可复用的组件新版本可能是不受机构控制的。
国内教材体系补充
Sommerville 原书重点讲瀑布、增量式开发、面向复用和敏捷,未单列“快速原型模型”和“螺旋模型”。国内教材通常将过程模型分为瀑布、快速原型、增量、螺旋四类。为便于对照,此处补充国内体系常考内容。
快速原型模型:先快速构建一个可运行原型给用户试用,根据反馈明确需求,再在此基础上开发正式系统。
- 优点:用户尽早看到可运行软件,便于澄清需求,降低返工风险,适合需求模糊的小型系统。
- 缺点:原型容易被误认为最终产品;若直接演化为正式系统,结构可能较差;额外原型开发增加短期成本。
螺旋模型:将瀑布模型与原型模型结合,并引入风险分析。每一轮螺旋包含制定计划、风险分析、实施工程、客户评估四个活动。
- 优点:强调风险分析,适合大型、高风险项目;迭代推进,每轮都有客户评估,能及时调整方向。
- 缺点:需要风险评估的专业知识和经验,门槛较高;螺旋轮次和周期不易控制;小型项目成本过高。
喷泉模型:主要用于面向对象软件开发,体现迭代性和无间隙性。各阶段之间没有明显边界,分析、设计、编码等活动可以交叉、同步进行,像喷泉一样向上喷涌、不断迭代。
- 优点:提高开发效率,节省时间;适应需求变化,灵活性较高;天然支持面向对象和复用。
- 缺点:阶段重叠需要大量开发人员,不利于项目管理;文档管理难度大,审核困难;对团队协作和沟通要求较高。
- 适用:需求不明确或变化频繁的面向对象项目。
RUP(统一过程):由 Rational Software 提出的迭代、增量、风险驱动、架构为中心的软件过程框架。二维结构:静态维度为 9 个核心工作流(业务建模、需求、分析与设计、实现、测试、部署、配置与变更管理、项目管理、环境);动态维度为 4 个阶段(初始、细化、构建、移交)。每个阶段内可包含多次迭代。
- 优点:迭代增量,尽早发现缺陷;用例驱动,以用户需求为中心;架构为中心,强调早期建立稳定架构;风险驱动,细化阶段重点处理高风险问题。
- 缺点:过于复杂,对中小型项目过于烦琐;文档负担重,制品并非全部交付;灵活性有限,与敏捷相比偏重设计和规范;对团队要求高,需要经验丰富的架构师和项目经理。
- 适用:大型、复杂、高风险项目,尤其是需要严格架构和风险管理的企业级系统。
总结
| 模型 | 核心特点 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| 瀑布模型 | 计划驱动;线性阶段;文档驱动;阶段完成才进入下一阶段,需适时冻结需求 | 过程可见,便于项目经理监控;文档规范,便于管理和交接;适合需求稳定的项目 | 反复代价高、费时;需求变更响应差;用户后期才看到系统;冻结需求易不成熟;用编程技巧绕过设计问题会破坏结构 | 需求了解充分,且开发过程中不太可能发生重大变更;容易结合通用管理模式 |
| 形式化系统开发(瀑布变形) | 用数学模型描述系统;通过保持一致性的数学变换生成可执行代码;可证明代码与描述一致 | 安全性/信息安全性极高;代码与描述一致性可证明 | 需要极专业的知识和技能;只适合极特殊系统 | 安全性或信息安全性要求极高的系统 |
| 增量式开发 | 先开发初始实现;多版本迭代;描述、开发、验证交织;快速反馈 | 降低需求变更成本;更容易获得用户反馈;更快交付部分有用软件,提前创造商业价值 | 过程不可见,文档不划算;系统结构容易退化,需持续重构;可能与大型机构官僚流程冲突 | 商务、电子商务、个人系统;需求难以提前完整定义,需要逐步逼近解决方案 |
| 面向复用的软件工程 | 复用组件、框架或 COTS;流程为组件分析→需求修改→使用复用的系统设计→开发和集成 | 减少需要开发的软件数量;降低成本与风险;通常能快速交付 | 需求妥协不可避免,可能不符合用户真正需要;系统进化控制失效;复用组件新版本可能不受本机构控制 | 存在大量可复用组件和集成框架;可接受一定程度的需求妥协 |
| 快速原型模型(国内补充) | 先快速构建可运行原型;用户试用后明确需求;再开发正式系统 | 用户尽早看到可运行软件;便于澄清需求;降低后期返工风险 | 原型容易被误认为最终产品;若直接演化为正式系统,结构可能较差;额外原型开发增加短期成本 | 需求模糊、用户自己也说不清的小型系统 |
| 螺旋模型(国内补充) | 瀑布模型 + 原型模型 + 风险分析;每轮螺旋包含制定计划、风险分析、实施工程、客户评估 | 强调风险分析,适合大型高风险项目;迭代推进,每轮客户评估,能及时调整方向 | 需要风险评估的专业知识和经验;螺旋轮次和周期不易控制;小型项目成本过高 | 大型、高风险项目 |
| 喷泉模型(国内补充) | 面向对象;迭代、无间隙、阶段重叠;分析、设计、编码交叉进行 | 提高效率,节省时间;适应需求变化,灵活性高;天然支持复用 | 阶段重叠需大量人员,不利项目管理;文档管理难,审核困难;对协作要求高 | 需求不明确或变化频繁的面向对象项目 |
| RUP(国内补充) | 迭代、增量、用例驱动、架构为中心、风险驱动;二维结构:9 工作流 + 4 阶段(初始、细化、构建、移交) | 迭代增量,尽早发现缺陷;用例驱动,以用户需求为中心;架构为中心;风险驱动 | 过于复杂,中小项目烦琐;文档负担重;灵活性有限;对团队要求高 | 大型、复杂、高风险的企业级系统 |
软件方法学
定义
软件方法学是指导软件开发全过程的系统化思想、原则、方法和工具的总称,回答“用什么思路分析、设计、实现软件”。在原书中,Sommerville 没有单列此章,相关内容分散在需求、建模、设计和敏捷等章节。
两类经典方法
| 维度 | 结构化方法 | 面向对象方法 |
|---|---|---|
| 核心 | 功能分解、自顶向下、逐步求精 | 对象/类、封装、继承、多态 |
| 基本单位 | 模块、过程、函数 | 对象、类 |
| 数据与操作 | 分离 | 封装在一起 |
| 常用工具 | DFD、数据字典、结构图 | UML:用例图、类图、时序图等 |
| 开发过程 | 偏线性、文档驱动 | 迭代、增量、用例驱动 |
| 适用 | 需求稳定、中小系统 | 复杂、大型、需求多变 |
| 缺点 | 需求变化代价大,复用/扩展较弱 | 抽象要求高,可能过度设计 |
敏捷更偏过程组织与协作方式,通常放在软件过程/过程模型里讲,这里不展开。
实际使用
实际项目很少纯用一种方法学。例如报修系统:工单领域模型用面向对象;金额计算用过程式/函数式分解,也可用数据流图描述;持久化用关系模型;审批流程用状态机。方法学是工具箱,不是互斥标签。
软件过程/生命周期是阶段与活动框架;软件方法学是具体分析、建模、设计的手段。二者结合使用。