ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

数据流图DFD实战:需求对齐、四符号约束与避坑自检

数据流图DFD实战:需求对齐、四符号约束与避坑自检

简介:这份《教你怎么画数据流图,包括数据流图实例》PPT面向管理信息系统课程学习者、系统分析入门者及需要绘制DFD的师生,用简明讲义解决数据流图符号识别、分层绘制与实例落地的问题。内容从数据流、加工、数据存储、外部项四类基本符号讲起,梳理确定外部项、输入输出流、主要处理功能及自顶向下逐层分解的绘制步骤,并补充布局原则、检查要点、数据流必须经过加工等注意事项,配合银行取款处理实例帮助理解关联图、顶层图和下层图的展开方式。资源包共1个PPT文件,约312KB,篇幅集中,便于课堂演示、自学查阅或绘图练习时快速对照。已有626人学习,适合用作DFD概念梳理、课程复习和系统分析入门的参考材料。

1. 撤掉表结构图只留一张 DFD:三个小时对齐需求的真实场景

某公司做一套跨平台报账系统,评审会上摆了两张图:业务方画的是审批走到哪一步,开发画的是表结构和接口。两边各说各话,会开了两轮没结论。后来把这两张图都撤了,只留一张数据流图,三个小时就对齐了——因为它不涉及硬件、软件、数据结构与文件组织,只描述系统在信息处理上要做什么。数据流图(DFD,Data Flow Diagram)就是组织中信息运动的抽象,是信息逻辑系统模型的主要形式。它最有价值的地方不是好看,而是符号少到业务方敢在上面动笔改。适合需求分析、系统分析岗,也适合要把业务讲给外包听、又不想提前暴露库表设计的人。这篇内容把四个符号的约束、两个完整案例的绘制步骤、编号规范和五类翻车现场一次讲透。

2. 四个符号各有各的约束:数据流、加工、数据存储、外部项的边界判定

DFD 只有四种基本符号,很多人第一次看觉得简单得不像个建模方法,画到第三层才发现每一根线都在还债。数据加工用 P 编号、外部项用 S 编号、数据流用 F 编号、数据存储用 D 编号,这套前缀不是为了好看,是为了让分层图之间的引用有唯一地址。下面这张表是我自己贴在显示器边上的对照表,画图时随时对一眼。

符号图形特征编号前缀语义高频误用
数据流带箭头的线F一个或一组确定的数据在流动把控制信号、实物、动作当成数据流
加工上下两分的圆角框P对数据流的变换加工名写成"处理数据""业务逻辑"
数据存储开口长方框,左端小方格D静止待取的数据存储两侧没有数据流,变成孤岛
外部项矩形框S系统边界之外的源点与终点把系统内部模块画成外部项

2.1 数据流:箭头只是运输方式,数据结构才是内容

数据流由一个或一组确定的数据组成,这句话的重点在"确定"。箭头本身不携带任何信息,真正被传递的是箭头上面那串名字所代表的数据结构。所以数据流名要能直观反映含义,"取款单、存折"合格,"数据""信息""结果""表单"不合格——后者在评审会上一定会被追问"到底是什么数据",然后会议就跑偏了。

数据流可以同名,也可以有相同的数据结构,但必须对应不同的数据或不同的含义。这条规则在分层图里最容易破。比如关联图上的 F1 叫"取款单、存折",分解到下一层后,审核通过的那份叫"合格存折、取款单"、被退回的那份叫"不合格存折、取款单",如果两层都写成"存折",读图的人会以为是同一股流在图上出现了两次。我一般要求子层数据流编号继承父层前缀,F1 拆成 F1.1 和 F1.2,一眼能看出血缘关系。

两个符号之间可以存在多条数据流,DFD 并不表明它们之间的任何关系,诸如次序、主次。这条经常被误解成"一条线只能画一个箭头"。实际上审核加工同时收"取款单"和"存折"两样东西,画成一条合并流也行,拆成两条并行流也行,取决于它们在业务上是否总是同时到达。如果存在"只交存折不填单"的情况,就必须拆开,否则下游加工会默认两个输入永远成对出现,实现时就是一个空指针。

还有一种情况要提前拦住:数据流不能用来表达时序。"先校验再落库"是加工内部的执行顺序,不是两条流之间的关系。想在图上表达先后,只能靠分层——上层加工在下层被拆成多个子加工,子加工之间用数据存储做界面,顺序才被隐含地表达出来。

2.2 加工:编号是唯一性的锚,分解是可控性的阀门

加工的符号分成上下两部分,上面是标识部分,下面是功能描述部分。标识部分是加工编号,以 P 开头且必须唯一;功能描述部分是加工名,要简单、能概括地对数据的加工行为,详细的定义放到数据词典里,不要塞进框图。我见过把一整段业务规则写进加工框的图,框比 A4 纸还大,最后没人愿意看第二眼。

编号的层级就是分解的层级:顶层加工叫 P,第一次分解出 P1、P2,P2 再分解出 P2.1、P2.2、P2.3、P2.4。这套编号一旦定下来就不要动,因为数据词典、测试用例、需求追踪矩阵全都靠它对齐。中途给某个加工插队改号,等于把所有下游文档全部作废一次,这个代价在项目中期是付不起的。

加工要逐层分解,目的是让分解后的加工功能简单、易于理解。停在哪里有个可操作的判断标准:当这个加工已经能用一句"动词 + 宾语"说清楚,并且不再依赖其他加工的中间结果时,就到底了。比如"审核取款单"到底了,"处理取款"没到底,因为它里面还藏着查账、改账、打印、存档四件事。分解不彻底会让子图失去意义,分解过头则会把"给变量赋值"这种实现细节也画进去,两种都是浪费。

2.3 数据存储与外部项:一个在界内,一个在界外

数据存储是静止的数据,符号是开口的长方框,存储名写在框内,要概要说明文件中的主要数据;编号写在左端小方格中,以 D 开头。它有两个硬性约束:一是数据存储上一定要有数据流,只进不出是黑洞,只出不进是凭空造数据;二是在分层 DFD 中,数据存储一般仅属于某一层或某几层,所以又叫局部文件。

局部文件这个说法很容易被忽略。顶层图上出现的 D1"帐目库",到了二层图里如果只被一个加工读写,那它其实是那个子系统的局部文件,没必要在更上层反复画。反过来,如果一个存储被两个加工共同读写,它就成了这两个加工之间的界面,必须画在两张子图都能看到的位置。判断依据不是"这个库有多大",而是"谁在什么层次上需要同时看见它"。

为避免交叉线,同一个数据存储可以在多处画出,用重复符号表示。draw.io 和 Visio 里没有现成的重复存储图元,我的做法是在框左侧加一道竖线并在角标注明"同 D1",评审时口头说明一次,图例里写一行,比强行拉一条横跨整页的线可读性好得多。

外部项又叫源点和终点,是系统外的实体,存在于环境之中,与系统有信息交流。从源点到系统的信息是输入,从系统到终点的信息是输出。同一个端点可以是人,也可以是其他系统,还可以既是源点又是终点——银行取款里的储户就是典型,他交单子是源,他拿回存折是终点。在 DFD 中引入源点和终点的目的是便于理解系统,所以不需要详细描述它们,编号以 S 开头即可。

边界判定的实操问题只有一个:这个实体是否在系统的控制范围内。储户在界外,因为他不能被系统修改;帐目库在界内,因为系统能写它。有人把"银行柜员"也画成外部项,这不算错,但要看系统边界划在哪——如果这套系统就是给柜员用的终端,柜员在界外;如果系统包含柜员的全部操作流程,柜员就该被吸收进加工里。同一份需求,边界划法不同,图的层数能差出两层,所以第一版图出来之后,第一件事是把边界画法拿去跟业务方确认,而不是急着往下分解。

3. 银行取款案例走七步:从关联图到二层图的完整绘制实操

这个案例的需求描述很朴素:储户把填好的取款单和存折交给银行,银行审核并查对帐目,不合格的存折和取款单退回储户,合格的送取款处理;取款处理修改帐目,把存折、利息单、结算清单和现金交给储户,同时把取款单存档。短短两句话,正好覆盖了关联图、顶层图、父子平衡、实物不能当数据流这几个关键点,适合当成第一条练手路径。

绘制步骤我按讲义里的七步走,但每一步补上了判断依据和产出物,照着做基本不会卡住。

步骤动作产出物判断依据
1确定外部项S 清单实体是否在系统控制范围外
2画关联图一张只有单个加工的图输入流与输出流是否闭合
3切子系统P1、P2 初稿每个子系统能否独立命名
4逐层分解顶层图父子图边界流是否一致
5重复分解二层图或基本加工加工名能否一句话说清
6检查布局可读的成图交叉线数量、源终位置
7用户走查签字版业务方能否复述每条流

3.1 前三步:定外部项、画关联图、把实物挡在门外

第一步确定外部项。储户是唯一的外部项,编号 S1。这里有个容易漏的点:储户既是源点又是终点,关联图上要画两个 S1 框,左边一个右边一个,中间是系统。只画一个框会让所有箭头都指向同一个矩形,读图的人分不清哪条是输入哪条是输出。

第二步画关联图。把整个取款系统当成一个加工 P,输入是 F1"取款单、存折",输出是 F2"存折、利率单、结算清单"。关联图的价值在于逼你回答"这个系统的输入输出到底是什么",很多需求文档写了几十页,一问输入输出还是含糊的,画这张图立刻就露馅。

这一步有个必须提前说清的坑:现金是实物,不能作为数据流。业务描述里明明写着"将存折、利息单、结算清单及现金交储户",初学者会顺手把"现金"画成一条流,图立刻就错了——DFD 描述的是信息运动,钞票的物理转移不是数据。正确做法是把现金交付写进 P2 的功能描述部分,或者在加工框下加一行注释。如果业务方坚持要在图上看见现金,就画一条虚线并标注"非数据流,实物交付",图例里说明,别混进 F 编号体系。

还有一个变体值得提前想清楚:如果这套系统只是银行核心系统里的一个模块,那么"帐目库"应该在界内,储户在界外;如果做的是柜面终端,柜员可能也要作为外部项 S2 出现,此时 F1 的来源就从储户变成了柜员。同一段业务,边界不同图就不同,这不是画错,是建模范围不同,但必须在图名上标清楚,比如"取款处理关联图(柜面终端视角)"。

第三步确定主要信息处理功能。按业务描述,取款被拆成两个加工:P1 取款审核、P2 取款处理。拆分的依据不是"步骤有几句话",而是"这两个环节之间是否存在一个可以被独立描述的数据界面"。审核的输出是"合格存折、取款单",处理的输入正好是这个,界面清晰,拆得成立。如果业务是"审核完直接改账",中间没有可命名的中间数据,硬拆就会造出一个假界面。

3.2 第四步到第五步:逐层分解与父子图平衡

第四步把关联图里的 P 分解成 P1、P2,画出顶层图。这一步的产出必须满足父子平衡:父图上出现在加工 P 边界上的每一条数据流,在子图里都必须能找到对应的流,不能凭空多出来,也不能凭空少掉。

本案例的顶层图结构是这样的:S1 储户输出 F1,F1 进入 P1 取款审核;P1 读 D1 帐目库做查对,输出 F1.1"合格存折、取款单"给 P2,输出 F1.2"不合格存折、取款单"退回 S1;P2 取款处理读写 D1,把取款单写入 D2 取款记录存档,输出 F2 给 S1。注意 F1 在子图里被拆成了 F1.1 和 F1.2,这是数据流的分解而不是新增,编号继承 F1 的前缀就是给评审看的证据。如果子图里突然冒出一条父图没有的 F5,那不是发现了新需求,是父图漏画了,必须回头补父图。

D1 帐目库在这里扮演的是典型的界面角色:P1 读它做查对,P2 读写它做修改,两个加工共享同一个存储,所以它必须画在顶层图上,而不是藏进某个子图。反过来,D2 取款记录只被 P2 写,没有其他加工读,它就是 P2 的局部文件,放在这一层画出来没问题,再往下分解时就没必要重复出现了。

第五步继续分解。P2 取款处理还能不能再拆?如果业务里包含"计息"和"打印"两件事,可以拆成 P2.1 计息、P2.2 更新帐目、P2.3 打印结算清单,此时 D1 依然跨加工,不变;但会新增中间数据流,比如"利息金额"。如果业务简单到只是查余额、扣减、打印三行代码,那就停在 P2,硬拆只会让图变长而不变清楚。判断标准还是那句:加工名能不能一句话说清,说完之后还需不需要解释。

分解过程中有个隐蔽的陷阱:同一层内的加工之间不要直接连线。加工与加工之间的数据传递必须经过数据流,而数据流在分层图里通常表现为"上层一条流、下层两个加工分别连接同一个数据存储"。如果两个子加工之间画了一条直接箭头,说明它们之间缺一个存储或者缺一层抽象,前者补存储,后者说明这两个加工本来就不该在同一层。

3.3 第六步到第七步:布局规则与用户走查

第六步检查布局。布局不是审美问题,是可读性问题,可读性直接决定这张图会不会被读第二遍。我固定用这几条:源点画左侧、终点画右侧;加工按主流程自上向下排列;数据存储画在产生它的加工和消费它的加工之间;同一存储多处出现时用重复符号而不是长直线;相邻层之间的编号连续性用颜色或线宽区分。

交叉线是布局里最耗时的部分。经验值是单张图超过三条交叉线就该重排,重排的手段只有两个:调整加工顺序,或者复制数据存储。前者靠业务理解,后者靠符号规范。不要在图上画跨越半个页面的弧线,那种线在打印出来之后基本跟背景网格糊在一起。

第七步和用户交流。这一步经常被当成形式,实际上它是整条流程里唯一能证伪的环节。走查时不要问"这个图对不对",业务方出于礼貌会说对;要问"这条流里的取款单上都填了什么""不合格的情况你们实际怎么处理""这个存储里的数据多久更新一次"。让他在图上指出一条他没见过的流,比他签一个字有价值得多。

走查还有一个副产品:命名返工。业务方对"合格存折、取款单"这种名字往往没有感觉,但会对"退单""差错件"这类行话立刻有反应。把他们嘴里的词替换到数据流名上,下一版评审的沟通成本会掉一半。

4. 图书预订系统的分层拆解:多分支数据流怎么编号才不打架

银行取款是一条主干走到底,图书预订系统则带分支和定时逻辑:书店向顾客发放订单,顾客填好交回系统,系统依据图书目录检查订单,合格订单按顾客情况和订单数目分成优先订单与正常订单,优先订单随时处理,正常订单定期处理,最后汇总按出版社要求发出去。分支一多,编号和分层就成了主要矛盾。

4.1 订单检查为什么必须单独成加工

关联图很干净:S1 顾客输出 F1 订单,系统输出 F2 汇总订单给 S2 出版社。把系统当成一个加工 P,两个外部项,两条流,五分鐘能画完。

到顶层图就出现分歧了。有人把"检查 + 分类 + 汇总"合成一个 P2 订单处理,理由是它们都属于"处理订单"。这样画的直接后果是:F3"不合格订单"这条流无处安放。它既不是输入也不是输出到外部项的流,只能挂在 P2 的边界上,而父图里根本没有这条流,父子平衡立刻被破坏。

正确的拆法是 P1 订单检查独立成加工。它的存在有三个硬理由:第一,它依赖 D1 图书目录这个存储,是一个明确的数据依赖;第二,它有两条出口——合格的进 D2 合格订单,不合格的走 F3 退回 S1,一个加工两个出口意味着它承担了判定职责,判定就该被单独看见;第三,它是最容易被业务方质疑的环节,"什么算不合格"这个问题只有把 P1 单独拎出来才问得出口。

于是顶层图是:S1 → F1 → P1;P1 读 D1 图书目录,输出 F3 不合格订单回 S1,输出合格订单进 D2;P2 订单处理读 D2,写 D3 待发出订单;P3 发送订单读 D3 和 D4 出版社要求,输出 F2 汇总订单给 S2。D4 出版社要求是外部输入的数据被固化下来的存储,它在顶层就出现,因为 P3 的分类规则依赖它。

这一步的血泪经验是:凡是带"检查""校验""审核"字样的加工,都倾向于独立成节点。它们通常有多个出口,合并进别的加工会把分支路径藏起来,而分支路径恰恰是测试用例的主要来源。

4.2 分类与定时处理:二层图怎么摆平两种节奏

P2 订单处理在顶层图里是一句话,实际业务包含数目统计、订单分类、随时处理、定期处理四件事,必须分解出二层图。

二层图的结构:P2.1 数目统计读 D2 合格订单,产出 D5 订单数目;P2.2 订单分类读 D2、D5 和 D6 顾客情况,输出 D7 优先订单和 D8 正常订单;P2.3 随时处理读 D7,写 D3 待发出订单;P2.4 定期处理读 D8,写 D3。四条子流最终汇到同一个存储 D3,再由顶层的 P3 消费。

这里最容易画错的是 D5"订单数目"。它是个中间结果,只被 P2.1 写、被 P2.2 读,看起来完全可以省略成一个局部变量。但它必须画出来,因为"订单数目影响分类结果"是一条业务规则,规则要有载体。如果把它省掉,P2.2 的输入就只剩 D2 和 D6,读图的人会以为分类只看顾客情况,实现时就会漏掉"大单优先"这类逻辑。中间存储画不画,判断标准是它是否承载了一条独立的业务规则,而不是它最终会不会落库。

第二个容易画错的是 D3 待发出订单被两个加工同时写。P2.3 随时处理和 P2.4 定期处理都往 D3 里放数据,这在 DFD 里是允许的,因为存储是静止的,写入方可以有多个。但如果两条路径写入的字段结构不一样,就必须拆成两个存储或者在上层合并成一条流——DFD 不表达时序,读图的人无法判断哪个先写。这种情况我的做法是在数据词典里把 D3 的结构写清楚,并在图例里标注"P2.3 写 A、B 字段,P2.4 写 A、C 字段"。

第三个是 D6 顾客情况的来源。它在二层图里凭空出现,既不是外部项输入,也不是上层存储。这类"黑匣子存储"是评审时被追问最多的地方。要么在顶层图补一个外部项或存储把它接上,要么在数据词典里注明"由客户档案系统同步",二选一,但不能不解释。

4.3 编号、命名与数据词典对齐

分支一多,编号就是唯一的锚。这套系统里加工编号是 P1、P2、P3、P2.1 到 P2.4;数据存储是 D1 到 D8,全局唯一且不随层变化;数据流是 F1、F2、F3,子层流用 F1.1 这种继承式编号;外部项 S1、S2 全局唯一。四套前缀各管一摊,互不占用,这条规矩定死了,后面所有文档都好对齐。

命名上我坚持两条:数据流名用名词短语,加工名用动宾短语,存储名用"××文件/××库/××表"结尾。这样一眼能看出这是流还是加工,评审时不会有人指着加工问"这个数据从哪来"。

图画到三层以上,纯靠眼睛检查编号一致性已经不现实了。我一般会维护一份和图上完全对应的 CSV 清单,改图先改表,再用一段脚本做机械校验。这套做法在跨平台项目里救过我好几次,因为前端同学改图、后端同学改表,两边不同步时脚本会先炸。

import csv from collections import defaultdict # process.csv: pid,pname,parent 例:P2.3,随时处理,P2 # flow.csv: fid,fname,frm,to 例:F1,订单,S1,P1 procs, flows = {}, [] with open("process.csv", encoding="utf-8") as f: for row in csv.DictReader(f): procs[row["pid"]] = row with open("flow.csv", encoding="utf-8") as f: flows = list(csv.DictReader(f)) errors = [] # 规则1:编号层级必须连续,P2.3 的父必须是 P2 for pid in procs: if "." in pid: parent = pid.rsplit(".", 1)[0] if parent not in procs: errors.append(f"{pid} 的父加工 {parent} 不存在") # 规则2:外部项之间、存储之间不允许直连 for f in flows: a, b = f["frm"][0], f["to"][0] if a == b and a in "SD": errors.append(f"{f['fid']} 两端都是 {a} 类节点,非法") # 规则3:每个加工至少一进一出,每个存储至少一进 in_cnt, out_cnt = defaultdict(int), defaultdict(int) for f in flows: out_cnt[f["frm"]] += 1 in_cnt[f["to"]] += 1 for pid in procs: if in_cnt[pid] == 0: errors.append(f"{pid} 没有任何输入流") if out_cnt[pid] == 0: errors.append(f"{pid} 没有任何输出流") print("\n".join(errors) if errors else "校验通过")

这段脚本做的是三件机械活:编号层级连续性、非法直连、孤立节点。参数上要注意两点,pid必须和图上完全一致,包括大小写和点号;frm和to只能填 P、D、S 三类编号,不要填中文名,否则规则2的首字符判断会失效。脚本判不出语义错误,比如"订单分类"到底该不该读顾客情况,但它能把 80% 的低级错误在评审前扫掉,剩下的 20% 留给走查。

5. 避坑:五类高频翻车的现象、原因与改法

下面五条都是我在评审现场真实见过的翻车,每条按现象、原因、解决三段写,照着对一遍能省下至少一轮返工。

5.1 数据流不经过加工,储户直接连到数据存储

现象:图上出现一条从外部项 S1 直接指向数据存储 D1 的箭头,标注"查询余额"。

原因:画图的人把"用户能看到什么"当成了"数据怎么走"。DFD 里任何进入系统的数据都必须经过加工,因为只有加工才能对数据做变换和判定,存储本身不会响应请求。

解决:在这条线上插入一个加工,哪怕它只是"查询帐目",也要有 P 编号。同时检查反向,是否存在存储直接连外部项的输出线,同样要补加工。这条规则还有个变体:两个数据存储之间直接连线,也是非法的,存储之间不能自己搬家。

5.2 父子图不平衡,子图凭空多出一条流

现象:关联图上只有 F1、F2 两条流,分解到顶层图后出现了 F3"不合格订单",父图里找不到对应项。

原因:分解过程中发现了新分支,但只改了子图,忘了回头补父图。这种情况在带判定逻辑的系统里几乎必然发生,因为关联图阶段很难预见所有异常分支。

解决:养成"自下而上回填"的习惯,子图每新增一条跨越边界的流,立刻回父图补画并标注同一编号。补不了就说明这条流本来就不该跨边界,应该收进某个加工内部。评审时优先看边界,边界上的每一条流都要能在上下两层找到对应。

5.3 把实物或动作当成数据流

现象:银行取款案例里画了一条"现金"流,从 P2 指向 S1;或者画了一条"点击提交"流,从 S1 指向 P1。

原因:把业务流程里的所有传递都当成了数据传递。DFD 描述的是信息运动,钞票、单据原件、鼠标点击都不属于数据。

解决:实物交付写进加工的功能描述,动作触发不作为流,改由外部项到加工的输入流体现——用户提交动作产生的是"取款单"这条数据流,动作本身不画。图例里可以加一行说明,避免下一版又被加回去。

5.4 数据存储当成传话筒,两个加工之间靠它硬连

现象:同一层里 P1 和 P2 之间没有任何数据流,但都连着 D1,D1 变成了一条隐形的传送带,图上完全看不出 P1 的输出去了哪。

原因:混淆了"共享存储"和"数据传递"。共享存储表达的是两个加工在不同时刻读写同一份数据,不表达前者把结果交给后者。

解决:先问业务上这两步之间有没有明确的交付物。有,就画一条数据流;没有,说明它们确实是异步的、通过存储解耦的,那就在存储名上体现职责,比如 D1 改成"待处理帐目表"。这一步判断错了,实现时就会出现"该同步的做成异步、该异步的做成同步"的架构级偏差。

5.5 分层过深与编号失控

现象:图分解到第四层,加工编号出现 P2.3.1.4,一张 A4 放不下,评审时没人愿意翻到最后一页。

原因:把"分解"当成了"细化"的唯一手段,遇到复杂逻辑就往下拆,拆到最后画的是程序流程图而不是数据流图。

解决:给层数设上限,业务系统三层基本够用,超过三层说明某个加工的职责本来就没想清楚。另一个手段是横向拆分,把一个巨型加工拆成几个平级加工,而不是继续纵向挖。编号方面,子层编号不要超过三段,P2.3.1 到头,再往下就该改用数据词典描述细节。

6. 一张自检表加十五分钟走查:把 DFD 钉在能签字的状态

图画完不等于能用,能签字的标准是别人照着图能复述系统在干什么、边界在哪、异常走哪条路。我固定用两样东西收尾:一张自检表,一次十五分钟走查。

自检表按符号分四组,逐项打勾,任何一项打不上就回去改:

检查组检查项通过标准
外部项每个 S 是否有进有出至少一条流与系统相连
加工每个 P 是否一进一出无孤立加工、无纯输出加工
数据流每条 F 两端是否合法不出现 S-S、D-D 直连
数据存储每个 D 是否被读写无只写不读的黑洞存储
分层父子边界流是否一致子图新增流已回填父图
命名是否有空泛命名无"数据""信息""处理"等词

走查环节我固定问四个问题,问完基本能判断这张图能不能交付。第一个问题:这套系统的输入是什么,从谁那里来?让对方指着图说,说不出来就是 S 层没画清。第二个问题:什么情况下这笔业务会被退回?这条最能暴露分支遗漏,很多人画了主流程忘了异常流。第三个问题:这份数据存在哪里,谁会去改它?用来验证数据存储的读写方是否完整。第四个问题:如果明天要加一个审批环节,你会插在哪两个加工之间?这个问题测的是分层是否合理,如果对方答"插不进去",说明中间缺了一层抽象。

这几个问题听着简单,实际用起来很扎人。有一次走查,业务方指着 D2"合格订单"问了一句"这个里面的订单有没有可能被改过",当场发现分类加工漏了一条回写路径,图上完全看不出来,但实现时一定会在联调阶段爆炸。这种事只有让业务方在自己的语言体系里提问才会浮出来,开发自查是查不到的。

进阶一点的做法是把自检表和第 4 章那段脚本接起来,CI 里跑一遍,编号和孤立节点的错误自动拦住,人只需要关注语义。这套组合我用在跨平台项目上,图改到第五版也没出现过编号对不上的情况。

血泪教训是早期我总觉得图是给自己看的,画完直接扔进文档库,等到联调时才发现某条流根本没实现,回头翻图发现图上也没画。从那以后我每次出 DFD,都强制先写 flow.csv 再画图,画完跑一遍脚本,最后拉业务方过那四个问题,一步都不跳。希望帮到你。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进