数据流图与数据字典:面向数据流的需求分析实践 简介这份PPT面向软件工程课程学习者与需求分析初学者围绕面向数据流的分析方法展开借助小型图书馆管理系统的案例讲解从现实业务到逻辑模型、物理模型的抽象与建模过程。压缩包内仅含1个PPT文件大小约1.41MB适合课堂讲授、复习整理与需求分析专题自学。已有225人学习下载。内容涵盖抽象、模型、需求获取与需求定义、功能性与非功能性需求、结构化与面向对象开发方法等知识点并串联借还书、图书增删、按作者或领域检索、借阅记录查询等需求场景帮助读者理解数据流向分析、当前系统与目标系统模型转换及需求验证思路可作为软件工程需求分析章节的配套学习材料。1. 面向数据流的需求分析一份能照着推演到落地的课件拆解很多人学软件工程卡住的地方不是不会写代码而是拿到一句做一个图书馆管理系统就无从下笔需求从哪来、怎么建模、模型和代码之间隔着什么。这份课件讲的就是这段空白——面向数据流的分析方法用一个小型图书馆管理系统当贯穿案例把现实世界到计算机世界的映射拆成物理模型、逻辑模型、目标系统逻辑模型、细化验证四步走。它适合两类人正在做课程设计、需要把需求文档写扎实的学生以及接了小型信息管理系统、需求访谈完却不知道怎么落成数据流图的从业者。课件里那套 DFD、数据字典、功能分解的推演路径是现在很多敏捷文档里被省略、但排查需求遗漏时最好用的后悔药。对面向数据流的分析方法这个说法先给个边界它不是画图技巧课核心是把系统看成一串加工和流动的数据用结构化分析SA的视角把功能、数据、行为三个领域逐一落地。课件里反复出现的抽象、模型、需求获取、功能性需求与非功能性需求分类是这套方法的骨架。下面按这套方法是什么 → 图书馆案例怎么一步步建模 → 参数与边界怎么写 → 坑在哪的顺序拆开每一步都能对着自己的项目抄。2. 从物理模型到逻辑模型把图书馆的五条需求拆成可建模的输入课件的第一个硬核动作是拿学生买教材举了个例子调查现实环境得到物理模型谁在哪个房间、走什么单据去掉非本质因素得到逻辑模型审查有效性、开发票、开领书单、发书再分析当前系统与目标系统的差别得到目标系统的逻辑模型。这条链路看着简单实际是需求分析里最容易翻车的地方——大部分人的调研停在了物理模型把教务科在信北 206 手工登记这种实现细节当成了需求。图书馆案例的五条功能正好可以按这个思路先做一次粗切借书还书是数据流的双向主干增删图书是数据维护分支按作者或专业领域检索是查询分支找出某读者借出的书、找出最近借走某本书的读者是两条反向追溯。这五条不是平级的前两条是事务型加工后三条是查询型加工建模时数据存储和加工的划分完全不同。先把它们按输入什么、加工什么、输出什么写下来再动手画图。2.1 五条功能的输入-加工-输出拆解表不用一上来就画 DFD先用一张表把每条需求的数据流对齐比直接画图少走很多弯路。这张表就是个草稿纸但它是后面所有图和数据字典的源头功能编号输入数据流加工输出数据流涉及数据存储F1 借书读者号、图书编号校验借阅资格与库存借阅记录、库存状态变更读者表、图书表、借阅记录表F2 还书图书编号核对借阅记录、更新库存归还确认、超期信息借阅记录表、图书表F3 增删图书图书信息 / 图书编号新增或注销图书记录操作结果图书表F4 检索图书作者名 / 专业领域匹配查询图书清单图书表F5 追溯借阅者图书编号按时间倒序匹配借阅记录读者信息借阅记录表、读者表这张表的意义在于它逼你把功能 4 供普通读者使用功能 1、2、5 供图书管理员使用这条角色约束提前落到数据流上F5 的输出是读者信息属于敏感数据只有管理员能触发F4 的输出是图书清单普通读者可触发。角色不是画在用例图上就完事它决定了加工由谁激活、数据存储谁可读谁可写。2.2 用 Python 把约束条件写成可执行的校验规则课件里给了三条必须满足的条件所有未借出的书随时可借同一时刻一本书不能既借出又被借阅一个读者一次借出的数目不超过预定值。这三条在文档里是自然语言在实现里必须变成判断分支否则需求评审时谁都说满足了上线后照样出现一本书被两个人同时借走。常见做法是先把约束写成状态机与计数规则再用一段最小可运行代码验证逻辑是否闭环。下面这段不是完整系统只是把约束条件翻译成判定函数用来在需求阶段就跟业务方对齐口径from dataclasses import dataclass MAX_BORROW 5 # 单个读者一次借出的上限对应课件中预定值 dataclass class Book: book_id: str author: str field: str is_out: bool False # 是否已借出唯一状态位 dataclass class Reader: reader_id: str borrowed: int 0 # 当前借出数量需与借阅记录保持一致 def can_borrow(book: Book, reader: Reader) - tuple[bool, str]: # 条件2书已被借出则拒绝保证一本不能同时被两人持有 if book.is_out: return False, 该书当前处于借出状态 # 条件3借出数量不得突破预定值 if reader.borrowed MAX_BORROW: return False, f已达借阅上限 {MAX_BORROW} 本 return True, 允许借阅 def borrow(book: Book, reader: Reader) - str: ok, msg can_borrow(book, reader) if not ok: return f借阅失败{msg} # 条件1未借出的书可借借出后立即置位避免同一时刻双重占用 book.is_out True reader.borrowed 1 return 借阅成功这段代码里is_out是单一状态位而不是在库/借出/预约多状态混用好处是条件 2 的判定只有一处不会出现两个字段互相矛盾的黑匣子。MAX_BORROW用常量而不是散落在各处的魔法数字因为课件明确说这是预定值意味着它是可配置的业务参数不是硬编码。can_borrow与borrow分开是为了让校验逻辑可以被查询类功能复用比如 F5 追溯时判断某本书当前状态。真做并发场景还要加锁或数据库行级锁这属于实现层但需求阶段就该把同一时刻这句话标注成需要事务保证不然评审时说同一时刻开发时各写各的。参数上要留意borrowed计数与借阅记录表存在冗余这是为了查询性能刻意做的反范式设计。代价是每次借还都必须双写一旦某次写失败就会出现计数与记录不一致。我的习惯是把计数改成由记录表聚合查询得出或者至少加一个定时对账任务别让两个真实来源互相打架。3. 数据流图分层与数据字典从顶层图推到二级图的具体画法面向数据流的分析方法落到交付物主要是分层数据流图加数据字典。课件里物理模型 → 逻辑模型 → 目标系统逻辑模型 → 细化这条线对应的就是 DFD 的逐层分解顶层图只画系统和外部实体一级图展开主要加工二级图再把每个加工拆细直到每个加工都能用一段结构化描述说清。分层的关键纪律是父子平衡父图上某条数据流的输入输出在子图里必须原样出现不能凭空多出或消失。这条纪律听着教条实际是抓需求遗漏最有效的检查手段。图书馆案例的顶层图有两个外部实体——图书管理员和普通读者中间一个加工图书馆管理系统数据流是借阅请求、检索请求、操作结果。到一级图加工拆成借还处理、图书维护、检索服务、借阅追溯四块数据存储出现图书表、读者表、借阅记录表三个。3.1 顶层图与一级图的平衡检查清单画完一级图别急着往下拆先做一次平衡核对。下面这张清单是我每次评审前都会过一遍的五个问题能挡掉大部分返工检查项判定标准图书馆案例中的对应点外部实体一致性顶层图与一级图的外部实体集合相同管理员、读者两个不多不少数据流守恒父图每条输入输出在子图中出现借阅请求必须流入借还处理数据存储无凭空产生每个存储至少有一个写入加工和一个读取加工借阅记录表由借还处理写、由追溯读加工命名动宾化加工名是动词名词不出现数据这类空词校验借阅资格合格处理数据不合格无孤立数据流每条流都有源和宿归还确认流向管理员第三项最容易被忽略。很多人画图时把读者表画上去但没有任何加工往里写数据这张表就成了装饰。要么补上读者注册加工要么把它从本层图里删掉留到后续迭代。3.2 数据字典的条目写法与一致性校验脚本DFD 只说明数据怎么流说不清数据长什么样这部分靠数据字典补。数据字典的条目分四类数据流、数据元素、数据存储、加工说明。每条定义用、、[]、{}这套记号描述结构比如借阅记录可以写成借阅记录 读者号 图书编号 借出日期 应还日期 归还日期。字典最怕的是与图脱节图改了字典没改两边各说各话。手工核对不现实写个小脚本做交叉校验更靠谱。下面这段读两份文本一份是数据流清单一份是字典条目检查每条流是否都有定义import re def load_flows(path: str) - set[str]: 读取数据流清单每行一条流名称 with open(path, encodingutf-8) as f: return {line.strip() for line in f if line.strip()} def load_dict_entries(path: str) - set[str]: 从数据字典中提取已定义的条目名形如 借阅记录 ... entries set() with open(path, encodingutf-8) as f: for line in f: m re.match(r^\s*([^\s])\s*, line) if m: entries.add(m.group(1)) return entries def check(flows_path: str, dict_path: str) - None: flows load_flows(flows_path) defined load_dict_entries(dict_path) # 图中出现但字典未定义的流是需求评审最该追问的部分 missing flows - defined # 字典里有但图中没有的条目通常是删图后忘记清理的残留 orphan defined - flows print(未定义的数据流, sorted(missing) or 无) print(字典中孤立条目, sorted(orphan) or 无) if __name__ __main__: check(flows.txt, data_dict.txt)逻辑很直白两个集合做差。missing是图里有、字典没有的流这类条目在评审时最危险因为没人说得清它的结构开发到一半才发现字段缺失。orphan是删改后留下的僵尸条目不影响功能但会误导后来人。参数上唯一要改的是文件路径和字典行的格式约定如果你的字典用 Markdown 表格维护把正则改成按竖线切分就行。提示这套校验只查有没有不查对不对。数据流的结构是否与数据存储字段吻合还得靠人工比对脚本只负责把遗漏摊到桌面上。4. 功能性需求与非功能性需求的边界图书馆案例里那些没写进图的东西课件把用户需求分成功能性需求和非功能性需求两类前者说系统做什么后者说系统工作时的特性。图书馆案例的五条功能全是功能性的但真正决定这个系统能不能用的往往是没画进 DFD 的那部分检索响应时间、并发借阅的吞吐、借阅记录保留多久、读者信息谁能看。这部分最容易被当成以后再说然后在验收时变成扯皮点。我的做法是在需求阶段就建一张非功能性需求表每条给出可测量的指标和验证方式哪怕指标是拍脑袋定的也比空着强。比如检索功能写按作者名检索应在 2 秒内返回前 50 条比写检索要快有用一百倍因为前者能在联调时直接测后者只能靠感觉吵架。4.1 非功能性需求的四类落点与量化写法课件列了性能需求、环境需求、界面需求、用户因素四类图书馆案例可以逐类落成具体条目类别课件中的关注点图书馆案例的量化写法验证方式性能响应时间、吞吐量、存储容量检索响应 ≤ 2s并发借阅 ≥ 20 请求/秒压测脚本统计 P95环境操作系统、网络、数据库单机部署浏览器访问无需外网部署清单核对界面数据格式、存储介质规定检索结果按书名、作者、状态三列展示原型走查用户因素用户类型、熟练程度、误操作可能读者端仅两个入口误操作需二次确认可用性测试这张表的作用不是凑文档而是把系统必须满足条件这类模糊表述逼成可验证项。课件里说一个读者一次借出的数目不能超过预定值这个预定值到底是多少、谁来改、改了要不要即时生效都属于非功能性范畴得单独约定。4.2 用状态表固化一本书同一时刻只能有一种归属借阅状态是这个系统里最容易出 bug 的地方因为它是并发写入的热点。与其在代码里到处加 if不如先把状态和合法迁移列成表让所有加工共用一份判定当前状态触发动作目标状态前置条件失败处理在库借书借出读者未达上限拒绝并提示原因借出还书在库存在未归还记录提示无有效借阅在库注销已注销无未归还记录拒绝注销借出注销不允许—提示先归还状态表定下来后DFD 里的校验借阅资格加工就有了明确输入输出数据字典里的图书状态字段也有了取值域。这套东西看着笨但它把课件里同一时刻一本书不能既被借出又被借阅这句自然语言变成了可测的规则。血泪经验是状态迁移表如果不提前画开发阶段每个模块都会自己发明一套判断最后合并时冲突到怀疑人生。5. 避坑与常见问题从课件方法落到真实项目时的五处翻车点课件讲的是方法方法本身没错错在落地时的简化。下面五条都是我在类似小型管理系统里真实踩过或见过的问题按现象、原因、解决三段写方便对照自查。5.1 把物理模型当需求图纸画得越细离需求越远现象需求文档里全是管理员在后台列表页点击新增按钮弹出表单填写 ISBN这类描述评审时业务方点头开发完却说不是想要的。原因停在了物理模型层把界面交互和操作步骤当成了需求。课件里去掉具体模型中的非本质因素这一步被跳过了导致实现细节污染了逻辑模型。解决每条需求回问一句这条描述去掉界面和操作顺序后还剩什么。剩下的是数据和处理规则那才是逻辑模型该有的内容。物理细节留到设计阶段需求文档里最多作为参考附注。5.2 DFD 父子图不平衡需求缺口在评审后才暴露现象顶层图有一条借阅请求流进系统一级图里却找不到对应加工或者一级图凭空多出一条顶层没有的数据流。原因分层是分批画的画子图时顺手加了新功能忘了回改父图。人多协作时更严重各画各的。解决每层图画完立刻做父子平衡核对用第 3 章那张清单逐项过。工具层面可以让 DFD 绘图软件做自动校验但自动校验只查结构不查语义数据流的名字对不上照样通过所以人工核对命名一致性不能省。5.3 数据字典与图脱节字段缺失在上线前才被发现现象开发到一半发现借阅记录缺归还日期或者检索功能需要的专业领域字段在图书表里根本没有。原因图改了字典没改或者字典是最后突击补的补的时候照着图抄图本身就有遗漏。解决字典与图同源维护改图必须同时改字典用 3.2 那段脚本做差集检查把缺失条目在每次评审前打印出来。更彻底的做法是把数据字典当成唯一事实来源图从字典生成虽然前期麻烦但后期省下的返工远大于投入。5.4 忽略角色与数据权限的绑定追溯功能成了隐私漏洞现象功能 5找出最近借走某本图书的读者做出来之后普通读者也能调用能看到别人借了什么书。原因课件明确写了功能 4 供普通读者、功能 1、2、5 供管理员但建模时角色只画在用例图上没有落到数据流的激活权限上开发时接口一律不加校验。解决在数据字典里给每个数据存储标注读权限和写权限在 DFD 上给每条流入敏感存储的流标注触发角色。接口层再做一次角色校验两层都做不是冗余是防止某一层被绕过。这类问题属于设计缺陷而非编码 bug测试阶段很难覆盖到只能靠建模时想清楚。5.5 约束条件写成自然语言并发场景直接失效现象单机测试全通过两个人同时借同一本书时都成功了库存变成负数或者出现两条借出记录。原因同一时刻一本书不能既被借出又被借阅这句话在文档里是约束在代码里没有对应的事务或锁校验与写入之间存在时间窗口。解决需求阶段就把这类约束标注为需事务保证并在数据字典里写明该书状态字段的更新必须原子。实现层用数据库行锁或乐观锁版本号别指望应用层先查后写能挡住并发。这条坑的教训是凡出现同一时刻同时不超过这类词都要单独拎出来问一句并发下还成立吗。6. 从课件到交付用一份需求追踪矩阵收口课件最后停在需求分析的验证但没给具体验证手段。真正让这套方法闭环的是一份需求追踪矩阵把每条功能需求、每条约束、每条非功能性指标映射到 DFD 的加工编号、数据字典条目和验收用例编号。矩阵不需要工具一张表就够但它是唯一能回答这条需求到底有没有被实现的东西。我的做法是三列对齐需求编号一列对应的一级图加工名一列验收用例编号一列。中间再插两列一列写涉及的数据存储一列写触发角色。填不满的行就是缺口要么需求没落图要么图没落测试。图书馆案例填完大概长这样需求编号加工数据存储触发角色用例编号F1 借书借还处理图书表、借阅记录表、读者表管理员TC-01F4 检索检索服务图书表读者、管理员TC-04F5 追溯借阅追溯借阅记录表、读者表管理员TC-05C2 唯一借出借还处理图书表—TC-11矩阵填完后还有一步验证容易被跳过拿用例反查需求。正向填表只能证明每条需求都有落点反向走一遍才能发现每个加工是否都有需求支撑。一级图里如果有个加工在矩阵里找不到对应需求行那它要么是多余设计要么是某条需求被漏写了——两种情况都值得停下来查。再补一个具体技巧约束类需求比如借出数量不超过预定值不要只挂在一个加工上它往往横跨借书、还书、追溯三个加工矩阵里应该出现多次。只挂一处的结果是开发在另一个加工里忘了校验测试也只测了挂靠的那个入口。我一般会在矩阵下方加一行备注写明该约束的全部生效点评审时逐点确认。从那以后我每次做这类小型信息系统的需求分析都会强制走一遍物理模型剥离 → 分层 DFD → 字典差集校验 → 追踪矩阵反查这四步哪怕项目再小也不省。省掉的每一步后面都会以返工的形式还回来。这份课件的价值不在它讲了多深的理论而在于它把一个完整案例的推演过程摊开给你看照着走一遍比读十篇方法论都实在。希望帮到你。本文还有配套的精品资源点击获取