数据流图(DFD):层级、符号与实用示例
学习如何用正确的符号创建数据流图。涵盖 DFD 的 0-2 级、Yourdon-DeMarco 与 Gane-Sarson 符号对比,以及真实案例。
当系统崩溃或流程产生错误输出时,第一个问题通常是"数据在哪里出了问题?"数据流图(DFD)通过使数据移动变得显式来回答这个问题——精确地显示数据来自哪里、流向哪里、如何转换,以及在哪里存储。
与模拟控制流(接下来发生什么)的流程图不同,DFD 模拟数据流(什么数据流向哪里)。这种区别使其成为系统分析、软件设计和记录复杂数据集成的正确工具。
什么是数据流图?
数据流图是数据如何在系统中流动的视觉表示。它展示:
- 外部实体 — 系统外部的数据来源和目的地
- 流程 — 将输入数据转换为输出数据的转换操作
- 数据存储 — 数据静止存放的地方
- 数据流 — 上述元素之间数据的移动
DFD 不显示时序、决策逻辑或谁执行任务。它们只显示数据移动。这种有限的范围使其在不陷入实现细节的情况下理解和设计系统非常有用。
DFD 符号
两种符号占主导地位:Yourdon-DeMarco 和 Gane-Sarson。它们用不同的形状表示相同的概念。
Yourdon-DeMarco 符号
软件工程中广泛使用的原始结构化分析符号:
| 元素 | 符号 | 说明 |
|---|---|---|
| 流程 | 圆形(气泡) | 转换数据;用动词短语标记 |
| 数据存储 | 开口矩形 | 存储数据;用名词标记 |
| 外部实体 | 矩形 | 系统外的来源或目的地 |
| 数据流 | 带标签的箭头 | 在元素之间移动的已命名数据 |
┌──────────┐ ╭──────────╮ ┌═══════════════╗
│ 客户 │───────→ │ 验证 │───────→ ║ D1:订单 ║
└──────────┘ 订单 │ 订单 │ 有效 ╠═══════════════╣
╰──────────╯ 订单 ║ ║
Gane-Sarson 符号
信息系统和业务分析中常用:
| 元素 | 符号 | 说明 |
|---|---|---|
| 流程 | 带圆角的矩形(分隔标题) | 用 ID 和流程名称标记 |
| 数据存储 | 左侧开口的矩形 | 用 D 编号和名称标记 |
| 外部实体 | 矩形 | 系统外的来源或目的地 |
| 数据流 | 带标签的箭头 | 在元素之间移动的已命名数据 |
┌──────────┐ ┌────────────────┐ ┌═══╦════════════╗
│ 客户 │───────→ │ 1.0 │───────→ ║D1 ║ 订单 ║
└──────────┘ 订单 │ 验证订单 │ 有效 ╚═══╩════════════╝
└────────────────┘ 订单
使用哪种符号?
两者传达相同的信息。根据你的情境选择:
- Yourdon-DeMarco:在软件工程、学术界以及使用结构化分析方法时优先使用
- Gane-Sarson:在业务信息系统和企业环境中常用
选择一种并在项目的所有图表中保持一致。
DFD 层级
DFD 按层级组织。高级别图表提供概览;低级别图表提供细节。每个级别将上一级别的单个流程分解为其内部子流程。
0 级:上下文图
上下文图将整个系统显示为单个流程,周围是外部实体。它定义系统边界,并显示哪些数据跨越该边界。
客户订单
┌──────────┐ ─────────────────→ ╭──────────────────────╮
│ 客户 │ │ │
└──────────┘ ←───────────────── │ 订单管理系统 │
订单确认 │ │
│ │
┌──────────┐ ─────────────────→ ╰──────────────────────╯
│ 供应商 │ 库存更新 │
└──────────┘ ↓
┌──────────────┐
│ 支付处理 │
└──────────────┘
上下文图应该能放在一页上,只显示跨越边界的数据流——没有内部细节。如果你发现自己在添加内部流程,那你处于错误的层级。
1 级:概览图
1 级图将单个上下文流程分解为其主要子流程。这些是系统的主要功能区域。
┌──────────┐ ╭──────────╮ ╭──────────╮
│ 客户 │───────→ │ 1.0 │───────→ │ 2.0 │───┐
└──────────┘ 订单 │ 接收 │已验证 │ 处理 │ │
│ 订单 │ 订单 │ 支付 │ │
╰──────────╯ ╰──────────╯ │
│ ↓
↓ ╭──────────╮
┌════════════════╗ │ 3.0 │
║ D1:订单 ║────────────→ │ 履行 │
╚════════════════╝ 订单数据 │ 订单 │
╰──────────╯
│
↓
┌──────────┐
│ 快递 │
│ 合作伙伴 │
└──────────┘
1 级图通常有 3-7 个流程。如果有更多,考虑将其分组为更少的高级别流程。
2 级:详细图
2 级将每个 1 级流程分解为其子步骤。1 级中的每个气泡都有对应的 2 级图。
例如,展开上面的流程 1.0 "接收订单":
┌──────────┐ ╭──────────╮ ╭──────────╮
│ 客户 │──────────→ │ 1.1 │──────────→ │ 1.2 │
└──────────┘ 原始订单 │ 验证 │ 有效数据 │ 检查 │
│ 格式 │ │ 库存 │
╰──────────╯ ╰──────────╯
│ │ │
无效 │ 有货
订单 缺货│
↓ ↓
┌──────────┐ ╭──────────╮
│ 客户 │ │ 1.3 │
└──────────┘ │ 预留 │
│ 商品 │
╰──────────╯
│
↓
┌════════════╗
║ D1:订单 ║
╚════════════╝
应该深入到多少层级?
当一个流程满足以下条件时停止分解:
- 简单到可以用几句话描述
- 由一个人或一个原子系统功能实现
- 已经达到实施所需的细节级别
大多数系统不需要超过 2 级。3 级很少见,通常表明系统过于复杂或分解结构不够良好。
DFD 与流程图的对比
这两者经常被混淆,因为都使用方框和箭头。它们回答的是不同的问题。
| 方面 | 数据流图 | 流程图 |
|---|---|---|
| 展示 | 数据如何在系统中移动 | 控制流如何在流程中传递 |
| 主要问题 | 什么数据流向哪里? | 接下来发生什么? |
| 时间/序列 | 未建模(仅数据转换) | 核心——序列是主要结构 |
| 决策逻辑 | 不表示 | 显式(菱形决策节点) |
| 谁执行 | 不显示 | 可通过泳道格式显示 |
| 数据存储 | 显式的数据存储符号 | 不表示 |
| 最适合 | 系统分析、数据架构 | 流程文档、程序指南 |
流程图显示贷款审批流程中的步骤。DFD 显示贷款申请系统接收哪些数据、存储在哪里,以及产生哪些输出。
当你在分析或设计系统时使用 DFD。当你在记录程序时使用流程图。
逐步创建 DFD
第一步:定义系统边界
确定什么在系统内部,什么在系统外部:
- 内部: 你控制的流程、数据存储和数据流
- 外部: 外部实体——客户、合作伙伴、外部系统
边界外的一切都是外部实体。跨越边界的数据在上下文图中显示为流。
第二步:绘制上下文图(0 级)
- 将整个系统作为一个带标签的圆圈放在中心
- 识别所有外部实体并将其放置在外围
- 用描述性标签绘制跨越边界的数据流
- 检查完整性:有没有进出系统的未标记数据?
第三步:识别主要流程(1 级)
将系统分解为 3-7 个主要流程:
- 用动词短语为每个流程命名("验证订单"、"处理支付")
- 编号(1.0、2.0、3.0)
- 识别连接它们的数据流
第四步:添加数据存储
识别流程之间保存数据的地方:
- 数据库:客户记录、订单历史、库存
- 文件:日志文件、配置
- 外部数据:传递给外部系统的数据(通常表示为边界流,而非内部存储)
用名词命名每个数据存储并分配 D 编号(D1、D2)。
第五步:用数据流连接
在元素之间绘制带标签的箭头:
- 流必须有描述性名称("客户订单"、"已验证记录"、"发票")
- 流连接流程与流程、流程与数据存储、外部实体与流程
- 数据存储不直接连接外部实体(数据必须经过流程)
第六步:分解到 2 级
对于 1 级中的每个主要流程,绘制单独的 2 级图,显示其内部子流程。进入和离开 1 级流程的数据流成为 2 级图的边界流。
第七步:验证一致性
检查:
- 进入流程的每个数据流都被该流程使用
- 离开流程的每个数据流都源自该流程
- 数据存储只能通过流程访问(不能由外部实体直接访问)
- 1 级边界流与上下文图流匹配
真实案例:电商订单系统
0 级:上下文图
┌──────────┐ 订单请求 ╭──────────────────────╮
│ 客户 │ ────────────→ │ │
└──────────┘ │ 电商 │
↑ 订单状态 │ 订单系统 │
└───────────────────── │ │
╰──────────────────────╯
┌──────────┐ 支付结果 │ ↑
│ 支付 │ ────────────→ │ │
│ 网关 │ ←──────────── │ 发货
└──────────┘ 扣款请求 ↓ 数据
┌──────────────┐
│ 快递 │
│ 合作伙伴 │
└──────────────┘
1 级:主要流程
客户 ─── 订单请求 ──→ ╭──────────╮
│ 1.0 │ ──→ D1:订单
│ 验证 │
│ 订单 │
╰──────────╯
│
已验证订单
↓
支付网关 ←── 扣款 ── ╭──────────╮ ── 支付 ──→ D2:支付
请求 │ 2.0 │ 记录
支付网关 ── 结果 ──→ │ 处理 │
│ 支付 │
╰──────────╯
│
已确认订单
↓
╭──────────╮
D1:订单 ── 订单数据 ─→ │ 3.0 │ ── 发货请求 ──→ 快递合作伙伴
D3:商品 ─ 库存数据 ──→ │ 履行 │
│ 订单 │
╰──────────╯
│
发货数据
↓
╭──────────╮
│ 4.0 │ ── 状态更新 ──→ 客户
│ 追踪和 │
│ 通知 │
╰──────────╯
2 级:分解流程 1.0(验证订单)
客户 ─── 原始订单 ──→ ╭──────────╮
│ 1.1 │ ── 无效 ──→ 客户(错误)
│ 检查 │
│ 格式 │
╰──────────╯
│
格式化订单
↓
╭──────────╮
D3:商品 ─ 库存信息 ─→ │ 1.2 │ ── 不可用 ──→ 客户
│ 验证 │
│ 库存 │
╰──────────╯
│
可用订单
↓
╭──────────╮
D4:客户 ─ 认证数据 ─→ │ 1.3 │ ── 未验证 ──→ 客户
│ 验证 │
│ 客户 │
╰──────────╯
│
已验证订单
↓
D1:订单(存储)
常见的 DFD 错误
将外部实体直接连接到数据存储。 数据存储是内部的;外部实体不能直接访问它们。所有跨越系统边界的数据都必须通过流程传递。
未标记的数据流。 每个箭头都必须有描述性名称。"数据"或"信息"不是描述性的。流应该以数据代表的内容命名:"客户订单"、"支付确认"、"库存水平"。
没有输入或输出的流程。 一个流程至少必须有一个输入流和一个输出流。没有传入数据的圆圈"凭空创造"数据——那不是流程,而是外部实体。没有传出数据的圆圈丢弃所有内容——将其建模为数据存储写入或删除该流程。
将控制流与数据流混淆。 决策、序列和控制逻辑不属于 DFD。如果你发现自己在画决策菱形,那你在创建流程图,而非 DFD。DFD 只显示数据移动。
1 级有过多细节。 1 级应该有 3-7 个主要流程。如果你在 1 级显示 15 个流程,那你跳过了层级分解。将相关流程分组到更高级别的气泡中,并使用 2 级显示细节。
级别不一致。 1 级图中进入流程 2.0 的数据流必须与流程 2.0 的 2 级图中的边界流匹配。不一致意味着图表不代表同一个系统。
跨子系统共享数据存储但不加解释。 如果多个流程访问同一数据存储,确保这是有意为之的,且访问方式合理。过度使用单一的"主数据库"数据存储会掩盖重要的数据架构决策。
使用 Flowova 创建数据流图
手动映射数据流很繁琐——识别所有边界流、一致地为流程编号、保持各级同步都需要大量努力。
Flowova 的数据流图制作工具可以从纯语言系统描述生成 DFD 结构。描述系统的输入、输出和主要流程,即可获得可精修的草稿图表。这对于快速创建上下文图和 1 级概览尤其有用,然后根据需要深入到需要进一步说明的流程的 2 级细节。
结论
当你需要了解或传达数据如何在系统中移动时——不是一步一步发生什么,而是数据从哪里来、什么对其进行转换、存储在哪里,以及最终流向哪里——DFD 是正确的工具。
从上下文图开始建立系统边界。分解到 1 级以识别主要流程。只有需要进一步说明的流程才深入到 2 级。保持数据流名称具体、避免将控制逻辑混入图表,并验证各级别之间的一致性。
