软件工程

概论

软件的定义:程序+文档

软件工程的目标:生成具有正确性、可用性、开销合宜的产品

  • 正确性:软件产品达到预期功能
  • 可用性:软件的基本结构、实现、文档为用户可用的程序
  • 开销合宜:软件的开发、运行的开销满足用户要求

软件工程活动:需求、设计、实现、确认、支持

  • 需求:系统模型、系统功能的精确、系统的描述
    • 需求验证:验证需求陈述和需求规约之间的一致性、完整性、可跟踪性
  • 设计
    • 总体设计:体系结构、子系统、模块、接口定义
    • 详细设计:每个模块的详细描述、数据结构说明、算法
  • 实现
  • 确认:贯穿于整个开发过程
    • 包括需求复审、设计复审、程序测试
  • 支持活动
    • 完善性维护、纠错性维护、适应性维护

软件生存周期:形成概念、历经开发、交付、修订、演化、淘汰

软件过程:过程是活动的集合,活动是任务的集合,任务是输入转换为输出的操作

关键过程分3类:

  1. 基本过程:与软件生产直接相关的活动集。又分为5个:
    • 获取过程:需方,定义客户要求,接受客户要求的产品
    • 供应过程:供方,
    • 开发过程:软件开发者(又包含13个活动)
    • 运行过程:系统操作者
    • 维护过程:维护者
  2. 支持过程:有关各方按其目标从事的一系列支持活动集。分为8个
    • 文档过程:为记录生存周期过程所产生的信息而定义的活动
    • 配置管理过程
    • 质量保证过程
    • 验证过程
    • 确认过程
    • 联合评审过程
    • 审计过程
    • 问题解决过程
  3. 组织过程:与软件生产组织有关的活动集
    • 管理过程
    • 基础设施过程
    • 改进过程
    • 人力资源过程
    • 资产管理过程
    • 复用程序管理过程
    • 领域软件工程过程

软件生存周期模型有哪些:

  1. 瀑布模型
  2. 增量模型
  3. 演化模型
  4. 喷泉模型

caption: 瀑布模型

瀑布模型

  • 要点
    • 按照固定顺序,连续而连接若干阶段工作
    • 规定每个阶段的输入、输出
    • 基于逻辑:如果上一阶段的输出是正确的,这一阶段也是正确的,那么输出也是正确的:
    • 正向流动、反向流动(返工)
  • 优点
    • 做之前有需求阶段,鼓励做之前对“做什么”做规约
    • 编码前有设计阶段,鼓励编码前设计
    • 每个阶段结束时复审,允许获取方和用户参与
    • 前一步的产品是下一步的基线,,允许基线和配置早期接受控制
  • 缺点
    • 客户必须完整、正确、清晰表达需求
    • 缺乏灵活性,如果需求有偏差,最终差评就会不满足需求
    • 早期的基线、里程碑花费很多时间
    • 直到项目结束之前,都不能演示系统的能力,增加了项目的风险

caption: 增量模型

增量模型

  • 在第一个版本需求确定的情况下
  • 每个增量都是一个瀑布模型
  • 优点:
    • 作为瀑布模型的变体,有其所有优点
    • 第一个可交付版本的成本和时间很少
    • 开发增量的风险不大
    • 由于很快有第一个版本,因此可以减小客户需求变更
    • 允许增量投资
  • 缺点
    • 没有对用户变更做规划,初始增量可能带来后来的增量不稳的哥
    • 需求不能在早期完善,某些增量可能要重新开发、重新发布
    • 管理成本、复杂性可能超出组织能力

caption: 演化模型

演化模型

  • 针对实现不能完整定义需求的情况
  • 针对用户的核心需求,开发核心系统
  • 根据用户反馈,实施活动的迭代

喷泉模型

  • 特点:不断迭代、每个阶段无缝
  • 面向对象

软件需求

需求的基本性质(来自IEEE标准830-1998)

  1. 必要性(Necessary)
  2. 无歧义(Unambiguous)
  3. 可测的(testable),可以对它测试吗
  4. 可跟踪的(Traceable)。从一个开发阶段到另一个开发阶段,可以跟踪吗
  5. 可测量(Measurable)

需求的分类

  • 功能需求
    • 必须执行的功能
    • 是整个需求的主体
  • 性能需求
    • 例如:处理实现、并发度、可支持的用户数量…
  • 外部接口需求:交互的硬件、软件、数据库。也可能是格式、时间等
    • 系统接口:描述应用与系统如何交互
    • 用户接口:与用户之间如何交互。
    • 硬件接口:与硬件设备的交互,
    • 软件接口:与软件的交互
    • 通讯接口:与通讯设备/局域网等的交互
    • 内存约束
    • 操作
    • 地点
  • 设计约束
    • 例如,必须用C++编写。内存消耗不超过50%。必须用红色、14点字体显示警告
  • 质量属性
    • 可靠性:正常运行
    • 存活性:某一部分不能运行时,软件继续运行/支持关键功能的可能性
    • 可维护性
    • 用户友好性:学习使用它的容易程度
    • 安全性
    • 可移植性

需求的发现

  • 自悟。需求人员知识丰富、想象力丰富。
  • 交谈:直接询问用户
    • 需求人员有“正确提出问题”能力,回答人员有“揭示需求本意”的能力
    • 风险,交谈期间需求不断增长,超出项目成本/时间。“完美蠕行”(Creeping elegance)
  • 观察。观察用户执行现在的任务,观察他们如何操作。
  • 小组会。客户与开发人员联席会议
    • 主持人的能力至关重要。必须仔细选择小组成员
  • 提炼:复审技术文档
  • 综合运用

需求规约(SRS,Software Requirements Specification)

  • 性质:
    • 重要性和稳定性。是基本需求、可选的需求、期望的需求。
    • 可修改:修改某一部分需求,不会过多影响其它需求
    • 完整:没有被遗漏的需求
    • 一致:没有互斥的需求
  • 功能,需要考虑的问题:
    • 功能源
    • 功能共享的数据
    • 功能与外部界面的交互
    • 功能所使用的计算资源

需求规约的格式(IEEE 830-1998)

1. 引言
    1.1 目的
    1.2 范围
    1.3 定义、缩略语
    1.4 参考文献
    1.5 概述(项目范围)
2. 总体描述
    2.1 产品概述
    2.2 产品功能
    2.3 用户特性
    2.4 约束
    2.5 假设和依赖
3. 特定需求
附录
索引

其中的“3. 特定需求”是文档的技术核心,有一些模版:

  1. 根据系统运行模式
  2. 根据用户类
  3. 按对象
  4. 根据系统层
  5. 根据激发
  6. 按功能层次
  7. 根据用户类、功能、特征
  8. 其它

需求规约的作用

  • 软件开发组织和用户之间,事实上的技术合同
  • 对于项目大多数工作,一个管理控制点
  • 对于产品设计,一个正式、受控的起始点
  • 基于它,还产生两个文档:初始测试计划,用户系统操作描述

初始测试计划:对未来系统哪些功能和性能进行测试,以及达到何种要求

  • 作用:早期发现错误,改正的代价小很多

用户系统操作描述:一份初步的用户手册

  • 软件开发早期,使未来用户从使用角度检查
  • 书写这个文档,迫使从用户角度考虑软件系统
  • 不是设计文档
  • 不是进度文档,不是规划文档。不给出项目成本、交付进度、开发方法、质量保证、验收、安装等信息

结构化分析方法

结构化方法包括

  • 结构化分析方法
  • 结构化设计方法
  • 结构化程序设计方法

需求分析的目标:

  • 解决需求陈述中的歧义、不一致的问题
  • 作为开发人员和客户间技术契约的基础
  • 给出问题的形式化或半形式化的描述

工具:

  • DFD图
  • 数据字典
  • 加工小说明

caption: DFD图

caption: 数据字典

caption: 判定表盒判定树


需求分析的输出:XXX系统需求规格说明书

        XXX系统需求规格说明书
1. 引言
  1.1 编写目的
    说明编写本需求规格说明书的目的
  1.2 背景说明
    (1) 给出待开发的软件产品的名称;
    (2) 说明本项目的提出者、开发者及用户;
    (3) 说明该软件产品将做什么,如有必要,说明不做什么。
  1.3 术语定义
  1.4 参考文献
2. 概述
  2.1 功能概述
    叙述待开发软件产品将完成的主要功能。
  2.2 约束
    叙述对系统设计产生影响的限制条件,并对下一节中所述的某些特殊需求提供理由,如管理模式、硬件限制、安全等。
3. 数据流图与数据字典及加工说明
    3.1 数据流图
      3.1.1 数据流图
        (1) 画出该数据流图
        (2) 加工说明
        (3) 数据流说明
      3.1.2 数据流图2
    3.2 数据字典
      3.2.1 文件说明
      3.2.2 数据项说明
4. 接口
  4.1 用户接口
  4.2 硬件接口
  4.3 软件接口
5. 性能需求
  5.1 精度
    逐项说明对各项输入数据和输出数据达到的精度
  5.2 时间特征
    定量说明本软件的时间特征,如响应时l、咖吨更,处数据传输、转换时间、计算时间等。
  5.3 灵活性
    说明本软件所具有的灵活性,即当用户需求有某些变化时(如操作方式、运行环境、时间特征等),本软件的适应能力。
6. 属性
  6.1 可使用性
    规定某些需求,如检验点、恢复方式和重启动性,以确保软件可使用。
  6.2 保密性
    规定保护软件的要素
  6.3 可维护性
  6.4 可移植性
7.其他需求
  7.1 数据库
  7.2 操作
  7.3 故障及处理

结构化设计

目标:依据需求规约,在一个抽象层上建立系统软件模型,包括软件体系结构(数据和程序结构),详细的处理算法,产品设计规格说明书。

分为

  • 总体设计。具体任务是:把 DFD 转化为 MSD
    • 体系结构设计(MSD):定义软件模块极其之间的关系
    • 接口设计:外部接口设计、内部接口设计
      • 外部接口:用户界面,与其它硬件、软件的接口
      • 内部接口:系统内各元素之间的接口
    • 数据设计:根据数据字典确定文件结构、数据库表结构
  • 详细设计

caption: 结构化设计

caption: MSD

总体设计的3个阶段:

  1. 初始设计:根据数据流图,转化为初始模块结构图。
  2. 精化设计:“高内聚低耦合”原则,设计全局数据结构和每个模块的接口
  3. 设计复审:复审,精化。

变换设计的步骤

  1. 设计准备:复审、精化系统模型
  2. 确定输入、变换、输出的边界
  3. 第一级分解
  4. 自顶向下分解

DFD分为2种:变换型、事务型。

caption: 变换型DFD转MSD

caption: 事务型DFD转MSD


模块化

  • 为什么?
    • 如果 C(x) 代表 x 的工作量
    • 人们发现 C(p1 + p2) > C(p1) + C(p2)
  • 随着模块的增长,模块总工作量下降。但是集成它们的工作量增长。

高内聚低耦合

caption: 耦合

耦合类型 不同模块之间互相依赖程度。强到弱:

  1. 内容耦合:一个模块直接修改、操作另一个模块的数据
  2. 公共耦合:两个以上模块共同饮用一个全局数据项
  3. 控制耦合:一个模块A向另一个模块B传递控制信号,B根据信号进行活动
  4. 标记耦合:两个模块通过界面传递公共参数(复杂数据类型,如数组、字符串)
  5. 数据耦合:模块之间通过参数传递基本类型的数据

内聚:同一个模块各成分之间的互相依赖程度。从低到高:

  1. 偶然内聚:同一个模块内各成分没有任何关系
  2. 逻辑内聚:同一个模块内,几个逻辑上相关的功能
  3. 时间内聚:同一个模块内,功能必须在同一个时间内完成的
  4. 过程内聚:同一个模块内,必须以特定次序执行
  5. 通信内聚:同一个模块内,都在操作同一数据集/生成统一数据集
  6. 顺序内聚:同一个模块内,都与一个功能相关,并且一个成分输出是另一个成分的输入
  7. 功能内聚:同一个模块内,所有成分对完成单一功能是最基本的,且该模块对完成这一功能而言是充分必要的

启发式规则:长期实践中总结的经验。不是设计目标,也不是必须遵循的原理。

  1. 改进软件结构,提高模块独立性
    • 例:多个模块的公用的字功能,可以单独拆成一个模块
  2. 模块规模适中-每页60行
    • 心理学:语句多于30个之后,可理解性快速下降
  3. 深度(结构图的深度)、宽度(结构图的宽度)、扇入(多少个上级模块调用它,越大越好)、扇出(一个模块调用下级模块的数量,太大说明过于复杂,太小说明过度集中一般为3、4个)适中
    • 好的系统:顶层扇出多,中层扇出少,底层扇出高。“葫芦型”
  4. 模块的作用域力争在控制域内
    • 作用域:A模块影响的所有模块。控制域:直接+简洁从属于A模块的模块集合
  5. 降低模块接口的复杂性
    • 尽量用简单的参数来传递
  6. 模块功能应该可以预测
    • 什么是“功能可预测”?相同的输入,获得相同的输出。
    • 什么模块不可预测?模块带有内部状态,它的输出取决于内部状态。

接口设计

  1. 模块或软件构件之间的接口设计
  2. 软件与其它软硬件系统之间的接口设计
  3. 软件与人之间的交互设计

人机交互界面

  • 需要了解的信息
    • 用户界面应具有的特性
    • 使用软件的用户是什么人
    • 用户怎样学习与你的系统交互
    • 用户需要完成哪些工作
  • 用户界面应该具备的特性
    • 可使用性。使用简单、有help帮助、快速的系统响应、低系统成本(不要求高配置)、容错
    • 灵活性。满足不同用户。
    • 可靠性。无故障使用。
  • 用户类型:外行、初学、熟练、专家
  • 界面设计类型,从以下方面考察:
    • 使用的难易程度
    • 学习的难易程度
    • 操作速度
    • 复杂程度
    • 控制:人机交互时,由计算机还是人发起控制对话
    • 开发难易程度
  • 界面设计的原则
    • 一致性
    • 操作步骤少
    • 不要“哑播放”:运行中的提示音、反馈,不然用户觉得死机了。
    • 提供 undo 功能
    • 减少人脑记忆负担
    • 提高学习效率

数据设计

  • 文件
    • 数据量较大的非结构化数据,如多媒体
    • 数据量大,信息松散,如历史记录、档案文件
    • 非关系层次化数据,如配置文件
    • 对数据的读写要求极高
    • 临时存放的数据
  • 数据库
    • 数据对象的映射
    • 关系的映射

详细设计

程序化程序设计:仅通过三种控制结构(顺序,选择,循环)连接,并且每个代码只有一个入口和一个出口

表达方式

  • 伪代码(PDL,Program Design language)
    • 优点:可以直接作为注释插入到源代码,保持文档和程序一致性,提高文档质量
    • 缺点:
      • 不如图形工具直观
      • 复杂逻辑下,与实际的动作不能清晰对应
  • 程序流程图
    • 优点:直观,便于初学者掌握
    • 缺点:
      • 不是逐步求精工具,过早考虑控制流,而不是全局结构
      • 控制流可以不受约束随意转移
      • 不表示数据结构
  • PAD图(Problem Analysis Diagram)
    • 优点:支持自顶向下逐步细化。
    • 每个细化都有竖线,使其有层次
  • N-S图
    • 支持自顶向下逐步细化
    • 严格限制转移
  • 判定表和判定树

caption: 流程图

caption: PAD图

caption: N-S图


概要设计:面向软件开发者,作为项目管理人员、系统分析人员、设计人员之间的交流媒介

  • 系统环境:
    • 硬件接口、软件接口、人机界面
    • 数据库
    • 设计有关的限制条件
  • 设计描述
    • 数据流和主要数据结构
    • 软件模块的结构
    • 模块之间的接口
  • 每个模块的描述
    • 处理过程外部行为
    • 界面定义
    • 数据结构
    • 必要的注释
  • 文件结构和全局数据

详细设计:软件设计人员与程序员之间的媒介。内容除了概要设计之外,还包括:

  • 各处理过程的算法
  • 全部数据结构

软件设计说明书

1. 引言
    1.1 编写目的
        说明编写本软件设计说明书的目的
    1.2 背景说明
        (1)待开发的软件产品名称
        (2)本项目的提出者、开发者、用户
        (3)该软件将做什么,不做什么(如有必要)
    1.3 术语定义
        本文档所用术语的定义等
    1.4 参考资料
2. 总体设计
    2.1 需求规定
        对本软件的主要输入、输出、处理的功能和性能要求
    2.2 运行环境
        本软件的软件环境、硬件环境、支持环境的要求
    2.3 处理流程
        本软件的处理流程,尽量用图、文、表的形式
    2.4 软件结构
        在DFD图基础上,用模块结构图说明各模块之间的关系
3. 运行设计
    3.1 运行模块的组合
        说明对系统施加不同的外界运行控制,引发不同的运行模块组合。说明每种运行所经历的内部模块和支持软件
    3.2 运行控制
        说明各运行控制方式、方法、具体操作步骤
4. 系统出错处理
    4.1 简要说明每种可能的出错,或者,故障出现时系统输出信息的格式和含义
    4.2 出错处理方法和补救措施
        故障出现后的措施,包括
        (1)后备技术。例如周期性备份
        (2)性能降级。使用另一个效率较低的系统和方法
        (3)恢复和再启动
5. 模块设计说明
    填写模块说明表,给出模块的一下内容:
    (1)模块的一般说明:名称、编号、设计者、所在文件、所在库、调用本模块的模块名、本模块调用的模块名
    (2)功能概述
    (3)处理描述,使用伪代码描述本模块的算法、计算公式、步骤
    (4)引用格式
    (5)返回值
    (6)内部接口。内部各接口之间的关系,包括:名称、意义、数据类型、有效范围、I/O标志
    (7)外部接口。与其它软、硬件的接口,包括:名称、意义、数据类型、有效范围、I/O标志、格式、媒体
    (8)用户接口。名称、意义、数据类型、有效范围、I/O标志、格式

软件设计评审

  • 非正式评审、正式技术评审
  • 概要设计评审和详细设计评审分开进行
    • 概要设计评审,评价从需求到设计数据和体系结构的变换
    • 详细设计评审,注重算法的正确性
  • 建立日常
  • 评审设计文档,而不是设计者
  • 评审中提出的问题应详细记录,不谋求当场解决
  • 限制参与人数:开发人员、用户代表、领域专家(如有必要)
    • 详细设计评审一般不要求用户和领域专家
  • 设计文档上有检查表,以帮助评审人员集中在重要问题上

  • 为提高评审效率,评审参加者要经过正规培训
  • 评审结束前,应做出是否通过的结论

一个概要设计的检查表(例子):

  • 软件体系结构是否满足需求
  • 达到高的模块化了吗
  • 模块与外部接口定义了吗
  • 数据结构与软件需求一直吗
  • 考虑可维护性了吗
  • 是否直接评价了质量因素

一个详细设计的检查表(例子):

  • 算法能完成要求的功能吗
  • 算法逻辑正确吗
  • 接口与体系结构设计一致吗
  • 逻辑的复杂性合理吗
  • 是否规定了错误处理和反故障处理?
  • 正确定义了局部数据结构吗

UML

面向对象

  • 一种程序开发方法
  • 还是一种方法论
    • 如何看待软件系统与现实世界的关系
    • 以什么观点求解
    • 如何进行系统构造

面向对象的主要特点

  1. 从客观存在出发,构造软件系统
    • 客观事物抽象为 对象
    • 事物的静态特征用 属性 表示
    • 事物的动态特征(行为)用 操作 表示
  2. 属性和操作结合起来,构成独立实体,对外屏蔽细节:封装
  3. 具有相同属性和操作的对象抽象为:
  4. 不同程度的抽象,得到更一般的类、更特殊的类,它们是 继承 关系
  5. 复杂对象可以用简单的对象组成:组合
  6. 对象之间只能通过 消息 进行通信。(不允许直接访问另一个对象的属性)
  7. 类之间的静态关系:关联

PS:现代编程语言不推荐继承,原因:

  1. 继承带来强耦合,父类的改动,会影响所有的子类
  2. 继承会被新手误用为“代码复用”工具,如果没有“A1 is A” 的关系而继承,只会导致糟糕的设计。例子:FileUploader 继承 HHTPClient
  3. 继承破坏封装性。子类可以访问父类成员。
  4. 继承违反了很多经典的软件工程原则:
    • LSP里氏替换原则:子类不能安全替换父类
    • SRP 单一职责:子类被迫拥有父类一堆功能
    • OCP 开闭原则:修改父类会影响所有子类;不够“关闭”
    • ISP 接口分离:子类被迫接收父类的不需要接口

基本类目

caption: UML-类

(class)

  • 类名:
    • 首字母大写
    • 居中
    • 可以用包名/限定名等,例如 com.guofei.MyClass
    • 抽象类用斜体
  • 属性。格式:[可见性]属性名[:类型][多重性][=初始值][{特性}]
    • 可以有多个属性,也可以没有属性。
    • 左对齐
    • 可见性:+ 公有的(其它类可以使用),# 受保护的(子类可以使用),- 私有(只有本类可以私用),~ 同一个包内的类可以使用。也可以使用关键字 public, protected, private, package 表示
    • 属性名:小写字母开头
    • 类型
    • 多重性:值的个数范围
    • 初始值
    • 性质串,例如 a:int=1{frozen} 表示不可改变
  • 操作。格式 [可见性]操作名[(参数表)][:返回类型][{性质串}]
    • 可见性。同“属性”
    • 属性名:通常是动词。小写开头,其它字母是大写
    • 斜体表示抽象
    • 可以有多个操作,也可以没有操作。

接口(interface)

  • 通过声明一个接口。表明提供一个所需要的,与实现无关的行为。
  • 接口只描述外部可见的操作,不描述内部结构
  • 接口没有实现。接口没有属性。接口只有操作
  • 接口等价于一个没有属性、没有方法,只有抽象操作的抽象类。
  • 接口不能访问其它类

caption: UML-interface的表示

caption: UML-interface的举例

caption: UML-interface的使用(简化版)


协作:(collaboration)用虚线椭圆表示

  • 一组类、接口等的集合,它们共同工作,完成行为

caption: UML-协作

caption: UML-协作2


用况(use case):一组动作序列的描述

caption: UML-用况


主动类(active class):并发行为,用来启动控制

caption: UML-主动类


构件(component)

caption: UML-构件

制品(artifact)

caption: UML-制品

节点(node)

caption: UML-节点

包、关系

是模型元素的一个分组

  • 有可见性,+(其它包可见),-(其它包不可见),#(仅子孙包可见),与前面类似
  • 包可以嵌套

包之间的关系有2种:

  1. 访问依赖
  2. 引入依赖(import)

caption: UML-包


关系

  • 关联(association)
    • 无箭头的实线
  • 泛化(generalization)
    • 空心三角箭头的实线
    • 表示 is-a-kind-of 关系
  • 实现(realization,细化)
    • 空心三角箭头的虚线
    • 常见于接口与实现之间,用况和实现之间
  • 依赖(dependency)
    • 箭头虚线
    • 描述一个事物使用另一个事物的信息和服务

UML 模型表达工具

6个对“系统静态部分”建模的图形工具:

  1. 类图
  2. 构件图
  3. 组合结构图
  4. 对象图:一组对象之间的关系
  5. 部署图:节点上生存的制品和配置
  6. 制品图:一组制品以及依赖关系

7种“系统动态部分”建模图形工具:

  1. 用况图:需求模型
  2. 状态图:对象行为比较复杂时,用它描述对象的状态和状态转移
  3. 活动图:注重活动到活动的控制流(并发),或者描述对象之间的协作,或者描述用户的业务流程
  4. 顺序图:注重消息的时间次序
  5. 通信图:注重收发消息。可以表示一组对象之间的交互情况。
  6. 交互概观图:描述系统宏观行为,是活动图+顺序图
  7. 定时图:展现实际时间,而不是仅时序

caption: UML-类图

caption: UML-用况图

用况图,包括:

  • 主题、用况、参与者、依赖、泛化、关联

caption: UML-顺序图

顺序图

  • 包含内容
    • 交互各方:角色、对象
    • 交互方式:同步、异步
    • 交互内容:消息
  • 一些说明
    • 对象生命线
    • 消息
      • 异步消息:枝形箭头
      • 同步消息:实心三角箭头
      • 同步消息的回复:枝形虚线箭头
    • 控制结构:选择执行(opt)、条件执行(alt)、并发执行(par)、迭代执行(loop),等等

caption: UML-顺序图-控制结构


状态图(State Machine Diagram)

caption: UML-状态机图

caption: UML-状态

caption: UML-状态转移

状态可以嵌套

正交子状态:并发执行的子状态

  • 分岔:转移到“正交区域”时,控制流分为多个并发流
  • 汇合:从“正交区域”离开时,它们汇合

caption: UML-正交子状态

UML中,可模型化的4种事件

  1. 信号 signal
  2. 调用 call
  3. 时间事件和变化事件
  4. 发送事件和接受事件

caption: UML-信号

caption: UML-调用、事件

状态转移

caption: UML-状态转移

面向对象分析(OOA)

面向对象分析(OOA):认识问题域,分析它们,最终产生一个需求层的面向对象模型

识别

  • 研究问题域、用户需求、确定系统边界。阅读相关材料、交流、调研、咨询专家等
  • 方法
    • 可以发现的对象:人员、组织、物品、设备、抽象事物、事件、文件等
    • 考虑边界。边界为是人员、设备、软件,之后可以设计它们的接口
    • 考虑系统责任。检查每一项需求是否有相应的对象提供,发现新的对象
  • 检查与审查
    • 舍弃无用的对象。
      • 通过属性判断。是否通过属性记录了有用的信息?
      • 通过操作判断。是否通过操作提供了有用的功能?
    • 精简对象
      • 只有一个属性的对象:考虑合并到其它对象中
      • 只有一个操作的对象:同上
    • 与显示条件有关的对象:推迟到 OOD
      • 例如:GUI、数据库、硬件、操作系统相关对象
  • 识别主动对象
    • 考虑问题域和系统责任:哪些对象有主动行为?
    • 从需求考虑并发执行:控制线程的起点在哪?
    • 考虑系统边界之外的参与者,它与系统中哪个对象直接交互?
  • 对象分类,建立类图
    • 对象分类
    • 检查与调整:
      • 分类是否足够详细?例如,“汽车”类有“乘客限量”属性,但货车不需要这个属性。这就需要额外建个“货车”类
      • 是否可以合并?例如,“吸尘器”和“电子琴”都作为商品销售,考虑合并为一个类
      • 属性、操作相似的类。轿车和货车,抽取一个“汽车”类
      • 同一事物的重复描述。“职员”与“工作证”

识别 属性

  • 方法
    • 按常识,这个对象有哪些属性?
    • 当前问题域中,对象应该有哪些属性?
    • 根据系统责任,这个对象应具有哪些属性?
    • 建立这个对象,是为了保存、管理哪些信息?
    • 对象为了实现操作,需要哪些属性?
      • 如,传感器对象,需要“事件间隔”来设置定期采样,需要“临界值”来判断是否告警
    • 对象是否需要某个属性,来描述其状态?
      • 如,设备对象,需要一个状态来描述关闭、待机、运行、故障
    • 用什么属性表示聚合和关联
  • 审查与筛选
    • 属性是否以系统责任为目标。图书管理系统,书的封面颜色就不用了
    • 是否描述对象本身的特征。错误的:课程-老师的电话号码
    • 是否破坏对象的“原子性”。通信地址,把xx市xx区单独拆分出来就没有意义。
    • 是否可以通过继承得到
    • 是否可以从其它属性导出
  • 现实条件有关的问题推迟到OOD阶段
    • 规范化问题。OOA的属性可以是任意类型,数据类型规范化放OOD中
    • 对象标识问题。与编程语言有关。
    • 性能问题。为了提高执行速度,增加一些属性。
  • 属性的命名
  • 属性的详细说明:注释、数据类型

识别 操作

  1. 区分对象行为的类型
    • 系统行为:创建、删除、复制、转存
    • 对象自身的行为:简单操作(读、写),复杂操作(计算、监控)
  2. 如何发现操作
    • 考虑系统责任
    • 考虑问题域
    • 对象状态的改变,需要哪些操作
    • 模拟操作执行路线
  3. 审查与调整
    • 审查每个操作:是否真的有用
    • 是不是高内聚:一个操作完成一个单一的、完整的功能。否则,考虑拆分、合并
  4. 对象的主动行为
    • 考虑问题域。行为是被引发的,还是主动的。
    • 与边界之外的活动中直接交互的对象操作
    • 根据系统责任观察系统功能的层次,外层的对象操作
    • 操作执行路线追踪
  5. 操作的命名和定位
    • 动词、动宾结构
    • 与事物一致:售货员-售货,商品-售出
  6. 详细说明
    • 文字解释
    • 操作名、输入输出、参数类型
    • 消息发送
    • 约束条件
    • 操作流程

识别 对象之间的关系

泛化(继承)

  • 识别
    • 分类学知识、常识
    • 分析集合关系、观察一个类是否具有另一个类的全部特征
    • 考察属性和操作。看看是否适合这个类的所有对象(否则考虑拆分),看看是不是两个类的属性和操作完全相同(合并)
    • 考虑复用
  • 审查与调整
    • 问题域是否需要这样的类?
    • 是否符合常识 is-a-kind-of
    • 是否构成继承关系:确实继承了属性和操作
  • 简化:过多的类、过深的继承,都会提高系统复杂性
    • 重点:删掉不必要的特殊类。
    • 类的差别用属性值体现。例如:“男人、女人、中国人、美国人、日本人、…”,用“人”代替,增加“性别”、“国籍”属性
    • 删掉单一用途的类,减少继承层次
    • 调整对象层、特征层

关联

聚合

依赖

面向对象设计(OOD)

目标:

  1. 提高软件生产率
  2. 提高质量:没有错误(而不是事后排错),好用、易用、可移植、易维护、用户满意
  3. 加强可维护性:易变部分和稳定部分隔离
    • 易变性:服务 > 接口 > 属性 > 类

问题域部分-实现条件

  1. 变成语言
  2. 精简、操作系统、网络设施
  3. 复用支持
  4. 数据管理系统
  5. UI

人机交互

为什么?

  1. 隔离GUI变化的影响
  2. 人机交互部分相对独立

如何做

  • 从 use case 抽取人机交互内容

控制驱动部分


数据管理部分


编程实现

敏捷开发

理念:推崇让客户满意、软件早期增量发布、小而高度自主的项目团队、非正式的方法、最小化软件工程产品、整体精简开发。强调超越分析和设计的发布,开发人员与客户之间主动和持续的沟通

敏捷联盟

  • 个体和交互【胜过】过程和工具
    • 人是获得成功的最重要的因素
    • 一个优秀的团队成员,其合作、沟通、交互能力比单纯的编程能力更重要
    • 合适的工具对成功很重要,(但不过分夸大)
    • 团队的构建比环境的构建重要得多
  • 可以工作的软件【胜过】面面俱到的文档
    • 没有文档的软件是灾难,但过多的文档更糟糕
    • 对于团队,需要编写并维护一份系统原理和结构方面的文档
  • 客户合作【胜过】合同谈判
    • 成功项目依赖有序、频繁的客户反馈。而不是合同、工作陈述
    • 能指导双方协同工作的合同才是优质合同
  • 响应变化【胜过】遵循计划
    • 响应变化的能力往往决定软件项目成败
    • 计划无需考虑过远
    • 建议计划策略:为下两周做详细计划,下三个月做粗略计划,更长期做极粗略计划

敏捷原则

  1. 最优先要做的是:通过尽早地、持续地交付有价值的软件来使客户满意。一获取有质量软件的理念
  2. 即使到了开发后期,也欢迎改变需求。敏捷过程利用变化来为客户创造竞争优势。一关于态度的声明
  3. 经常交付可工作的软件,其时间间隔可以是几周到几个月。交付的时间间隔越短越好。一项目规划的理念(涉及如何处理文档和软件项目 开发之间的关系)
  4. 在整个项目开发期间,业务人员和开发人员必须天天在一起工作。一团队组成和精神问题
  5. 不断激励开发人员,开展项目的有关工作。给他们提供所需要的环境和支持,并信任他们能够完成所承担的工作。一 “领导” 的含义 - 涉及管理功能
  6. 在团队内部,最有效果的、最有效率的传递信息的方法,就是面对面的交谈。一获取开发信息 (需求、技术信息和项目信息等) 的途径
  7. 首要的进度度量标准是工作的软件。一进度度量的理念
  8. 敏捷过程提倡可持续的开发速度。责任人、开发者和用户 应该能够保持一个长期的、恒定的开发速度。一项目 “持续发展” 的能力
  9. 不断关注优秀的技能和设计,增强敏捷能力。一提高敏捷能力的一种途径
  10. 简单是根本的一使未完成的工作最小化的艺术
  11. 最好的体系结构、需求和设计,出自自己组织的团队。一团队观念 —- 种软件项目管理的理念
  12. 每隔一段时间,团队对如何才能有效的工作进行反省,然后对自己的行为进行适当的调整。一自我调整和适应

极限编程(eXtreme Programing,XP)是敏捷方法中最显著的一个。

极限编程实践

  1. 客户作为团队成员。应当寻找可以代表真正客户、并可一起工作的人
  2. User Stories
  3. 短的交付周期。两周一次迭代
  4. 验收测试
  5. 结对编程
  6. 测试驱动开发。先写单元测试,由于功能还没有,它一定会运行失败;然后编写功能代码,使其测试通过。
  7. 集体所有权
    • 每个结对,都有权 checkout 任何模块
    • 没有谁对特定模块/技术单独负责
    • 每个人都对每个模块负责(GUI/中间件/数据库)
  8. 持续集成。可以每天多次集成,要保证所有测试通过

极限编程模块:策划、设计、编码、测试


敏捷设计

为什么?为了避免以下问题

  1. 僵化性(Rigidity):难以改动,一个改动会导致连锁变化
  2. 脆弱性(Fragility):改动一个地方,导致许多其它地方都可能出现问题
  3. 粘固性(Immobility):一个部分,被别的部分用到,并且难以分离出来
  4. 粘滞性(Viscosity):
    • 软件粘滞:面临一个改动,保存系统一致很困难,很容易采用一些破坏性的方法
    • 环境粘滞:环境迟钝和低效。例如编译时间长
  5. 不必要的复杂性(Needless Complexity)。导致难以理解,也就是过分设计
  6. 不必要的复制(Needless Repetition)。重复代码极多
  7. 晦涩性(Opacity):模块难以理解,而且随着演化更难理想。好的代码能持续保持清晰。

软件测试

分类

  • 静态分析。不实际运行代码,而是分析源码,发现“死代码”、无限循环、未初始化的变量、未使用的数据、重复定义的数据等。
  • 动态测试。输入测试用例,执行软件。分为功能性测试(黑盒测试),结构测试(白盒测试)

什么是错误?

  • 软件未达到产品说明书标注的功能
  • 软件出现产品说明书指明的错误
  • 软件功能超出软件说明书的范围
  • 软件未达到产品说明书未指出,但应达到的目标
  • 软件测试人员认为软件难以理解、不易使用、运行速度缓慢,或者最终用户认为不好

白盒测试 知道产品内部工作过程,测试内部动作是否按照规格说明书规定正常进行。

  • 路径测试(PX),执行所有的控制路径。(最强的覆盖,一般难以实现)
  • 语句覆盖(P1),每个语句都至少覆盖执行一次。(最弱的覆盖)
  • 分支测试(P2),每个分支至少执行一次(比P1稍强)
  • 条件组合,每个判定中所有可能的条件取值都要覆盖到。(比P2稍强)

测试关键路径

  • 主要功能路径
  • 没有功能的路径
  • 最短路径

黑盒测试:已知产品应该有的功能,把程序看作一个不能打开的黑盒子,测试功能是否正常。

  • 方法
    • 等价类划分
    • 边界值分析:选取合法值边界上的值作为测试用例。
    • 因果图
    • 错误推测
  • 发现的错误类型:
    • 功能不对、功能遗漏
    • 界面错误
    • 数据结构错误、外部数据库访问错误
    • 性能错误
    • 初始化和终止错误

软件测试的步骤

  1. 单元测试。白盒测试为主
  2. 集成测试。目标是发现与接口有关的错误
  3. 确认测试。目标是发现软件与需求不一致的错误。黑盒测试为主。
  4. 系统测试。集中检验所有元素(软硬件)之间的协作是否合适
    • 功能测试
    • 恢复测试。强制让软件出错,然后检验其恢复能力
      • 如果是自动恢复,观察重新初始化、检测点、数据恢复等正确性
      • 如果是人工干预恢复,估算平均修复时长,是否在可接受范围内
    • 安全性测试。
    • 强度测试。非正常数量、频率、容量资源下运行
    • 性能测试。
    • 可用性
    • 部署测试。多种平台/操作系统

项目管理

什么是项目?为创造一件独特的产品/服务/结果而进行的临时性努力

  • 有独特的目的
  • 临时性
  • 逐步细化
  • 需要不同领域的资源
  • 有一位主要客户/项目发起人
  • 项目有不确定性

项目干系人:所有相关人员,包括发起人、项目组、协助人员、顾客、供应商、甚至项目反对者。

9个知识领域

  • 4个核心:
    • 项目范围管理
    • 项目时间管理
    • 项目成本管理
    • 项目质量管理
  • 4个辅助:
    • 人力资源管理
    • 沟通管理
    • 风险管理
    • 采购管理
  • 项目整体管理

CMM

CMM(the Capability Maturity Model for software)

软件维护

软件交付后,软件维护过程开始。

软件维护的工作量占整个软件生存周期工作量的70%以上。

软件维护的分类

  1. 改正性维护。改正隐藏的错误
  2. 适应性维护。随着外部环境变化(如,新的硬件配置、操作系统、输出输出方式、存储介质、网络环境),而做适配性维护
  3. 完善性维护。软件使用过程中,用户提出的新的需求(功能上的、性能上的)。
  4. 预防性维护。为了提高软件的额可维护性、可靠性,为接下来的改良打好基础。

软件再工程

  • 文档重构。遗留软件中的劣质文档
    • 保持现状:如果软件正在走向寿命的终点,就保持现状
    • 使用时重构:不重构全部文档,而是对正在改变的部分建立完整文档
    • 完全重构:如果软件是业务的关键,设法精简、重构所有文档
  • 逆向工程。针对多年前的软件,文档缺失/质量不佳,重新理解各个部分。
  • 代码重构。原代码质量很差
  • 正向工程。用新的方法论,重写整个软件。
    • 原因:
    • 维护旧代码的成本,远高于新开发(可能是20-40倍)
    • 采用现代的方法论,使其未来维护成本大大降低
    • 老版本已经存在,新开发的效率远高于平均
    • 用户已有使用软件的经验,容易确定需求/新需求/未来需求变化方向
    • 再工程自动化工具,可以进一步提高效率
    • 已经完成的预防性维护,可以提供部分成果(程序、文档、数据结构)
    • 典型案例:把古老的大型机系统,转为 C/S 结构

其它

以下笔记来自【清华大学】刘强:《软件工程》

持续进行的需求管理

行动 产出
需求获取 会议记录等
需求分析 分析模型
需求规格说明 需求规格说明书
需求验证 已确认的需求规格说明书

团队建设

  1. 进度管理
    • 每周一晚8:00召开小组讨论会,地点在xxx。主要内容是进展、心得、遇到的问题和风险
    • 每周三、五团队集中开发
    • 每次集中开发前矩形10分钟站立会议。报告开发进度、困难。
    • 周报(或需求管理系统)提交到系统
  2. 团队管理
    • 记分方式记录成员参与度,每次参加加1分。
    • 周会应当简洁,每人事先准备。轮流做会议纪要
  3. 团队建设
    • 鼓励写技术博客
    • 达到阶段目标时,请大家pizza party

需求提取:

  • 5W2H
  • 1:card
    • As a 【user】,I want 【function】,so that 【value】
    • As a 【role】,I want 【feature】,because 【reason】
    • As a 【role】,I can 【feature】
    • As a 【role】,I want 【feature】,so that 【reason】
  • 2:conversation

敏捷开发 原因是互联网时代的特点决定的:

  1. 小bug可以容忍,但是时间很重要,早一天发布可能结果完全不同
  2. 客户需求是无法在一开始定下的,往往先有了软件,才有了需求
  3. 即使是已经做完的app,也要经常更新,否则也会失败

参考资料



您的支持将鼓励我继续创作!