结构化设计方法
Created: 2023-03-27 Mon 13:36
设计 是一项核心的工程活动。
在20世纪90年代早期, Lotus 1-2-3 的发明人 Mitch Kapor 在 Dr. Dobbs 杂志上发表了 软件设计宣言 ,其中指出:
什么是 设计 ?
设计是你站在两个世界 —
技术世界 和人类的 目标世界 ,
而你尝试将这两个世界 结合 在一起……
罗马建筑批评家 Vitruvius 提出了这样一个观念:
设计良好的建筑应该展示出 坚固 、 适用 和令人 赏心悦目 。
%%{init: { 'theme': 'neutral', 'fontFamily': 'KaiTi' }}%%
graph LR
S["设计良好的软件"] --> A["坚固"] --> A_["程序应不含任何对其功能有障碍的缺陷"]
S --> B["适用"] --> B_["程序需符合开发的目标"]
S --> C["赏心悦目"] --> C_["使用程序的体验应是愉快的"]
@startuml
skinparam defaultFontName Times New Roman, KaiTi
left to right direction
title 从设计良好的建筑来思考好的软件应具备的属性
node 设计良好的软件
设计良好的软件 -[#red]-> 坚固
设计良好的软件 -[#green]-> 适用
设计良好的软件 -[#blue]-> 赏心悦目
坚固 -[#red]-> 程序应不含任何对其功能有障碍的缺陷
适用 -[#green]-> 程序需符合开发的目标
赏心悦目 -[#blue]-> 使用程序的体验应是愉快的
@enduml
Figure 1: 从设计良好的建筑来思考好的软件应具备的属性
- 依据什么准则将软件系统 划分 成若干独立的成分?
- 在各个不同的成分内,功能细节和数据结构细节如何 表示 ?
- 用什么标准可对软件设计的技术质量做统一的
衡量 ?
分而治之 是人们解决 大型复杂问题 时通常采用的策略。
尽管模块分解可以简化要解决的问题,但 模块分解并不是越小越好 。
Figure 2: 模块大小、模块数目与成本的关系
模块独立性 是指软件系统中 每个模块 只涉及软件要求的具体的 子功能 , 而与软件系统中 其他模块 的 接口 是 简单 的。
若一个模块只具有 单一的功能 且与其他模块没有太多的联系, 我们则称此模块具有 模块独立性 。
参与人数 | 0 |
---|---|
高度内聚、松散耦合的模块 | 0 |
低度内聚、紧密耦合的模块 | 0 |
抽象 是指 忽视 一个主题中与当前目标 无关 的方面, 以便更充分地 注意 与当前目标 有关 的方面。
当我们进行软件设计时,设计开始时应尽量提高软件的抽象层次, 按 抽象级别 从 高 到 低 进行软件设计。
过程抽象 和 数据抽象 是两种常用的抽象手段。
复用 是指同一事物 不做修改 或 稍加修改 就可以 多次重复使用 。
在构造新的软件系统时不必从零做起, 可以直接使用 已有的 软构件 即可组装(或加以合理修改)成新的系统。
保证软件 灵活性设计 的关键是 抽象 。
理想情况下,一个系统的任何 代码 、 逻缉 、 概念 在这个系统中都应该是 唯一 的, 也就是说 不存在重复的代码 。
结构化软件设计 的主要任务是要解决 如何做 的问题,
要在
需求分析 的基础上建立各种 设计模型 ,
并通过对设计模型的 分析 和 评估 ,来确定这些模型 是否能够满足需求 。
在软件设计阶段,往往存在 多种设计方案 , 通常需要在多种设计方案之中进行 决策 和 折中 , 并使用选定的方案进行后续的开发活动。
可从 管理 和 技术 两个不同的角度来认识 设计阶段 及 设计内容 。
Figure 3: 设计阶段及设计内容
%%{init: { 'theme': 'forest', 'fontFamily': 'Times New Roman, KaiTi' }}%%
flowchart LR
S>"软件设计阶段(工程管理的角度)"]
S ==> A["概要设计阶段"]
S ==> B["详细设计阶段"]
subgraph G1["概要设计阶段任务"]
direction TB
R["软件需求"] --> Q1("概要设计") --> D1["数据结构"]
Q1 --> D2["软件的系统结构"]
end
subgraph G2["详细设计阶段任务"]
direction TB
D["结构表示"] --> Q2("详细设计") --> E1["详细的数据结构"]
Q2 --> E2["算法"]
end
A -.- G1
B -.- G2
Figure 4: 软件设计阶段(工程管理的角度)
%%{init: { 'theme': 'forest', 'fontFamily': 'Times New Roman, KaiTi' }}%%
flowchart LR
B>"软件设计内容(技术的角度)"] ==> BA["结构化设计方法"]
B ==> BB["面向对象设计方法"]
subgraph G1["概要设计阶段"]
BAA["体系结构设计"]
BAB["接口设计"]
BAC["数据设计"]
end
subgraph G2["详细设计阶段"]
BAD["过程设计"]
end
BA --> BAA
BA --> BAB
BA --> BAC
BA --> BAD
BB --> BBA["体系结构设计"]
BB --> BBB["接口设计(人机交互设计)"]
BB --> BBC["数据设计"]
BB --> BBD["类设计"]
BB --> BBE["构件设计"]
Figure 5: 软件设计内容(技术的角度)
结构化分析 的结果为 结构化设计 提供了最基本的 输入 信息。
Figure 6: 结构化设计与结构化分析的关系
Figure 7: 软件结构的形成
(从软件需求分析到软件设计的过渡)
一个软件系统通常由很多模块组成, 结构化程序设计中的 函数 和 子程序 都可称为 模块 , 它是 程序语句 按 逻辑关系 建立起来的组合体。
Figure 8: 模块的表示
如果一个软件系统,
- 全部 实际加工 (即 数据计算 或 处理 )都由
原子模块 来完成,- 其他所有 非原子模块 仅仅执行 控制 或 协调 功能,
这样的系统就是 完全因子分解 的系统,完全因子分解的系统被认为是 最好的系统 。 但实际上,这只是我们力图达到的目标,大多数系统做不到完全因子分解。
Figure 9: 模块的分类
模块结构 最普通的形式就是 树状结构 和 网状结构 。
Figure 10: 模块的树状结构和网状结构
参与人数 | 0 |
---|---|
树状结构 | 0 |
网状结构 | 0 |
- 在软件模式设计时,建议采用 树状结构 , 但往往可能在最底层存在一些 公共模块 (大多数为 数据操作模块 ), 使得实际软件的模块结构 不是 严格意义上的 树状结构 ,这属于正常情况。
- 不加限制的 网状结构 ,由于模块间相互关系的 任意性 , 使得整个结构十分 复杂 ,处理起来势必引起许多麻烦。 这与原来划分模块以便于处理的意图相矛盾。
所以在软件开发的实践中,人们通常采用 树状结构 ,而不采用 网状结构 。
结构图(structure chart, SC) 是精确表达 模块结构 的图形表示工具。
它不仅严格地定义了各个模块的 名字 、 功能 和 接口 , 而且还集中地反映了 设计思想 。
有些结构图中模块间的调用关系将 箭头 简单地画为 连线 , 这时只要调用与被调用模块的 上下位置 保持就是允许的。
- 为了表示在模块之间传递的 数据 或 控制 信息, 在联结模块的箭头旁边给出 短箭头 ,并且
- 用尾端带有 空心圆 的短箭头表示 数据信息 ,
- 用尾端带有 实心圆 的短箭头表示 控制信息 。
- 通常在短箭头附近应注有 信息的名字 。
Figure 11: 模块间的调用关系和接口表示
在结构图中,这种
- 条件调用 所依赖的 条件 和
- 循环调用 所依赖的 循环控制条件
通常都 无需注明 。
Figure 12: 条件调用和循环调用的表示
Figure 13: 结构图示例
Figure 14: 典型的数据结构
基于数据流的设计方法 可以很方便地将 数据流图 中表示的 数据流 映射成
软件结构 。
Figure 15: 基于数据流方法的设计过程
- 典型的数据流类型有 变换型数据流 和 事务型数据流 , 数据流的类型不同,得到的系统结构也不同。
- 通常,一个系统中的所有数据流都可以认为是 变换 流,
- 但是,当遇到有明显事务特性的数据流时,建议采用 事务 型映射方法进行设计。
Figure 16: 变换型数据流
Figure 17: 变换型系统结构图
完成选择分派任务的部分叫做 事务处理中心 ,或 分派部件 。
Figure 18: 事务型数据流
事务型数据流图所对应的系统结构图就是 事务型系统结构图 。
Figure 19: 事务型系统结构图
Figure 20: 简化的事务型系统结构图
事务型系统结构图在 数据处理 中经常遇到, 但是更多的是 变换 型与 事务 型系统结构图的结合。
例如,变换型系统结构中的某个 变换 模块本身又具有 事务 型的特点。
设计人员应当根据 数据流图 的 主要问题类型 , 选择一个 面向全局的 ,即涉及整个软件范围的问题处理类型。 此外,在 局部范围 内是 变换 型还是 事务 型,可 具体研究 ,区别对待。
- 在 需求分析阶段 得到的数据流图侧重于描述 系统如何加工数据 ,
- 而 重画数据流图 的出发点是描述 系统中的数据是如何流动的 。
在这一步,可以暂时 不考虑 数据流图的一些支流,例如 错误处理 等。 根据经验, 几股数据流汇集 的地方往往是系统的 中心变换 部分。
Figure 21: 数据流图中的输入、中心变换与输出部分
- 逻辑输入 是离 物理输入 端 最远 的但 仍被看作系统输入 的 数据流 ;
- 逻辑输出 是离 物理输出 端 最远 的但 仍被看作系统输出 的 数据流 。
自顶向下 设计的关键是找出 系统树形结构图 的 根 或 顶层模块 。
这一步工作是 自顶向下、逐步细化 , 为每一个 输入 模块、 输出 模块、 变换 模块设计它们的从属模块。
Figure 22: 变换型数据流导出的结构图
与 变换 分析一样, 事务 分析也是从分析 数据流图 开始, 自顶向下,逐步分解,建立系统的 结构图 。
Figure 23: 事务型数据流导出的系统结构图
Figure 24: 一个典型的变换-事务混合型问题的结构图
从耦合的机制上进行分类,按照相对的 耦合松紧程度 的排列, Myers\(^*\) 给出的模块间可能的 耦合方式 有 7种 类型, 给设计人员在设计 程序结构 时提供了一个 决策准则 。
\(*\) Stevens, Wayne P.; Myers, Glenford J.; Constantine, Larry LeRoy (June 1974). "Structured design". IBM Systems Journal. 13 (2): 115–139. https://doi.org/10.1147/sj.132.0115.
低 | 耦合性 | 高 | ||||
非直接耦合 | 数据耦合 | 标记耦合 | 控制耦合 | 外部耦合 | 公共耦合 | 内容耦合 |
强 | 模块独立性 | 弱 |
开始时两个模块之间的耦合 不只是一种类型,而是多种类型的混合 。 这就要求设计人员按照Myers提出的方法进行 分析 , 逐步加以 改进 ,以 提高 模块的 独立性 。
在内容耦合的情形下,被访问模块的 任何变更 , 或者用 不同的编译器 对它再编译,都会造成 程序出错 。
它一般出现在 汇编语言 程序中, 目前大多数高级程序设计语言已经设计成 不允许 出现 内容耦合 。 这种耦合是 模块独立性最弱 的。
Figure 25: 公共耦合示意图
若一组模块
则称之为 外部耦合 。
如果一个模块
则它们之间的耦合称为 控制耦合 。
这种耦合的实质是在 单一接口 上选择 多功能模块 中的 某项功能 。 因此,对被控制模块的 任何修改 ,都会 影响 控制模块。 另外,控制耦合也意味着控制模块 必须知道 被控制模块 内部 的一些 逻辑关系 , 这些都会 降低 模块的 独立性 。
Figure 26: 控制耦合举例
这要求这些模块都 必须清楚 该记录的 结构 , 并 按结构要求 对此记录进行 操作 。 在设计中应尽量 避免 这种耦合,它使在数据结构上的操作 复杂化 了。
如果我们采取 信息隐蔽 的方法, 把在数据结构上的操作全部 集中 在一个模块中, 就可以 消除 这种耦合。
Figure 27: 标记耦合举例
Figure 28: 改控制耦合为数据耦合举例
Figure 29: 改标记耦合为数据耦合举例
耦合是不好的,设计模块时不应该让模块间产生耦合。
参与人数 | 0 |
---|---|
正确 | 0 |
不正确 | 0 |
In software engineering, coupling is
- the degree of interdependence between software modules;
- a measure of how closely connected two routines or modules are;
- the strength of the relationships between modules.
Figure 30: Coupling Vs. Cohesion
耦合是影响软件复杂程度的一个重要因素。
高 | 内聚性 | 低 | ||||
功能内聚 | 信息内聚 | 通信内聚 | 过程内聚 | 时间内聚 | 逻辑内聚 | 巧合内聚 |
强 | 模块独立性 | 弱 |
在上面的关系中可以看到,
人们总是希望一个模块的内聚类型向 内聚程度高 的方向靠。 模块的内聚 在系统的 模块化设计 中是一个关键的因素。
例如,一些 没有任何联系 的语句可能在许多模块中重复多次, 程序员为了节省存储,把它们抽出来组成一个新的模块, 这个模块就是 巧合内聚模块 。
例如,根据输入的 控制信息 ,或从文件中读入一个记录, 或向文件中写一个记录。这种模块是 单入口多功能模块 , 例如 错误处理 模块,它接收 出错信号 , 对 不同类型 的错误打印出 不同的错误信息 。
window.onload = function() {
var room = getParameterByName("room") || generateToken(32);
var link = addParam(window.location.href, "room", room );
document.getElementById("room").innerHTML = link;
document.getElementById("room").href = link;
var qrcode = new QRious({ element: document.getElementById('qrcode'), level: 'H', padding: 0, size: 500, value: link, backgroundAlpha: 0 });
document.querySelector("#host").addEventListener('click', function(e) {
e.preventDefault();
RevealSeminar.open_or_join_room(document.getElementById('password').value);
});
}
例如对某个数据表的 增加 、 修改 、 删除 、 查询 功能, 这个模块将 根据不同的要求 确定该执行哪一个功能。 由于这个模块的所有功能都是基于 同一个数据结构 (数据表), 因此,它是一个信息内聚的模块。
信息内聚模块可以看成是 多个功能内聚模块的组合 ,并且达到 信息的 隐蔽 。 即把某个 数据结构 、 资源 或 设备 隐蔽 在一个模块内, 不为别的模块所知晓。
一个模块中
则称该模块为 功能内聚 模块。
功能内聚模块的 优点 是它们容易 修改 和 维护 , 因为它们的 功能 是 明确的 ,模块间的 耦合 是 简单的 。
功能内聚模块的 内聚程度 最高 。 在把一个系统分解成模块的过程中, 应当 尽可能 使模块达到 功能内聚 这一级。
一个完整的功能模块,不仅能够完成 指定的功能 , 而且还应当能够告诉使用者完成 任务的状态 ,以及 不能完成的原因 。 也就是说,一个完整的模块应当有以下几部分:
所有上述部分,都应当看作是一个模块的 有机组成部分 , 不应分离到其他模块中去 ,否则将会增大模块间的耦合程度。
在得出系统的初始结构图之后,应当 审查分析 这个结构图。 如果 发现几个模块的功能有相似之处 ,可以加以 改进 。
Figure 31: 相似模块的各种合并方案
如果一个判定的 作用范围 包含在 这个判定所在模块的 控制范围 之内, 则这种结构是 简单 的。
Figure 32: 作用范围与控制范围的关系
Figure 33: 高扇入和高扇出的分解
应限制使用如下3种病态连接:
Figure 34: 限制使用的病态连接
模块的大小 ,可以用模块中所含 语句的数量的多少 来衡量。
通常规定其语句行数在 50~100 左右, 保持在 一页纸 之内,最多不超过 500行 。
目标
针对第3章的 银行储蓄系统 ,开发软件的 结构图 。
Figure 35: 银行储蓄系统的数据流图
通过对第一步得到的 数据流图 进行 分析 , 可以看到整个系统是对 存款 及 取款 两种不同的事务进行处理, 因此具有 事务 特性。
Figure 36: 数据流的边界
Figure 37: 第一级分解后的结构图
对第一级分解后的结构图中的 输入数据 、 输出数据 和 调度 模块进行分解, 得到未经精化的 输入结构 、 输出结构 和 事务结构 。
Figure 38: 第二级分解过程
将 输入结构 、 输出结构 和 事务结构 3部分合在一起, 得到初始的软件结构。
Figure 39: 初始的软件结构
由于调度模块下 只有两种事务 ,因此,可以将调度模块 合并 到上级模块中,如图所示。
Figure 40: 将调度模块合并到上级模块后的软件结构
检查密码 模块的作用范围不在其控制范围之内 (即 输入密码 模块不在 检查密码 模块的控制范围之内), 需对其进行调整,如图所示。
Figure 41: 对输入密码模块进行调整后的软件结构
提高模块的独立性,并对 输入事务 模块进行细化。 也可以将 检查密码 功能合并到其上级模块中。
Figure 42: 对模块独立性进行调整后的软件结构
接口设计 的依据是 数据流图 中的自动化系统 边界 。
人机交互(用户)界面 是 人机交互 的主要方式。
为了设计好人机交互界面,设计者需要:
Figure 43: 界面设计的类型
在选用 界面形式 的时候,应当考虑每种类型的 优点 和 限制 。
数据 是 软件系统 中的重要组成部分, 在 设计阶段 必须对要存储的 数据 及其 结构 进行设计。
- 目前,大多数设计者都会采用成熟的 关系数据库管理系统(DBMS) 来 存储 和 管理 数据,由于关系数据库已经相当成熟, 如果应用开发中选择关系数据库, 在数据存储和管理方面可以省去很大的开发工作量。
- 虽然如此, 在某些情况下,选择文件保存方式仍有其优越性 。
以下几种情况适合于选择文件存储:
关系数据库 最成熟,应用也最广泛,一般情况下,大多数设计者都会选择关系数据库。 在结构化设计方法中,很容易将 结构化分析阶段 建立的 实体–关系 模型 映射 到关系数据库中。
概要设计 任务完成后,进入 详细设计 阶段,即 过程设计 阶段。
由于软件 开发 和 维护 中存在的一系列严重问题, 导致 20世纪60年代 爆发了 软件危机 。 很多人将软件危机的一个原因归咎于 GOTO语句的滥用 , 由此引发了关于GOTO语句的争论。
- 1965年, E. W. Dijkstra 在一次会议上提出,应当将GOTO语句从高级语言中取消。
- 1966年, Bohm 和 Jacopini 证明了任何 单入口 、 单出口 的 没有死循环 的程序 都能由3种 最基本的控制结构 构造出来:
- 顺序结构
- 选择结构
- 循环结构
- 20世纪70年代, E. W. Dijkstra 提出了程序要实现结构化的主张, 并将这一类程序设计称为 结构化程序设计(structured programming) 。
程序流程图(program flowchart) 也称为 程序框图 , 是软件开发者最熟悉的 算法表达工具 。
- 早期的流程图存在一些缺点。特别是表示 程序控制流程 的 箭头 , 使用的 灵活性 极大,程序员可以不受任何约束,随意 转移控制 , 不符合结构化程序设计的思想。
- 为使用流程图描述结构化程序,必须 限制 流程图只能使用一些基本控制结构。
Figure 44: 流程图的基本控制结构
Figure 45: 嵌套构成的流程图实例
Figure 46: 标准程序流程图的规定符号
Figure 47: 循环的标准符号
Figure 48: 注解符的使用
Figure 49: 多选择判断
Nassi 和 Shneiderman 提出了一种符合 结构化程序设计原则 的
图形描述工具 ,
叫做 盒图(box-diagram) ,也叫做 N-S图 。
Figure 50: N-S图的5种基本控制结构
Figure 51: N-S图的实例
Figure 52: N-S图的扩展表示
问题分析图(Problem Analysis Diagram, PAD) 是日本日立公司提出的、 由 程序流程图 演化来的用 结构化程序设计 思想表现程序逻辑结构的 图形工具 。
Figure 53: PAD的基本控制结构
Figure 54: PAD实例
Figure 55: PAD的扩充控制结构
- 伪代码的语法规则:
- 外语法(outer syntax) 应当 符合 一般程序设计语言常用语句的 语法规则 ;
- 内语法(inter syntax) 可以用英语中一些简单的 句子 、 短语 和通用的 数学符号 来 描述 程序应执行的 功能 。
IF 客户订货金额超过5000元 THEN
IF 客户拖延未还赊欠钱款超过60天 THEN
在偿还欠款前不予批准
ELSE (拖延未还赊欠钱款不超过60天)
发批准书、发货单
ENDIF
ELSE (客户订货金额未超过5000元)
IF 客户拖延未还赊欠钱款超过60天 THEN
发批准书、发货单,并发催款通知书
ELSE (拖延未还赊欠钱款不超过60天)
发批准书、发货单
ENDIF
ENDIF
if-then-else
或 case-of
结构。while-do
或 repeat-util
结构。参与人数 | 0 |
---|---|
程序流程图 | 0 |
N-S图 | 0 |
PAD | 0 |
PDL或伪代码 | 0 |
- 在处理较大的 复杂任务 时,常采取 模块化 的方法,即
- 在程序设计时不是将全部内容放在同一模块中, 而是分成若干 模块 ,每个模块实现一个功能。
- 模块分解完成后,下一步的任务就是将每个模块的功能逐步分解细化为一系列的 处理 。
要求用筛选法求 \(100\) 以内的素数。 所谓的筛选法,就是从 \(2\) 到 \(100\) 中去掉 \(2, 3, 5, 7\) 的倍数, 剩下的就是 \(100\) 以内的素数。
为了解决这个问题,可以按程序功能写出以下框架:
main() {
建立2到100的数组A[],其中A[i]=i; #1
建立2到10的素数表B[],存放2到10以内的素数; #2
若A[i]=i是B[]中任一数的倍数,则剔除A[i]; #3
输出A[]中所有没有被剔除的数; #4
}
main() {
// 建立2到100的数组A[],其中A[i]=i #1
for (i = 2; i <= 100; i++) A[i] = i;
// 建立2到10的素数表B[],存放2到10以内的素数 #2
B[1] = 2; B[2] = 3; B[3] = 5; B[4] = 7;
// 若A[i]=i是B[]中任一数的倍数,则剔除A[i] #3
for (j = 1; j <= 4; j++)
检查A[]所有的数能否被B[j]整除并将能被整除的数从A[]中剔除 #3.1
// 输出A[]中所有没有被剔除的数 #4
for (i = 2; i <= 100; i++)
若A[i]没有被剔除,则输出之 #4.1
}
#3.1
和语句 #4.1
的细化(直到最后每个语句都能直接用程序设计语言来表示为止)
main() {
// 建立2到100的数组A[],其中A[i]=i #1
for (i = 2; i <= 100; i++) A[i] = i;
// 建立2到10的素数表B[],存放2到10以内的素数 #2
B[1] = 2; B[2] = 3; B[3] = 5; B[4] = 7;
// 若A[i]=i是B[]中任一数的倍数,则剔除A[i] #3
for (j = 1; j <= 4; j++)
// 检查A[]所有的数能否被B[j]整除并将能被整除的数从A[]中剔除 #3.1
for (i = 2; i <= 100; i++)
if (A[i] / B[j] * B[j] == A[i])
A[i] = 0;
// 输出A[]中所有没有被剔除的数 #4
for (i = 2; i <= 100; i++)
// 若A[i]没有被剔除,则输出之 #4.1
if (A[i] != 0)
printf("A[%d] = %d\n", i, A[i]);
}
#include <stdio.h>
void main() {
// 建立2到100的数组A[],其中A[i]=i #1
int A[101], B[5];
for (int i = 2; i <= 100; i++) A[i] = i;
// 建立2到10的素数表B[],存放2到10以内的素数 #2
B[1] = 2; B[2] = 3; B[3] = 5; B[4] = 7;
// 若A[i]=i是B[]中任一数的倍数,则剔除A[i] #3
for (int j = 1; j <= 4; j++)
// 检查A[]所有的数能否被B[j]整除并将能被整除的数从A[]中剔除 #3.1
for (int i = 2; i <= 100; i++)
if (A[i] / B[j] * B[j] == A[i])
A[i] = 0;
// 输出A[]中所有没有被剔除的数 #4
// 向A[]中补充10以内的素数 #4.1
A[2] = 2; A[3] = 3; A[5] = 5; A[7] = 7;
for (int i = 2; i <= 100; i++)
// 若A[i]没有被剔除,则输出之 #4.2
if (A[i] != 0)
printf("%d ", A[i]);
}
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97
这几个文档 互相补充 ,向用户提供了可视的 设计方案 , 并 为软件开发和维护提供了所需的信息 。
参考教材
参考教材
接口设计说明(IDD) 与 接口需求规格说明(IRS) 配合,用于沟通和控制接口的设计决策。
参考教材
所有模块的设计文档完成以后,就可以对 软件设计 进行 评审 :
概要设计评审的检查内容如下:
1. 系统概述 | 6. 属性设计 | 11. 清晰性 |
2. 系统描述和可追踪性 | 7. 数据结构 | 12. 一致性 |
3. 是否对需求分析中不完整、易变动、潜在的需求进行了相应的设计分析 | 8. 运行设计 | 13. 可行性 |
4. 总体设计 | 9. 出错处理 | 14. 详细程度 |
5. 接口设计 | 10. 运行环境 | 15. 可维护性 |
参考教材
详细设计评审的检查内容如下:
1. 清晰性 | 6. 数据 | 11. 性能 |
2. 完整性 | 7. 功能性 | 12. 可靠性 |
3. 规范性 | 8. 接口 | 13. 可测试性 |
4. 一致性 | 9. 详细程度 | 14. 可追踪性 |
5. 正确性 | 10. 可维护性 |
参考教材