软件工程笔记
王老师软件工程课笔记
Part I 绪论
1、软件危机的定义
-
软件规模增长,复杂度增加,导致超预算、完成脱期、质量下降。
-
可靠性随规模增长而下降。
2、软件危机的成因
-
维护费用急剧上升,占软件总费用的大部分,包括纠错性维护、适应性维护和完善性维护。
-
软件技术进步缓慢;软件复杂度增长,而生产方式仍是手工;早期个人自由化开发的软件难以维护。
3、软件工程的范畴
-
软件开发技术:包括开发方法学、开发工具、软件工程环境。
-
软件工程管理:包括软件管理学、软件度量学、软件经济学。
4、3种编程范式
-
过程式编程范式:程序 = 数据结构 + 算法,自顶向下逐步求精,如
Pascal,难以维护。 -
面向对象编程范式:数据及操作封装于对象中,强调对象与消息。
-
基于构件技术的编程范型:通用的可复用组件,支持跨平台运行。
5、三代软件工程的区别
-
传统软件工程:结构化分析、结构化设计、面向过程编码与测试。
-
面向对象的软件工程:OO
分析、对象提取、详细设计、面向对象编码与测试。 -
基于构件的软件工程:领域分析、构件设计、建立可复用构件库,按构件集成模型开发。
Part II 生命周期与过程
1、软件生命周期
软件从立项开始到废止为止,大致分为计划、开发和运行三个时期。
典型的软件生存周期包括:
1 | 需求分析 → 软件分析 → 软件设计 → 编码 → 测试 → 运行维护 |
2、传统软件过程模型
瀑布模型(Waterfall Model)
-
阶段顺序执行,前一阶段完成后才能进入下一阶段。
-
各阶段有明确输出,作为下一阶段输入。
-
推迟实现:逻辑设计与物理实现分离。
-
质量保证:每个阶段需编写文档并复审。
快速原型模型(Prototyping Model)
-
先建立一个符合用户初步需求的原型系统。
-
用户通过原型明确需求,开发者根据反馈改进。
-
是获取真实需求的一种有效方法。
增量模型(Incremental Model)
-
瀑布模型与快速原型模型的结合。
-
软件被划分为多个增量,每个增量独立完成开发。
-
每次迭代交付一个可运行的子系统。
螺旋模型(Spiral Model)
-
在瀑布模型和快速原型模型基础上演变而来。
-
每个周期包含:计划 → 风险分析 → 建立原型 → 用户评审。
-
适用于大型复杂软件项目。
构件集成模型(Component Integration Model)
-
将数据和操作封装为对象,称为"类"。
-
设计和实现的类可作为构件,具有通用性和复用性。
-
构件存入构件库,供后续开发使用。
3、构件集成模型的特点
-
使用预先封装好的构件来构造应用软件系统。
-
融合了螺旋模型的特性,支持迭代开发。
-
软件开发与构件开发可并行进行,主要用于面向对象开发。
4、统一过程(RUP)
统一过程(Rational Unified Process)是一种迭代式软件开发过程。
四个阶段:
-
初始阶段:判定项目是否可行。
-
细化阶段:用例细化、风险分析、生成系统框架。
-
构造阶段:识别剩余用例,进行迭代开发与质量检测。
-
迁移阶段:验收产品,制作用户文档,部署上线。
每个阶段分为若干次迭代,每次迭代包含多个工作流:
1 | 需求 → 分析 → 设计 → 实现 → 测试 → 维护 |
5、软件可行性研究
-
目的:判断待开发项目是否值得进行。
-
内容:包括经济可行性、技术可行性、运行可行性和法律可行性。
Part III 结构化分析与设计
1、结构化分析与设计的任务
-
建立系统的分析模型。
-
编写《软件需求规格说明书》。
2、结构化分析的指导思想
-
抽象:忽略与目标无关的细节,提取关键特征。
-
分解:将复杂系统分解为若干子系统,逐步细化。
3、SA模型的构成
结构化分析(SA)模型以 数据字典 为核心,主要包括:
-
实体联系图(ER图):描述数据对象及其关系。
-
数据流图(DFD):描述系统中数据的流动和处理过程。
-
状态转换图(STD):描述系统状态的变化及控制逻辑。
数据流图(DFD)基本符号
-
圆框:表示加工(处理)。
-
方框:表示数据源点或终点。
-
箭头:表示数据流向。
-
双杠:表示数据文件或数据库。
4、SD模型的结构
结构化设计(SD)模型包括以下四个方面:
-
体系结构设计:定义系统的整体结构。
-
接口设计:定义模块之间的接口。
-
过程设计:定义每个模块的算法逻辑。
-
数据设计:定义数据结构。
5、从DFD图到SC图的过程
-
变换型结构:由传入路径、变换中心和传出路径组成。
-
事务型结构:包含一条接受路径、一个事务中心和若干条动作路径。
6、优化SC图的原则
-
合理划分模块,保持模块独立性。
-
遵循"高扇入,低扇出"的原则。
7、模块设计与结构化设计的关系
-
模块设计是结构化设计的细化。
-
目的是为SC图中的每个模块确定算法和内部数据结构。
-
使用合适的表达工具(如流程图、N-S图)进行描述。
8、模块设计的原则和方法
-
清晰第一的设计风格。
-
使用结构化的控制结构(顺序、选择、循环)。
-
采用逐步细化的实现方法。
9、流程图与N-S图
-
流程图:用菱形表示判定,箭头表示控制流向。
-
N-S图(纳-萨图):用矩形框表示控制结构,无箭头,结构更清晰。
Part IV 面向对象与UML
1、面向对象的基本特征
面向对象方法的核心特征包括:
-
抽象:提取对象的共性,忽略与当前目标无关的细节。
-
封装:将数据与操作封装在对象内部,隐藏实现细节。
-
继承:子类继承父类的属性和方法,实现代码复用。
-
多态:同一操作作用于不同对象时表现出不同的行为。
2、UML图的分类
UML(统一建模语言)图分为两大类:
静态图(结构图)
-
用例图(Use Case Diagram)
-
类图(Class Diagram)
-
对象图(Object Diagram)
-
构件图(Component Diagram)
-
部署图(Deployment Diagram)
动态图(行为图)
-
状态图(State Diagram)
-
活动图(Activity Diagram)
-
时序图(Sequence Diagram)
-
协作图(Collaboration Diagram)
3、UML视图
UML提供了多种视图,用于从不同角度描述系统:
-
用例视图:描述系统功能需求。
-
逻辑视图:描述系统内部的逻辑结构。
-
进程视图:描述系统的并发和同步机制。
-
构件视图:描述系统的物理构件组织。
-
部署视图:描述系统在物理节点上的部署情况。
4、UML的应用
UML广泛应用于软件开发的各个阶段:
-
描述系统需求(用例图)。
-
建立静态模型(类图、对象图)。
-
描述系统行为(状态图、活动图、时序图)。
5、用例图与用例模型
参与者(Actor)
指与系统交互的外部实体,可以是人或其他系统。
用例(Use Case)
表示系统提供的一个完整功能,通常是一个业务流程。
用例规约
对用例的详细描述,包括前置条件、后置条件、主事件流、备选事件流等。
用例之间的关系
-
包含关系(include):一个用例包含另一个用例的行为。
-
扩展关系(extend):一个用例在特定条件下扩展另一个用例。
-
泛化关系(generalization):子用例继承父用例的行为。
6、动态建模
时序图(Sequence Diagram)
-
描述对象之间的交互顺序。
-
强调消息发送的时间顺序。
协作图(Collaboration Diagram)
-
描述对象之间的交互关系。
-
强调对象之间的链接和消息传递。
区别
-
时序图强调时间顺序。
-
协作图强调对象之间的结构关系和交互链接。
Part V 需求工程与需求分析
1、什么是需求
需求是软件系统必须满足的条件或能力,包括:
-
用户需求:用户为达成特定目标所期望的系统功能。
-
业务需求:组织或客户为实现业务目标所需的功能。
-
功能需求:系统必须提供的具体功能。
-
非功能需求:如性能、安全性、可靠性、可用性等。
需求通常以合同、规范、说明书等形式明确下来。
2、需求工程(Requirements Engineering)
需求工程是指采用有效的技术和方法,使用合适的工具和符号,对目标系统的需求进行:
-
获取
-
分析
-
描述
-
验证
-
管理
其目标是确保开发出满足用户真实需求的软件系统。
3、需求分析的步骤
需求分析通常包括以下几个步骤:
-
需求获取:通过与用户交流、调研、观察等方式收集需求。
-
需求建模:使用模型(如用例图、ER图、DFD图)对需求进行抽象和描述。
-
需求描述:编写《软件需求规格说明书》(SRS)。
-
需求验证:检查需求的完整性、一致性、可行性和可验证性。
-
需求管理:对需求变更进行控制与跟踪。
4、软件需求规格说明书(SRS)
SRS 是需求分析阶段的主要文档,内容包括:
-
功能需求
-
非功能需求
-
系统接口
-
用户界面
-
数据需求
-
运行环境
-
假设与依赖
SRS 是后续设计、开发、测试和验收的依据。
5、需求分析的目标
-
明确系统必须做什么。
-
为系统设计提供基础。
-
为项目验收提供标准。
-
降低开发风险,避免需求变更带来的成本增加。
Part VI 面向对象分析
1 面向对象分析的核心
面向对象分析(OOA)以 用例模型 为主体,建立以下三类模型:
-
类-对象模型:描述系统静态结构。
-
对象-关系模型:描述对象之间的关联、依赖、泛化等关系。
-
对象-行为模型:描述对象的动态行为、状态变化及交互过程。
2 分析类的三种原型
根据职责不同,将分析阶段识别的类划分为三种原型:
1 | 负责系统与外部参与者之间的交互,如 GUI、API、打印接口等。 |
3 分析过程概要
-
根据用例图识别参与者和用例。
-
为每个用例绘制时序图(或协作图),确定消息流与所需对象。
-
从时序图中提取边界类、控制类、实体类。
-
建立类图:定义类属性、操作及类间关系(关联、泛化、依赖)。
-
建立状态图(可选):描述实体类对象的生命周期。
-
持续验证模型与需求的一致性,迭代求精。
4 类-对象模型示例要素
-
类名:名词,首字母大写;尽可能使用业务术语。
-
属性:类所维护的信息,可见性可暂时省略。
-
操作:从用例行为或消息序列中抽象出的职责。
-
关系:
-
关联(Association):对象间的连接,可注明多重性。
-
泛化(Generalization):继承关系,子类继承父类特征。
-
依赖(Dependency):临时、单向使用关系。
-
5 对象-行为模型补充
-
用 状态图 描述单个实体类对象的状态转换事件。
-
用 活动图 描述用例或控制类的业务流程。
-
用 时序图/协作图 细化对象间交互顺序与消息。
6 分析阶段交付物
-
用例模型(用例图 + 用例规约)。
-
类图(含边界类、控制类、实体类及其关系)。
-
关键动态图(时序图、状态图、活动图)。
-
分析模型说明书(可选,用于正式评审)。
Part VII 面向对象设计
1 设计目标
面向对象设计(OOD)在分析模型基础上,定义:
-
如何构造系统;
-
如何组织类与对象;
-
如何满足非功能需求(性能、复用、可扩展、可维护等)。
2 模块与信息隐藏
1 | 具有明确定义的输入、输出和功能的程序实体,如类、包、构件。 |
3 模块独立性度量
1 | 衡量模块内部元素彼此结合的紧密程度。\ |
4 设计任务总览
面向对象设计分为两大层次:
4.1 系统架构设计
-
高层架构设计:选择分层、MVC、微服务、客户端/服务器等总体结构。
-
确定设计元素:将分析类映射为设计类、包、子系统、构件。
-
任务管理策略:多线程/进程模型、并发控制、事务策略。
-
分布式机制:远程方法调用、消息队列、服务发现等。
-
数据存储方案:关系数据库、对象-关系映射、NoSQL、文件系统。
-
人机界面设计:界面框架、交互流程、可视化控件选型。
4.2 系统元素详细设计
-
类/对象设计:细化属性、操作签名、可见性、算法框架;应用设计模式。
-
子系统设计:定义子系统接口与协作契约,降低耦合。
-
包设计:按功能、层次、复用原则划分包,控制包间依赖。
5 类设计常用原则
-
单一职责原则(SRP):一个类只负责一项职责。
-
开闭原则(OCP):对扩展开放,对修改关闭。
-
里氏代换原则(LSP):子类应能替换父类而不影响正确性。
-
依赖倒置原则(DIP):依赖抽象,而非具体实现。
-
接口隔离原则(ISP):客户端不应被迫依赖不用的接口。
6 设计模式速览
-
创建型:Singleton、Factory Method、Abstract
Factory、Builder、Prototype。 -
结构型:Adapter、Bridge、Composite、Decorator、Facade、Flyweight、Proxy。
-
行为型:Observer、Strategy、Template
Method、Command、Iterator、State 等。
在详细设计阶段,可借助模式提高复用性与可维护性。
7 设计模型交付物
-
细化类图(属性、操作、可见性、设计模式标注)。
-
包图与子系统图(层次、接口、依赖)。
-
关键动态图(时序图、协作图、状态图、活动图)。
-
数据模型(类-表映射、ORM 配置、索引策略)。
-
界面原型与交互说明(可选)。
-
《软件设计说明书》(SDS)。
Part VIII 编码与测试
1 编码原则
-
清晰第一:程序应易于阅读与理解。
-
简洁直接:避免过度技巧与冗余逻辑。
-
遵循团队编码规范(命名、缩进、注释、文件组织)。
-
持续重构:保持代码"坏味道"最低。
2 测试基本概念
-
定义:为发现错误而执行程序的过程。
-
特点:
-
挑剔性:测试只能证明程序有错误,不能证明无错误。
-
复杂性:输入空间、执行路径、并发状态极大。
-
不彻底性:无法穷尽所有情况。
-
经济性:在有限成本下尽可能暴露高价值缺陷。
-
3 测试级别(V模型对应)
-
单元测试(Unit Testing)
-
集成测试(Integration Testing)
-
确认测试(Validation Testing)
-
系统测试(System Testing)
-
验收测试(Acceptance Testing)
4 测试方法分类
4.1 静态分析(不执行程序)
-
静态分析器:自动检查语法、类型、安全漏洞、编码规范。
-
代码评审:走查(Walkthrough)、审查(Inspection)、结对评审。
4.2 动态测试(执行程序)
-
黑盒测试:基于需求规格,不关心内部结构。
- 等价类划分、边界值分析、决策表、因果图、状态测试、场景测试。
-
白盒测试:基于程序内部逻辑结构。
- 逻辑覆盖:语句覆盖、判定覆盖、条件覆盖、判定/条件覆盖、条件组合覆盖、路径覆盖。
5 逻辑覆盖强度等级(由弱到强)
-
语句覆盖(Statement Coverage)
-
判定覆盖(Branch Coverage)
-
条件覆盖(Condition Coverage)
-
判定/条件覆盖(Branch/Condition Coverage)
-
条件组合覆盖(Multiple Condition Coverage)
-
路径覆盖(Path Coverage)
6 测试用例设计模板
- 用例编号、测试项、优先级、前置条件、输入、操作步骤、预期结果、实际结果、是否通过、备注。
7 回归测试与自动化
-
每次修改后重新执行已有测试,防止引入新缺陷。
-
对稳定模块编写自动化测试脚本(单元、接口、UI),形成持续集成流水线。
8 调试(Debugging)
-
目标:定位并消除已发现错误的根源。
-
常用策略:断点、单步、打印日志、回溯分析、二分定位、因果推理。
9 测试交付物
-
测试计划(Test Plan)
-
测试用例与脚本(Test Case / Script)
-
缺陷报告(Bug Report)
-
测试总结报告(Test Summary Report)
当时还是2023年秋天。
