一、引言:软件工程概述
软件工程(Software Engineering)是一门将工程化的方法应用于软件的开发、运行和维护的学科,它涵盖了系统化的、规范的、可量化的方法。在系统架构设计师考试中,软件工程是贯穿始终的核心知识体系,从需求到维护的每一个环节都涉及工程化的思想与方法。
软件工程是:
1. 将系统化的、规范的、可度量的方法应用于软件的开发、运行和维护的过程,即将工程化应用于软件中;
2. 对上述方法的研究。
——出处:IEEE 610.12-1990 软件工程术语标准
1.1 软件危机的由来
20 世纪 60 年代,随着计算机应用的普及,软件规模急剧膨胀,开发效率、质量与维护问题集中爆发,史称"软件危机"(Software Crisis)。1968 年,北约在德国加米施召开的学术会议上首次提出"软件工程"一词,标志着软件工程作为一门独立学科正式诞生。
· 开发成本与进度严重超支
· 软件质量低、缺陷多、不可维护
· 需求频繁变更,开发无法适应
· 缺乏科学的开发方法和管理规范
· 文档不全、人员流失导致知识断层
· 软件难以追踪和验证("看不到摸不着")
软件危机的根源在于软件本身的特殊性:软件是逻辑产品而非物理产品,看不见摸不着;其复杂性随规模呈非线性增长;且软件不会"磨损",但会因环境变化和需求变更而"退化"。软件工程正是为应对这些挑战而生。
1.2 软件工程三要素
软件工程由三个核心要素构成,三者相辅相成:
软件工程三要素
- 方法(Methods):提供了"如何做"的技术,包括需求分析、设计、编码、测试、维护等各种方法学,如结构化方法、面向对象方法。
- 工具(Tools):为方法的运用提供自动化或半自动化支持,如 IDE、版本控制工具、测试工具、CASE 工具。
- 过程(Process):将方法和工具综合起来以达到合理、及时进行软件开发的目的,定义了活动的顺序、里程碑和交付物。
1.3 软件工程知识体系(SWEBOK)
IEEE 计算机学会发布的 SWEBOK(Software Engineering Body of Knowledge)将软件工程知识划分为 15 个知识域,这是软考复习的总体框架:
| 知识域 | 核心内容 |
|---|---|
| 软件需求 | 需求工程过程、需求获取、分析、规约、验证与管理 |
| 软件设计 | 软件结构设计、详细设计、设计模式、设计原则 |
| 软件构造 | 编码、单元测试、调试、代码复用 |
| 软件测试 | 测试用例设计、测试策略、缺陷管理 |
| 软件维护 | 纠正性、适应性、完善性、预防性维护 |
| 软件配置管理 | 版本控制、变更控制、配置审计 |
| 软件工程管理 | 项目计划、估算、风险管理、质量管理 |
| 软件工程过程 | 过程定义、过程评估、过程改进(CMMI) |
| 软件工程模型与方法 | 建模语言(UML)、结构化方法、面向对象方法 |
| 软件质量 | 质量属性、质量模型、质量保证、评审与审计 |
软考系统架构设计师考试中,软件工程知识是上午综合知识题和下午案例分析题的重点考查内容。其中软件开发模型、需求工程、软件设计、软件测试是高频考点,必须重点掌握。
二、软件生命周期
软件生命周期(Software Life Cycle)是指软件产品从构思、定义、开发、使用、维护到退役的整个过程,又称软件生存周期。将生命周期划分为若干阶段,便于管理和控制每个阶段的质量、成本和进度。
2.1 生命周期阶段划分
国标 GB/T 8566 将软件生命周期划分为若干阶段,软考通常采用以下经典划分:
2.2 各阶段任务与交付物
| 阶段 | 核心任务 | 关键交付物 | 里程碑 |
|---|---|---|---|
| 可行性研究 | 确定项目是否值得做、能否做,从技术、经济、操作、法律等角度论证 | 可行性研究报告、项目计划 | 立项决策 |
| 需求分析 | 明确系统"做什么",确定功能需求、非功能需求与约束 | 软件需求规格说明书(SRS) | 需求评审通过 |
| 概要设计 | 将需求转化为软件体系结构,划分模块、定义接口 | 概要设计说明书(HLD) | 架构评审通过 |
| 详细设计 | 为每个模块设计内部算法、数据结构、接口细节 | 详细设计说明书(LLD) | 设计评审通过 |
| 编码 | 将详细设计翻译为程序代码,遵循编码规范 | 源程序、单元测试脚本 | 代码完成 |
| 测试 | 发现并修复缺陷,验证是否满足需求 | 测试计划、测试用例、测试报告 | 验收通过 |
| 维护 | 运行期间的纠错、适配、完善与预防 | 维护记录、变更文档 | 退役 |
1. 技术可行性:现有技术能否实现?风险多大?
2. 经济可行性:成本-收益分析(ROI),是否值得投资?
3. 操作/运行可行性:用户能否接受、能否顺利运行?
此外还有法律可行性(是否侵权、合规)与方案可行性(多种备选方案对比)。
2.3 软件维护的四种类型
软件维护是生命周期中持续时间最长、成本最高的阶段。维护活动分为四类,是软考的高频考点:
| 维护类型 | 触发原因 | 占比 | 举例 |
|---|---|---|---|
| 改正性维护 | 发现并修复遗留缺陷 | 约 20% | 修复支付金额计算错误的 Bug |
| 适应性维护 | 适应环境变化(硬件、OS、法规) | 约 25% | 系统从 Windows 迁移到 Linux |
| 完善性维护 | 用户提出新需求、改善性能 | 约 50%(占比最大) | 增加报表导出 Excel 功能 |
| 预防性维护 | 主动改进可维护性、可靠性 | 约 5% | 重构代码、更新文档 |
三、软件开发模型(高频考点!)
软件开发模型(Software Development Model)是软件工程过程的具体实例化,它规定了软件开发活动中各阶段的执行顺序、衔接关系以及交付要求。不同模型反映了不同的过程哲学。本章是软考系统架构设计师考试的绝对高频考点,必须熟练掌握每个模型的特征、优缺点和适用场景。
对每种模型,请按以下五要素记忆:
1. 核心思想:模型基于什么理念?
2. 过程特征:阶段如何组织?是否迭代、是否增量?
3. 优缺点:至少各记 3 条;
4. 适用场景:什么样的项目最适合?
5. 典型图表:能画出示意图。
3.1 瀑布模型(Waterfall Model)
瀑布模型由 Winston Royce 于 1970 年提出,是最早的、也是最经典的软件开发模型。它将生命周期划分为顺序的、依赖的阶段,前一个阶段的输出作为后一个阶段的输入,像瀑布一样逐级下落,不可回溯(严格意义上的瀑布模型)。
瀑布模型核心特征
- 阶段顺序性:前一阶段完成后才进入下一阶段,阶段间有明确的里程碑和评审
- 文档驱动:每阶段必须产出规范的文档,文档是阶段衔接的纽带
- 严格评审:每阶段结束前进行评审,评审通过才能进入下一阶段
- 推迟实现:编码在需求、设计完成后才开始,避免过早编码
- 可见性差:用户直到测试阶段才能看到可运行系统
优点
- 过程清晰、阶段分明,易于管理和控制
- 文档完整,有利于团队协作和后续维护
- 每个阶段都有明确的里程碑和质量基线
- 适合需求稳定、技术成熟的项目
缺点
- 无法应对需求变更,灵活性差
- 用户直到很晚才能看到可运行产品
- 前期缺陷发现晚,修复成本高
- 文档工作量大,效率低
· 需求非常明确且稳定;
· 技术成熟、风险低;
· 大型、复杂的系统软件(如航天、军工、金融核心);
· 合同型项目,需求由甲方严格定义。
3.2 增量模型(Incremental Model)
增量模型将软件拆分为若干个增量构件,每个增量实现一部分功能。第一个增量通常是核心功能("最小可用产品"),后续增量逐步添加新功能。每个增量本身经历需求、设计、编码、测试的完整小型瀑布。
优点
- 用户较早得到核心功能,信心强
- 优先级高的功能先开发、先测试,风险早暴露
- 每个增量可独立部署、独立验收
- 资金分批投入,便于控制投入产出
缺点
- 增量划分困难,接口需提前规划
- 后续增量可能影响已交付功能,需回归测试
- 要求软件架构必须开放、可扩展
- 总成本可能高于瀑布模型
· 核心功能明确但完整功能可分期交付;
· 需要快速投入市场获取反馈;
· 资金分批到位的项目;
· 团队能力较强,能预先规划好可扩展的架构。
3.3 螺旋模型(Spiral Model)
螺旋模型由 Barry Boehm 于 1988 年提出,是一种风险驱动的迭代模型。它将瀑布模型与原型模型结合,并引入风险分析环节。每轮螺旋分为四个象限:制定计划 → 风险分析 → 实施工程 → 客户评估,每完成一轮螺旋就向中心收拢,软件逐步完善。
· 最大特点:风险分析,是唯一显式包含风险评估的模型;
· 每一轮都包含完整的目标设定→风险评估→开发→评审循环;
· 适用于大规模、复杂、高风险的项目;
· 依赖有经验的风险分析专家,否则风险分析流于形式。
优点
- 显式风险分析,支持高风险项目
- 迭代开发,灵活适应需求变化
- 客户参与每轮评估,反馈及时
- 结合了瀑布的严谨与原型的灵活
缺点
- 风险分析成本高,依赖专家
- 过程复杂,管理难度大
- 对小项目、低风险项目过于"重型"
- 难以确定何时结束螺旋
3.4 喷泉模型(Fountain Model)
喷泉模型是面向对象开发中常用的模型,它强调迭代和无间隙。各阶段(分析、设计、编码)没有严格的界限,可以交叉、重叠,像喷泉水花一样相互喷涌、回溅。
· 迭代性:分析、设计、实现可反复进行;
· 无间隙性:阶段无明显边界,可交叉重叠;
· 面向对象:与 OOA/OOD/OOP 自然契合;
· 自下而上代表分析与设计逐步深化。
优点
- 与面向对象方法无缝衔接
- 支持迭代,灵活应对变化
- 阶段交叉提高了开发效率
缺点
- 阶段界限模糊,管理与控制难
- 对文档和评审要求高,否则易混乱
- 不适用于面向过程开发
3.5 V 模型(V-Model)
V 模型是瀑布模型的变种,它将开发活动与测试活动一一对应。左半边自上而下是定义阶段(需求分析→概要设计→详细设计→编码),右半边自下而上是测试阶段(单元测试→集成测试→系统测试→验收测试),整体呈"V"字形。
· 需求分析 ↔ 验收测试:验收测试用例基于需求编写
· 概要设计 ↔ 系统测试:系统测试验证整体设计
· 详细设计 ↔ 集成测试:集成测试验证模块间接口
· 编码 ↔ 单元测试:单元测试验证代码逻辑
优点
- 测试与开发同步规划,质量有保障
- 缺陷可在对应的早期阶段被发现
- 阶段对应关系清晰,便于管理
缺点
- 仍属线性模型,对需求变更应对不足
- 测试准备需要早期投入资源
- 实际可执行系统仍要到后期才出现
3.6 快速原型模型(Rapid Prototyping)
快速原型模型在需求分析阶段快速构建一个可运行的原型系统,让用户直观体验并提出修改意见,反复迭代直到用户满意。原型可以抛弃(抛弃式原型)或演化成最终产品(演化式原型)。
优点
- 用户早期参与,需求获取准确
- 原型直观,减少需求误解
- 开发周期短,响应快
- 适合需求不明确的项目
缺点
- 原型可能成为最终产品,质量难保障
- 缺乏系统设计,可维护性差
- 用户可能误以为原型就是产品
- 需要快速开发工具支持
3.7 迭代模型 / 敏捷开发(Agile)
敏捷开发是一种以人为核心、迭代、循序渐进的开发方法。2001 年发布的敏捷宣言确立了四大价值观:个体与互动高于流程工具;可工作软件高于详尽文档;客户合作高于合同谈判;响应变化高于遵循计划。
· 尽早、持续地交付有价值的软件;
· 欣迎需求变化,即使在开发后期;
· 业务人员与开发人员每日协作;
· 围绕有动机的人构建项目,给予信任;
· 面对面交流是最有效的沟通方式;
· 可工作软件是进度的首要度量。
Scrum 是敏捷开发中最流行的过程框架。它将项目划分为若干固定时长的Sprint(冲刺,通常 2~4 周),每个 Sprint 交付一个可工作的增量。
优点
- 快速响应变化,适应需求不确定
- 持续交付可用软件,客户满意度高
- 团队沟通紧密,氛围好
- 风险早暴露早解决
缺点
- 文档较少,不利于后期维护
- 依赖高素质团队,新人难融入
- 大规模项目协调困难
- 进度和成本难以预测
3.8 统一过程(RUP / UP)
统一过程(Rational Unified Process,RUP)是由 Rational 公司(IBM)提出的一种用例驱动、以架构为中心、迭代和增量的软件开发过程框架。RUP 是一个可裁剪的过程框架,包含四个阶段和九个核心工作流。
1. 用例驱动:用例是需求获取、设计、测试、沟通的核心线索;
2. 以架构为中心:架构是项目骨架,为不同视角提供共同理解;
3. 迭代和增量:项目分解为多次迭代,每次迭代产生增量。
RUP 四个阶段
- 初始(Inception):确定项目范围与愿景,识别关键用例,估算成本与风险。里程碑:LCO 生命周期目标。
- 细化(Elaboration):分析问题域,建立稳健的架构基线,制定项目计划,淘汰高风险。里程碑:LCA 生命周期架构。
- 构造(Construction):开发所有组件和特性,集成形成产品。里程碑:IOC 初始运行能力。
- 移交(Transition):将产品移交用户,包括培训、安装、Beta 测试。里程碑:PR 产品发布。
RUP 九个核心工作流
- 工程类(6 个):业务建模、需求、分析与设计、实现、测试、部署
- 支持类(3 个):配置与变更管理、项目管理、环境
3.9 DevOps
DevOps 是 Development(开发)和 Operations(运维)的组合,强调开发、测试、运维的紧密协作,通过自动化实现持续集成(CI)、持续交付/部署(CD),从而缩短交付周期、提高发布质量。
· 持续集成(CI):开发人员频繁提交代码到主干,自动构建与测试;
· 持续交付(CD):自动将代码部署到类生产环境,可随时发布;
· 持续部署:自动将通过测试的代码部署到生产环境;
· 基础设施即代码(IaC):用代码管理基础设施;
· 监控与日志:实时监控运行状态,快速定位问题;
· 微服务与容器化:Docker + Kubernetes 是 DevOps 的基础设施。
3.10 开发模型对比总结
| 模型 | 核心特征 | 驱动方式 | 适用场景 |
|---|---|---|---|
| 瀑布模型 | 线性顺序,文档驱动 | 文档 | 需求明确稳定 |
| 增量模型 | 分批交付,逐步增加功能 | 需求优先级 | 核心功能可早交付 |
| 螺旋模型 | 迭代 + 风险分析 | 风险 | 大规模高风险项目 |
| 喷泉模型 | 迭代无间隙 | 对象 | 面向对象开发 |
| V 模型 | 开发与测试一一对应 | 测试 | 对测试严格要求的系统 |
| 快速原型 | 原型驱动,快速反馈 | 原型 | 需求不明确 |
| 敏捷开发 | 短迭代,拥抱变化 | 价值 | 需求多变、中小项目 |
| RUP | 用例驱动、架构为中心、迭代 | 用例+架构 | 大型复杂项目 |
| DevOps | 开发运维一体,自动化 | 自动化 | 互联网持续交付 |
· 需求明确、稳定 → 瀑布
· 风险高、规模大 → 螺旋
· 需求不明确 → 原型
· 核心功能优先 → 增量
· 面向对象 → 喷泉
· 测试严格 → V 模型
· 需求多变、小型 → 敏捷
· 大型统一过程 → RUP
· 持续交付、互联网 → DevOps
四、需求工程
需求工程(Requirements Engineering)是软件工程中最关键的阶段之一。研究表明,软件项目中约 40%~50% 的缺陷源于需求问题。需求工程不仅是"写下需求",而是一个包含获取、分析、规约、验证与管理的完整过程。
4.1 需求工程过程
需求工程五步骤
- 需求获取:通过访谈、问卷、观察、JAD 会议等方式从干系人收集需求
- 需求分析:对原始需求进行综合、提炼、建模,消除冲突与歧义
- 需求规约:将分析结果编写为软件需求规格说明书(SRS)
- 需求验证:通过评审、原型、形式化方法验证需求的正确性、完整性、一致性
- 需求管理:基线化、变更控制、版本管理、需求跟踪
4.2 需求的类型
| 类型 | 定义 | 举例 |
|---|---|---|
| 功能需求 | 系统"必须做什么"——输入、处理、输出 | 用户可以查询订单状态 |
| 非功能需求 | 系统"做得怎么样"——性能、可靠性、易用性、安全性 | 响应时间 < 200ms;可用性 99.9% |
| 设计约束 | 限制设计选择的条件(技术、标准、法规) | 必须使用 Oracle 数据库;遵守 GDPR |
| 接口需求 | 与外部系统的交互(用户接口、硬件、软件、通信) | 提供 RESTful API 给第三方 |
· "系统必须支持 1000 并发用户"——是非功能需求(性能);
· "系统必须用 Java 编写"——是设计约束,不是功能需求;
· "用户可以通过手机号登录"——是功能需求;
· "密码必须加密存储"——既是功能需求也是非功能需求(安全),需视语境判断。
4.3 需求分析方法
需求分析主要有两种方法:结构化分析(SA)和面向对象分析(OOA)。
| 维度 | 结构化分析(SA) | 面向对象分析(OOA) |
|---|---|---|
| 核心思想 | 功能分解,自顶向下 | 对象抽象,识别类与对象 |
| 建模工具 | DFD、数据字典、实体关系图、状态转换图 | 用例图、类图、顺序图、状态图(UML) |
| 关注点 | 数据流与功能 | 对象、属性、方法、关系 |
| 适用 | 数据处理类系统 | 复杂业务系统、面向对象开发 |
4.4 结构化分析与数据流图(DFD)
数据流图(Data Flow Diagram, DFD)是结构化分析的核心工具,用于描述系统内数据的流动与变换。DFD 有四种基本符号:
1. 外部实体(External Entity):系统外的人员、组织或系统,用矩形表示;
2. 加工(Process):对数据的处理,用圆形或圆角矩形表示;
3. 数据存储(Data Store):数据的保存处,用双横线或开口矩形表示;
4. 数据流(Data Flow):数据的流动,用带箭头的线表示。
DFD 是分层的,从顶层向下逐步细化:
- 顶层图(上下文图):把整个系统看作一个加工,只显示外部实体与系统间的数据流。
- 0 层图(Level 0):将顶层加工分解为若干主要加工。
- 1 层图(Level 1):继续细化每个 0 层加工。
- 更低层:直到每个加工足够清晰、可独立实现为止。
4.5 需求跟踪矩阵
需求跟踪矩阵(Requirements Traceability Matrix, RTM)是需求管理的核心工具,用于建立需求-设计-代码-测试之间的双向追溯关系。它确保每个需求都有对应的设计、实现和测试用例,避免需求遗漏。
| 需求 ID | 需求描述 | 设计模块 | 代码文件 | 测试用例 | 状态 |
|---|---|---|---|---|---|
| REQ-001 | 用户登录 | AuthService | auth.py | TC-101/102 | 已完成 |
| REQ-002 | 订单查询 | OrderService | order.py | TC-201/202 | 测试中 |
| REQ-003 | 报表导出 | ReportService | report.py | TC-301 | 设计中 |
五、软件设计
软件设计是将需求转化为软件结构的过程。它分为概要设计(高层架构与模块划分)和详细设计(模块内部算法与数据结构)。好的设计是高质量软件的基础。
5.1 软件设计过程
概要设计与详细设计
- 概要设计(HLD):将系统分解为模块,定义模块间接口与调用关系,确定数据结构、数据库模式、运行设计、出错处理。产出:概要设计说明书。
- 详细设计(LLD):为每个模块设计内部算法、数据结构、流程图、输入输出。产出:详细设计说明书,应能达到"程序员可直接编码"的精度。
5.2 结构化设计:模块化与内聚耦合
结构化设计的核心是模块化——将系统分解为若干相对独立的模块。衡量模块独立性的两个定性指标是内聚(Cohesion)和耦合(Coupling)。设计原则是:高内聚、低耦合。
· 高内聚:模块内部各元素彼此紧密结合,共同完成一个明确的任务;
· 低耦合:模块之间联系尽可能少,接口简单;
· 高内聚使模块功能明确、易理解、易复用;低耦合使模块独立性强,修改影响小。
5.2.1 内聚的七种类型(由低到高)
| 级别 | 类型 | 含义 | 举例 |
|---|---|---|---|
| 最低 | 偶然内聚 | 模块内各元素无实质联系,只是为节省代码而放在一起 | 一个工具函数同时打印日志、计算日期、读文件 |
| 低 | 逻辑内聚 | 模块内完成逻辑上相关的多种功能,由参数决定执行哪个 | print(type, data) 根据类型打印不同报表 |
| 中 | 时间内聚 | 模块内各功能在同一时间段执行 | 系统初始化函数同时打开文件、连接数据库、加载配置 |
| 中 | 过程内聚 | 模块内各功能按特定顺序执行,前后依赖 | 按顺序读取输入→校验→计算→输出的处理流程 |
| 中高 | 通信内聚 | 模块内各功能操作同一数据集,但顺序无依赖 | 同时计算学生总分和平均分(同一成绩数据) |
| 高 | 顺序内聚 | 前一功能的输出是后一功能的输入 | 读取数据→解析数据→保存数据 |
| 最高 | 功能内聚 | 模块所有元素共同完成一个单一、明确的功能 | 计算圆面积的函数 |
5.2.2 耦合的七种类型(由高到低)
| 级别 | 类型 | 含义 | 举例 |
|---|---|---|---|
| 最高 | 内容耦合 | 一个模块直接访问另一模块的内部数据或代码 | GOTO 跳入另一模块;修改另一模块的变量 |
| 高 | 公共耦合 | 多个模块共享同一个全局数据结构 | 多个模块读写同一全局变量 |
| 高 | 外部耦合 | 多个模块访问同一外部数据(如同一文件) | 多个模块都读写 config.txt |
| 中 | 控制耦合 | 模块间传递控制信息(如标志位)影响对方逻辑 | 传递 mode="admin" 决定走哪个分支 |
| 中低 | 标记耦合 | 模块间传递数据结构(记录) | 传递整个用户对象,但只用了几个字段 |
| 低 | 数据耦合 | 模块间只传递简单数据参数 | 传递 userId 字符串查询用户 |
| 最低 | 非直接耦合 | 模块之间无直接联系,通过主模块控制 | 两个独立模块由主程序分别调用 |
内聚由低到高口诀:"偶逻时过通顺功"(偶然-逻辑-时间-过程-通信-顺序-功能)
耦合由高到低口诀:"内公外控标数非"(内容-公共-外部-控制-标记-数据-非直接)
功能内聚最好,偶然内聚最差;非直接耦合最好,内容耦合最差。
5.3 面向对象设计原则(SOLID)
面向对象设计遵循五大原则,合称 SOLID:
| 缩写 | 原则 | 核心思想 |
|---|---|---|
| S | 单一职责原则(SRP) | 一个类应该只有一个引起它变化的原因 |
| O | 开闭原则(OCP) | 对扩展开放,对修改关闭 |
| L | 里氏替换原则(LSP) | 子类必须能替换父类且不影响程序正确性 |
| I | 接口隔离原则(ISP) | 客户端不应依赖它不需要的接口 |
| D | 依赖倒置原则(DIP) | 依赖抽象,不依赖具体;高层不依赖低层 |
5.4 软件设计度量
软件设计质量可通过一系列度量指标衡量:
- 模块扇入(Fan-In):有多少模块调用本模块。扇入大说明复用性高,是好事。
- 模块扇出(Fan-Out):本模块调用多少模块。扇出过大说明模块过于复杂,应适当分解。一般扇出 ≤ 7 为宜。
- 代码行数(LOC):模块代码行数,建议单模块不超过 100~200 行。
- McCabe 圈复杂度:见后文测试章节。
六、软件测试
软件测试是软件质量保证的重要手段,目标是发现缺陷并评估质量。测试不能证明软件无错,但能暴露已知问题。IEEE 将测试定义为"通过运行程序来观察、分析其行为以验证质量属性的过程"。
6.1 测试级别
软件测试分为四个层次,由低到高、由小到大:
| 级别 | 测试对象 | 执行者 | 关注点 |
|---|---|---|---|
| 单元测试 | 函数/方法/类 | 开发人员 | 内部逻辑、边界值、错误处理 |
| 集成测试 | 模块间接口 | 测试人员 | 接口、数据流、调用关系 |
| 系统测试 | 整个系统 | 测试人员 | 功能、性能、安全、兼容性 |
| 验收测试 | 用户视角 | 用户/客户 | 是否满足业务需求,是否可发布 |
集成测试的策略
- 自顶向下集成:从主模块开始,逐步集成下属模块,使用桩模块(Stub)模拟下层未实现模块。优点:早期验证主控逻辑。
- 自底向上集成:从底层模块开始,逐步向上集成,使用驱动模块(Driver)调用上层未实现模块。优点:底层模块测试充分。
- 三明治集成:结合自顶向下和自底向上,从两端向中间集成。
- 大爆炸集成(Big Bang):所有模块一次性集成。适用于小项目,缺点是错误定位困难。
6.2 测试方法
6.2.1 黑盒测试
黑盒测试将软件视为"黑盒",不考虑内部结构,仅根据需求规格说明设计测试用例。常用方法:
| 方法 | 核心思想 | 适用场景 |
|---|---|---|
| 等价类划分 | 将输入域划分为有效/无效等价类,每类选代表值 | 输入数据范围明确 |
| 边界值分析 | 测试边界及其附近的值(缺陷常出现在边界) | 数值范围、数组、日期 |
| 判定表 | 列出条件组合与对应动作的表格 | 多条件组合的复杂逻辑 |
| 因果图 | 用图表示输入条件(因)与输出(果)的关系 | 条件间存在约束关系 |
| 错误推测 | 凭经验列出可能出错的场景 | 补充测试用例 |
6.2.2 白盒测试
白盒测试基于程序内部结构和逻辑设计测试用例。常用的覆盖标准由弱到强为:
| 覆盖标准 | 含义 | 强度 |
|---|---|---|
| 语句覆盖 | 每条语句至少执行一次 | 最弱 |
| 判定覆盖(分支覆盖) | 每个判定的真假分支至少执行一次 | 弱 |
| 条件覆盖 | 每个条件的真假至少取一次 | 中 |
| 判定/条件覆盖 | 同时满足判定覆盖和条件覆盖 | 中 |
| 条件组合覆盖 | 每个判定中所有条件组合至少出现一次 | 强 |
| 路径覆盖 | 程序中所有可能路径至少执行一次 | 最强 |
· 语句覆盖 < 判定覆盖 < 条件覆盖 < 判定/条件覆盖 < 条件组合覆盖 < 路径覆盖
· 路径覆盖 > 条件组合覆盖 > 判定/条件覆盖 > 判定覆盖 ≈ 条件覆盖 > 语句覆盖
· 语句覆盖是最弱的,路径覆盖是最强的。
· 注意:条件覆盖不一定强于判定覆盖(二者侧重点不同),但条件组合覆盖一定强于二者。
6.3 McCabe 圈复杂度
McCabe 圈复杂度(Cyclomatic Complexity)用于衡量程序的逻辑复杂度,由 Thomas McCabe 提出。它基于控制流图计算,公式为:
V(G) = E - N + 2P
其中:
· E:控制流图的边数
· N:控制流图的节点数
· P:连通分量数(通常为 1,简化为 V(G) = E - N + 2)
另一种简化公式:V(G) = 判定节点数 + 1(适用于单入口单出口的程序)
· V(G) ≤ 10:简单,易测试
· 10 < V(G) ≤ 20:中等复杂
· 20 < V(G) ≤ 50:复杂,需重构
· V(G) > 50:极复杂,错误率高,必须重构
圈复杂度也代表了独立路径数,即至少需要的测试用例数。
6.4 测试驱动开发(TDD)
测试驱动开发(Test-Driven Development)是敏捷开发中的一种实践,由 Kent Beck 提出。其核心是"先写测试,再写代码",循环过程为:红-绿-重构。
TDD 三步骤循环
- 红(Red):编写一个会失败的测试用例,描述待实现的功能
- 绿(Green):编写最简单的代码使测试通过
- 重构(Refactor):在测试保护下改进代码结构,消除重复
6.5 案例:电商结算模块测试
案例背景
某电商平台结算模块负责计算订单最终支付金额。规则如下:
- 商品金额满 100 元打 9 折;满 500 元打 8 折
- 使用优惠券抵扣 20 元(订单金额需 ≥ 50 元才可用券)
- 运费:订单金额 ≥ 99 元免邮;否则 +10 元运费
- 会员等级折扣与商品折扣不叠加
测试设计(黑盒-等价类划分 + 边界值)
| 输入条件 | 有效等价类 | 无效等价类 | 边界值 |
|---|---|---|---|
| 商品金额 | 0 < x < 100;100 ≤ x < 500;x ≥ 500 | x ≤ 0;非数字 | 0, 1, 99, 100, 499, 500 |
| 是否用券 | 用券且 x ≥ 50;不用券 | 用券但 x < 50 | 49, 50, 51 |
| 是否会员 | 是会员;非会员 | — | — |
关键测试用例
| 用例 | 输入 | 预期输出 | 覆盖 |
|---|---|---|---|
| TC-1 | 金额=99,无券,非会员 | 99 + 10 = 109 | 边界值 |
| TC-2 | 金额=100,无券,非会员 | 90 + 0 = 90 | 折扣边界 |
| TC-3 | 金额=500,用券,非会员 | 400 - 20 + 0 = 380 | 折扣边界+券 |
| TC-4 | 金额=49,用券 | 提示:金额不足,不可用券 | 无效等价类 |
| TC-5 | 金额=50,用券,非会员 | 50 - 20 + 10 = 40 | 券边界 |
| TC-6 | 金额=200,无券,会员(8 折) | 160 + 0 = 160 | 会员折扣 |
· 边界值是缺陷高发区,0、99、100、500 必须覆盖;
· 等价类划分要包含无效等价类,验证系统的容错;
· 多条件组合使用判定表设计,避免遗漏组合;
· 白盒测试关注 if-else 分支覆盖,确保每个分支都被执行。
七、软件配置管理
软件配置管理(Software Configuration Management, SCM)是软件工程中用于标识、组织、控制修改的一组活动。其目标是建立和维护软件产品在整个生命周期中的完整性。
7.1 配置管理核心概念
1. 配置标识:识别配置项,命名、版本化;
2. 配置控制:变更的评估、审批、实施与记录;
3. 配置状态报告:记录并报告配置项的状态变化;
4. 配置审计:验证配置项是否符合需求与标准。
配置项(Configuration Item, CI)是配置管理的对象,包括:源代码、文档、数据、可执行程序、开发环境、第三方库版本等。
基线(Baseline)是经过正式评审和批准的配置项快照,作为后续开发的基准。基线一旦建立,变更必须通过正式的变更控制流程。
7.2 版本控制:SVN vs Git
| 维度 | SVN(集中式) | Git(分布式) |
|---|---|---|
| 架构 | 集中式,依赖中央服务器 | 分布式,每个克隆都是完整仓库 |
| 离线工作 | 不支持,必须连服务器 | 支持,本地可提交 |
| 分支 | 较重,复制目录 | 轻量,指针切换 |
| 速度 | 受网络影响 | 本地操作,快 |
| 权限控制 | 可按目录细粒度控制 | 仓库级,较粗 |
| 典型场景 | 企业内部、文档管理 | 开源、代码托管 |
7.3 变更控制流程
变更控制是配置管理的核心活动。任何对基线的修改都必须经过正式的变更控制流程,避免随意修改导致混乱。
1. 功能配置审计(FCA):验证配置项的实际功能是否符合需求;
2. 物理配置审计(PCA):验证配置项的物理形态(代码、文档)是否与基线一致。
八、软件质量保证
软件质量是软件满足明确或隐含需求的程度。软件质量保证(SQA)是一组系统化的活动,确保软件产品符合规定质量标准。
8.1 软件质量模型
ISO/IEC 9126 质量模型
ISO 9126 将软件质量分为六大特性(外层)和 21 个子特性:
| 质量特性 | 含义 | 子特性 |
|---|---|---|
| 功能性 | 满足明确和隐含需求的能力 | 适合性、准确性、互操作性、依从性、安全性 |
| 可靠性 | 在规定条件下维持性能的能力 | 成熟性、容错性、易恢复性 |
| 易用性 | 用户理解、学习、使用的难易 | 易理解性、易学性、易操作性 |
| 效率 | 资源使用与性能的关系 | 时间特性、资源特性 |
| 可维护性 | 修改的难易程度 | 易分析性、易改变性、稳定性、易测试性 |
| 可移植性 | 转移到新环境的能力 | 适应性、易安装性、遵循性、易替换性 |
软考易混点:功能性包含"安全性"(访问控制);可靠性包含"容错性"(出错后继续运行)和"易恢复性"(出错后恢复)。
McCall 质量模型
McCall 模型从三个视角定义 11 个质量因素:
- 产品运行视角:正确性、可靠性、效率、完整性、可用性
- 产品修改视角:可维护性、灵活性、可测试性
- 产品转移视角:可移植性、可复用性、互操作性
8.2 质量保证 vs 质量控制
| 维度 | 质量保证(QA) | 质量控制(QC) |
|---|---|---|
| 目标 | 预防缺陷,过程导向 | 发现缺陷,产品导向 |
| 关注点 | 开发过程是否符合规范 | 产品是否符合质量标准 |
| 手段 | 审计、评审、培训、标准制定 | 测试、检查、度量 |
| 时机 | 贯穿全生命周期 | 主要在测试阶段 |
| 执行者 | SQA 工程师 | 测试人员 |
8.3 软件评审与审查
软件评审是质量保证的重要活动,主要包括:
- 评审(Review):对文档、设计、代码的人工检查,发现缺陷。包括非正式评审和正式审查。
- 走查(Walkthrough):作者带领团队逐步走查文档,收集意见。
- 审查(Inspection):Fagan 提出的正式评审方法,有明确的角色(作者、主持人、读者、记录员、检查员)和流程,是最严格的评审。
8.4 CMM / CMMI 能力成熟度模型
能力成熟度模型集成(CMMI)是评估组织软件过程成熟度的标准。CMMI 分为五个成熟度等级:
| 等级 | 名称 | 特征 | 关键过程域 |
|---|---|---|---|
| 1 | 初始级(Initial) | 无序、依赖英雄主义 | 无 |
| 2 | 已管理级(Managed) | 项目级有规范,可重复 | 需求管理、配置管理、项目计划 |
| 3 | 已定义级(Defined) | 组织级标准过程 | 组织过程聚焦、培训、同行评审 |
| 4 | 量化管理级(Quantitatively Managed) | 用数据量化管理 | 组织过程性能、定量项目管理 |
| 5 | 优化级(Optimizing) | 持续改进、技术创新 | 组织创新与部署、原因分析与解决 |
· 等级 1 是"无序",等级 5 是"持续优化";
· 等级 3 是分水岭——从"项目级"到"组织级"的跨越;
· 等级 4 引入定量管理(数据驱动);
· 等级 5 强调持续改进与创新。
九、项目管理基础
软件项目管理是为了在约定的时间、成本、质量约束下完成软件产品而进行的一系列活动。PMBOK 将项目管理划分为 10 大知识领域。
9.1 项目三角形
项目管理有三大核心要素:范围、时间、成本,外加质量构成"项目铁三角"。三者相互制约,改变其一必然影响其他。
· 范围:项目要做什么
· 时间:完成需要多久
· 成本:投入多少资源
· 质量:达到什么标准
中心是质量。三角任一边变化都会影响其他两边,并最终影响质量。
9.2 项目管理十大知识领域
9.3 进度管理:甘特图与关键路径
甘特图(Gantt Chart)用横条表示任务的开始、结束和进度,直观但不反映任务间依赖关系。
PERT/CPM(关键路径法)用网络图表示任务及其依赖,找出决定项目最短工期的关键路径。关键路径上的任务延误会直接影响项目交付。
· 最早开始时间 ES:所有前置任务完成后最早能开始的时间
· 最早结束时间 EF = ES + 工期
· 最晚结束时间 LF:不影响总工期的最晚完成时间
· 最晚开始时间 LS = LF - 工期
· 总浮动时间 = LS - ES = LF - EF
· 关键路径:总浮动时间为 0 的路径(最长路径)
9.4 风险管理
风险管理包括风险识别、风险评估、风险规划和风险控制四个步骤。
| 风险类型 | 举例 | 应对策略 |
|---|---|---|
| 项目风险 | 人员流失、进度延误 | 规避、转移、减轻、接受 |
| 技术风险 | 新技术不成熟、架构错误 | 原型验证、技术评审 |
| 商业风险 | 市场需求变化、竞争 | 市场调研、灵活应变 |
十、实战案例:ERP 系统软件工程实践
下面以一个中型制造企业的 ERP 系统开发为例,完整演示软件工程各阶段如何落地。
项目背景
- 客户:某机械制造企业,员工 500 人,年营收 2 亿
- 目标:替换老旧的财务+进销存独立系统,建设一体化 ERP
- 模块:采购、库存、生产、销售、财务、人力资源
- 预算:300 万元;工期:12 个月;团队:15 人
- 约束:核心财务模块必须 6 个月内上线(影响年度审计)
10.1 模型选型
项目特点:规模较大、有明确核心模块优先上线要求、需求部分明确但部分需探索。综合考虑,采用增量模型 + 螺旋模型的混合策略:
- 整体:增量模型,分三期交付——第一期财务+库存核心,第二期采购+销售,第三期生产+人力
- 每个增量内部:使用螺旋模型,每轮迭代做风险分析,特别是技术风险(如与老系统数据迁移)
- 开发实践:采用 Scrum 管理 Sprint,配合 CI/CD 流水线
· 增量模型保证核心财务模块 6 个月上线,满足审计约束;
· 螺旋模型的风险分析应对数据迁移、老系统集成等不确定性;
· Scrum 的短迭代适应业务部门逐渐明确的需求;
· CI/CD 保证多模块并行开发的质量。
10.2 需求分析
需求工程采用用例驱动的面向对象分析方法:
- 需求获取:与财务部、采购部、生产部等干系人召开 JAD 会议,梳理业务流程
- 需求建模:绘制用例图、活动图、顺序图,明确 300+ 个用例
- 需求规约:编写 SRS,包括功能需求、非功能需求(如财务模块响应 <1s)、设计约束(必须用 Oracle)
- 需求验证:组织用户评审会,使用原型演示关键流程
- 需求管理:建立需求跟踪矩阵,每条需求对应设计模块、代码、测试用例
10.3 设计决策
| 设计决策 | 选择 | 理由 |
|---|---|---|
| 架构风格 | B/S + 分层 + 微服务 | 跨地域办公、独立部署 |
| 数据库 | Oracle(财务)+ MySQL(业务) | 财务要强一致性;业务要高性能 |
| 模块设计 | 高内聚低耦合 | 各模块独立部署、独立扩展 |
| 接口设计 | RESTful API + 消息队列 | 同步查询用 REST,异步事件用 MQ |
| 设计原则 | SOLID | 财务规则多变,需易扩展 |
10.4 测试策略
- 单元测试:开发人员编写 JUnit 测试,覆盖率 ≥ 80%,特别是财务计算逻辑
- 集成测试:自底向上集成,验证模块间接口(如采购→库存→财务的数据流)
- 系统测试:包括功能测试、性能测试(1000 并发)、安全测试(财务数据加密)
- 验收测试:用户参与,使用真实业务数据演练,包括数据迁移验证
- 回归测试:每次增量发布后,对已上线模块做回归,借助自动化测试
· 财务模块要求零缺陷上线,采用 V 模型——开发与测试一一对应;
· 数据迁移是高风险点,建立独立迁移测试环境;
· 老系统并行运行 3 个月,验证新系统稳定后才切换。
10.5 配置与质量管理
- 版本控制:Git + GitLab,分支策略采用 GitFlow
- 变更控制:成立 CCB,所有需求变更经评估后纳入下个 Sprint
- 质量保证:SQA 工程师每周审计过程文档;代码审查采用 Gerrit
- 持续集成:Jenkins 自动构建+测试,每天多次集成
十一、软考考点总结与真题
11.1 核心公式速记
1. McCabe 圈复杂度:V(G) = E - N + 2P (E 边数、N 节点数、P 连通分量数)
简化:V(G) = 判定节点数 + 1 (单入单出程序)
2. 关键路径:总工期 = 最长路径长度;总浮动 = LS - ES = LF - EF
3. 测试用例数下限:等于圈复杂度 V(G)
4. 软件维护占比:完善性 ≈ 50%、适应性 ≈ 25%、改正性 ≈ 20%、预防性 ≈ 5%
11.2 高频考点清单
| 章节 | 高频考点 |
|---|---|
| 开发模型 | 九种模型特征、优缺点、适用场景;螺旋模型=风险驱动;RUP=用例+架构+迭代;瀑布=文档驱动 |
| 需求工程 | 需求分类(功能/非功能/约束);DFD 四要素与分层;需求跟踪矩阵 |
| 软件设计 | 内聚七种(功能最好);耦合七种(非直接最好);高内聚低耦合;SOLID 五原则 |
| 软件测试 | 覆盖标准强弱排序;圈复杂度公式;黑盒/白盒方法;集成测试策略 |
| 配置管理 | SCM 四大功能;基线概念;CCB 变更控制;SVN vs Git |
| 质量保证 | ISO 9126 六特性;CMMI 五级;QA vs QC |
| 项目管理 | 项目铁三角;关键路径计算;十大知识领域 |
11.3 真题演练
真题 1(开发模型选择)
某大型企业信息系统项目,需求明确、技术成熟、规模较大,但对质量要求极高,希望每个阶段都有严格评审。最适合采用哪种开发模型?
A. 螺旋模型 B. 瀑布模型 C. 增量模型 D. 快速原型
解析:需求明确、技术成熟、要求严格评审,这是瀑布模型的典型适用场景。螺旋模型适用于高风险项目;增量模型适用于分批交付;快速原型适用于需求不明确。
真题 2(圈复杂度计算)
某程序控制流图有 16 条边、12 个节点、1 个连通分量。求该程序的圈复杂度 V(G),并说明至少需要多少个测试用例才能实现路径覆盖的下限。
解析:根据 McCabe 圈复杂度公式 V(G) = E - N + 2P,代入 E=16、N=12、P=1,得 V(G)=6。圈复杂度等于程序中独立路径数,因此至少需要 6 个测试用例才能覆盖所有独立路径(路径覆盖的下限)。该模块复杂度属于中等(V(G) ≤ 10),可测试性较好。
真题 3(内聚与耦合)
某模块内含若干功能:读取数据、校验数据、计算结果、保存结果、打印报表。这些功能按固定顺序执行,前一功能输出作为后一功能输入。该模块的内聚类型属于哪种?如果该模块还直接修改了另一模块的内部变量,则耦合类型属于哪种?
解析:
1. 模块内功能按顺序执行,前一输出是后一输入,符合顺序内聚的定义(高强度内聚,仅次于功能内聚)。
2. 直接修改另一模块的内部变量,属于内容耦合——最强的耦合类型,应坚决避免。改进方法:通过接口/方法调用传递数据,改为数据耦合。
11.4 记忆口诀汇总
· 开发模型选型:需求明→瀑布;风险高→螺旋;需求变→敏捷/原型;分批交→增量;面向对象→喷泉;测试严→V 模型
· 内聚由低到高:偶逻时过通顺功
· 耦合由高到低:内公外控标数非
· 白盒覆盖强弱:语判条判组路(语句<判定<条件<判定/条件<条件组合<路径)
· ISO 9126 六特性:功可易效维移
· CMMI 五级:初管定量化优(初始-已管理-已定义-量化管理-优化)
· RUP 三特征:用例驱动 + 架构为中心 + 迭代增量
· 维护四类占比:完善最占(50%),预防最少(5%)
11.5 总结
软件工程是系统架构设计师考试的核心基础,贯穿上午综合知识、下午案例分析、下午论文三大题型。本章覆盖了从需求到维护的完整生命周期,重点包括:开发模型的选型(每种模型的特征、优缺点、适用场景)、需求工程的 DFD 与需求跟踪、软件设计的内聚耦合、软件测试的覆盖标准与圈复杂度、配置管理的变更控制、质量保证的 CMMI以及项目管理的进度与风险。
1. 开发模型是每年必考,至少掌握 5 种模型的完整五要素;
2. 内聚/耦合的 7 种类型必须能排序 + 举例;
3. 圈复杂度公式必须能算会用,常出选择题;
4. CMMI 五级和 ISO 9126 六特性是背诵型考点,反复记忆;
5. 案例分析题常考需求变更管理、模型选型论证、测试用例设计,需结合实际场景作答;
6. 论文题若涉及软件工程,可围绕增量+敏捷的实践展开。
软件工程不是僵化的教条,而是一套权衡的艺术。架构师的价值在于根据项目特性,灵活选用合适的模型、方法和工具,在质量、成本、进度之间找到最佳平衡点。掌握了软件工程,就掌握了软件项目成功的"方法论"。