简介:这份PPT面向软件工程课程学习者与需求分析入门者,围绕面向数据流的分析方法展开,重点解决从现实业务到逻辑模型、物理模型的建模与需求定义问题。压缩包仅含1个PPT文件,大小约1.41MB,内容以课堂讲义形式组织,便于按讲次查阅和复习。已有226人学习,说明其适合作为课堂配套资料使用。讲义以小型图书馆管理系统为例,串联借书、还书、增删图书、检索与借阅记录查询等需求,讲解抽象、模型、逻辑模型与物理模型、需求获取、功能性/非功能性需求、需求定义及分析验证等知识点,并对比结构化开发方法与面向对象开发方法。读者可据此理解数据流分析的基本流程、需求建模的表达方式及从当前系统到目标系统的转换思路,适合课程复习、作业参考和需求分析入门梳理。
1. 从一张借书单说起:面向数据流的分析方法到底在分析什么
去图书馆借一本书,你递出借书证,管理员在系统里敲几下键盘,这本书就从「在馆」变成了「借出」。整个过程里真正被搬来搬去的不是书,是数据:一条借阅记录、一次库存状态变更、一次借阅额度检查的结果。面向数据流的分析方法,就是把注意力集中到这些「搬来搬去的数据」上的一套需求建模办法——它先不问系统由哪些对象组成,而是问数据从哪来、经过哪些加工、存到什么地方、最后流向谁。软件工程里讲需求分析,这条路子流传了几十年,因为它要求你在动手写代码之前,先把「系统到底要处理哪些数据」说明白。搞懂它,再看需求评审会上那几张画着圆圈和箭头的图,就不会觉得那只是玄学。
2. 需求为什么不能直接开写:从物理模型到逻辑模型的关键一步
2.1 现实世界和计算机世界之间,隔着一层模型
一个校园教材采购场景:学生要买教材,先填一张购书申请,交到某个科室审查,审查通过后开发票、开领书单,学生拿着领书单去领书。这条线上有纸张、有办公室、有来回跑的人。这套东西在软件工程里叫当前系统的物理模型,它如实记录了现实里发生的一切,包括大量与「系统该做什么」毫无关系的信息:谁在哪间办公室、单据什么颜色、盖哪个章、走几层楼。
直接把这一套搬进计算机,得到的是一个照着现有流程复刻的电子壳子:原来的三个签字变成三次点击,原来的两张纸变成两个页面,效率没提高,毛病倒是一个不落全固化了。所以需求分析的第一步不是问「怎么把它做成软件」,而是先把物理模型里的非本质因素剥掉。剥完之后剩下的那层东西,才叫逻辑模型。物理模型回答「现在是怎么做的」,逻辑模型回答「本质上在做什么」,目标系统的逻辑模型回答「换成计算机做,应该做什么」。
这中间隔着一次映射:现实世界 → 概念符号模型 → 计算机世界。映射做得好不好,直接决定后面所有设计的返工量。
2.2 抽象:地铁图为什么不按真实比例画
抽象这个词被讲得太重,其实日常里到处都是。地铁线路图就是个好例子:它不按真实地理比例画,站点间距被拉平,线路被拉直,河流和街区统统消失。但在换乘这件事上,它比卫星地图好用一百倍。它舍弃的是地理精度,保留的是「哪条线在哪一站能换乘」这个连接关系。
需求分析里的抽象干的是同一件事:按你关心的维度保留,其余全丢掉。保留什么?输入是什么、做了什么处理、输出是什么、存了哪些数据。丢掉什么?用什么设备、谁坐在哪个屋、界面是蓝色还是绿色。抽象的结果是一套概念符号模型——数据流图、数据字典、加工说明,都属于这一类。它们的共同点是:纸上没有一个像素,但你能照着它把系统造出来。
提示:抽象不是「简化」,而是「有选择地省略」。省错了东西,图就变成废纸;省对了东西,图就是设计图纸。
2.3 当前系统的逻辑模型,和目标系统的逻辑模型
需求分析的过程可以拆成几步走:先调查现实环境,拿到当前系统的物理模型;再去掉非本质因素,抽出当前系统的逻辑模型;然后分析当前系统和目标系统的差别,建立目标系统的逻辑模型;接着细化、改进、优化;最后做需求验证。
用小型图书馆管理系统比一比就清楚了。现在借书靠手写登记本,逻辑上只有三件事:登记一条借阅关系、判断这本书是否在馆、判断这位读者还有没有额度。目标系统做的也还是这三件事,只是执行者从人变成了程序。差别不在「业务变了」,而在「谁来执行、执行得多快、能不能并发」。把这三件事写成处理逻辑,就是逻辑模型;把它落到具体界面、数据库表、服务器数量上,才回到物理模型。很多人一上来就聊数据库建几张表、接口怎么设计,本质是把物理模型当成了起点,跳过了中间那一层——后面需求一改,全盘翻车,血泪经验大多来自这里。
项目里的图书馆系统有两条明确的业务约束:馆内所有未借出的书必须能随时供读者借阅;同一时刻一本书不能既被借出又被借阅;一个读者一次借出的数量不能超过预定值。这三条在物理模型里体现为「管理员看一眼登记本」,在逻辑模型里就必须写成可判断的规则,否则程序根本没法执行。
2.4 功能需求管做什么,非功能需求管做到什么程度
需求分两条腿。功能性需求定义系统做什么,描述系统必须支持的功能和过程。图书馆系统里那几条就是典型的功能需求:借书、还书;增加或删除一本书;按作者名或专业领域检索一批书;找出某位读者借出的一批书;找出最近借走某本书的读者。系统有两类用户——图书管理员和普通读者,其中「找出某位读者借出的书」供普通读者用,借书、还书、增删图书、查最近借阅人这几项供管理员用。功能需求最怕写成一个动词短语就交差,「借书」两个字背后其实藏着校验、写入、更新状态三步。
非功能性需求定义系统工作时的特性,描述操作环境和性能目标。它通常包括存储容量限制、执行速度、响应时间、吞吐量这类性能指标;硬件设备、操作系统、网络、数据库这类环境约束;与外部系统的输入输出、数据格式、存储介质这类界面约定;以及用户类型、熟练程度、培训需求、误操作可能性这类人的因素。这类需求最容易被写成一句「系统要快」,然后被所有人忽略,直到上线那天才发现检索一万本书要等八秒。
| 需求类型 | 回答的问题 | 图书馆系统里的例子 |
|---|---|---|
| 功能需求 | 系统做什么 | 借书、还书、增删图书、按作者检索、查借阅人 |
| 性能需求 | 做得多快、能扛多少 | 检索响应时间、并发借阅处理能力 |
| 环境需求 | 跑在什么上面 | 数据库类型、网络条件、部署位置 |
| 界面需求 | 和外界怎么交换数据 | 书目数据导入格式、借阅记录导出格式 |
| 用户因素 | 谁在用、好不好用 | 读者自助检索的易用性、管理员的误操作容忍度 |
需求分析要达成的目标也就清楚了:给出数据领域、功能领域、行为领域三个方面的模型;提出详细的功能说明,确定设计约束条件,规定性能要求;同时保持和用户的密切沟通,让用户明确自己那一侧要配合什么。这三件事缺一件,需求文档就只是写给自己看的。
3. 数据流方法的三件套:数据流图、数据字典、加工说明
3.1 数据流图里只有四种角色
数据流图看起来符号很多,其实只有四种角色在台上。外部实体是系统边界之外、跟系统打交道的人或系统,图书馆系统里就是读者和图书管理员。加工是对数据做变换的动作,借书处理、还书处理、图书维护、检索服务,都是加工。数据存储是数据待着不动的地方,图书目录、借阅记录、读者档案。数据流是数据在它们之间移动的路径,一张借书请求从读者流向借书处理,一条借阅记录从借书处理流向借阅记录存储。
这四种角色构成一套极简语法,好处是逼你把「谁给的数据、经过什么处理、存到哪、给谁看」四件事一次说全。需要注意:数据流图画的是数据怎么流动,不是程序执行顺序,也不表达判断和循环。图上不会出现「如果书已借出则提示失败」这种分支,那属于加工说明的内容。初学者最容易在这上面出错,把数据流图画成带菱形判断框的流程图,画完自己还挺满意,评审时被问一句「你这个箭头是数据还是控制信号」就卡住了。
3.2 分层:从一张顶层图逐层往下拆
真实系统的数据流图不可能只有一张,那样画出来会像一团毛线。常规做法是分层:顶层图只画系统作为一个整体黑匣子,和外部实体之间的输入输出;0 层图把黑匣子打开,露出里面的主要加工;再往下每一层继续拆,直到每个加工都小到能写清楚一段说明。
图书馆系统的顶层图很干净:读者给出借阅请求,系统返回借阅结果;管理员给出图书维护指令,系统返回处理结果。到了 0 层,就能看到借书处理、还书处理、图书维护、检索服务四块,它们共同读写图书目录和借阅记录两个存储。再往下拆借书处理,会露出「校验读者状态」「校验图书状态」「写入借阅记录」「更新图书状态」几个子加工。
分层画的时候要守住一条规则:父子平衡。上层某个加工的输入输出数据流,必须和它拆开之后那一层图边界上的输入输出对得上,不能凭空多出来一条,也不能悄悄少一条。这条规则很枯燥,但它是唯一能防止「画到第三层发现对不上、只好回去改第一层」的机制。
3.3 数据字典:把每条数据流说清楚
图能让结构一眼看清楚,但图上的每条箭头都得有个准确含义。数据字典干的就是这件事:把数据流、数据项、数据存储、加工的定义统一登记下来,让所有人对同一个名字有同一个理解。没有它,同一张图上「借阅记录」可能在一个人脑子里是书名加日期,在另一个人脑子里还包括罚款金额,等做出来才发现差了一截。
数据字典常用几个简单符号:等号表示定义,加号表示顺序连接,竖线表示从中选一个,花括号表示重复若干次,圆括号表示可选。举个简化例子,「借阅记录 = 读者编号 + 图书编号 + 借出日期 + (归还日期)」,读起来就是一条借阅记录由读者编号、图书编号、借出日期顺序组成,归还日期可能为空。「图书目录 = {图书条目}」,表示图书目录是若干图书条目的集合。这些符号不复杂,价值在于强制你把含糊的词拆到不能再拆。
| 条目名 | 类型 | 简述 | 组成 |
|---|---|---|---|
| 借阅请求 | 数据流 | 读者发起借书时的输入 | 读者编号 + 图书编号 |
| 借阅记录 | 数据存储 | 记录谁借了什么、何时借何时还 | 读者编号 + 图书编号 + 借出日期 + (归还日期) |
| 图书条目 | 数据项组 | 一本书的登记信息 | 图书编号 + 书名 + 作者 + 专业领域 + 在馆状态 |
| 借阅额度 | 数据项 | 单个读者可同时借阅的上限 | 整数 |
3.4 加工说明:小说明怎么写才不靠猜
数据流图的最底层加工没法再拆了,这时候要靠加工说明把它讲清楚。常用的三种写法是结构化语言、判定表、判定树。结构化语言接近自然语言但更克制,判定表适合规则多、条件交叉的情况,判定树把条件一层层展开更直观。
拿借书这个加工来说,文字写「校验读者和图书状态,通过后写入借阅记录」太糊,写成可判定的逻辑才没有歧义:
# 借书加工的判定逻辑:对应数据字典里的借阅请求、借阅记录、借阅额度 def check_borrow(book, reader, limit): # 规则一:同一时刻一本书不能既被借出又被借阅 if book.status != "在馆": return False, "该书已借出" # 规则二:读者一次借出的数量不能超过预定值 if reader.borrowed_count >= limit: return False, "已达借阅上限" # 规则三:读者状态必须可用(未挂失、未过期) if not reader.active: return False, "读者状态异常" return True, "可以借阅"这段代码不是让你真去实现系统,而是演示加工说明该精确到什么程度。三个参数正好对应数据字典里的三个条目:book是图书条目,reader是读者档案,limit是借阅额度。每一条 if 分支都来自现实世界里的一条业务约束,反过来也能验证数据字典是不是漏了字段——比如你想写「读者状态异常」却发现自己没定义读者状态,那就是字典缺项。三种写法里,规则少就用结构化语言,规则交叉多就上判定表,条件有层次就用判定树,选哪个不重要,写到别人能照着测才算过关。
4. 面向数据流还是面向对象:两种建模视角的分界线
4.1 一个顺着信息流向切,一个顺着信息内容切
现有的需求分析建模方法,可以按关注点分成两大阵营。面向信息流向的一派,代表是结构化分析方法,它顺着数据在系统里怎么流动来切分系统;面向信息内容的一派,代表是面向对象分析方法,它顺着数据本身由什么构成、有哪些行为来切分系统。描述系统需求时,本来就可以从功能、行为、信息三个侧面入手,侧重点不同,画出来的图自然不一样。
结构化方法的核心产物是一组图加一套字典,讲的是「数据从 A 到 B 经过哪些变换」。面向对象方法的核心产物是类、属性、方法、关系,讲的是「这个东西是什么、能干什么、和谁有关系」。同一个图书馆系统,结构化视角看到的是借书处理、还书处理、检索服务几条流水线;面向对象视角看到的是图书、读者、借阅记录几个对象,借书是读者对象和图书对象之间发生的一次交互。
这两种视角不存在谁更先进的问题,它们回答的是不同的问题。就像描述一栋楼,你可以画人流的动线图,也可以画房间的功能分区图,两张图都正确,但你要拿去审批消防通道,动线图更管用。
4.2 为什么结构化方法天然偏爱数据流
结构化开发方法有一条贯穿始终的思路:自顶向下、逐层分解。这条思路和数据流是天生一对。因为数据流天然有层级——顶层看整个系统的进出,往下一层看几大处理块之间的流转,再往下一层看单个处理块内部的细节。每一层都是一次「把黑匣子打开」,打开的依据就是数据在这个加工内部怎么变。
这套分解还有个副产品:它能顺手暴露数据的不一致。某个数据项在 0 层图里出现,在 1 层图里消失了,或者某个存储只写不读,一眼就能看出来。结构化方法在信息管理系统、批处理系统这类「数据进出清晰、加工链条长」的场景里特别顺手,原因就在这。
面向对象方法的长处则在另一头:当系统里对象关系复杂、状态多、行为需要封装时,按数据内容切分更能控制复杂度。两种方法后来在实践里也经常混着用——先用数据流把业务流程理清楚,再用对象模型把领域概念固定下来,这不算犯规。
4.3 两种方法不是新替旧的关系
| 对比维度 | 面向数据流(结构化分析) | 面向对象分析 |
|---|---|---|
| 切分依据 | 数据流向与加工过程 | 信息内容与对象职责 |
| 主要产物 | 数据流图、数据字典、加工说明 | 类图、用例、交互序列 |
| 擅长场景 | 信息管理系统、批处理、流程清晰的数据加工 | 对象关系复杂、状态多、需要长期演进的系统 |
| 对需求变更的耐受 | 流程一变就要改图,改动面较大 | 对象边界稳定时,变更局部化更好 |
| 沟通对象 | 业务人员容易看懂箭头和加工 | 技术人员更容易对齐设计 |
看完这张表,会发现选择的关键不在「哪个新」,而在「这次的问题长什么样」。业务流程占主导、数据加工链条长、需要和不懂技术的业务方对齐,那就先上数据流。领域概念复杂、对象之间交互频繁、后续要反复迭代,那就先上对象模型。硬要把一个实时控制系统画成数据流图,画到第三层你就会发现自己不得不往里塞控制信号,而控制流本来就不是它该画的东西。
5. 五个一学就混的地方:把数据流方法用错的常见误区
5.1 把数据流图当流程图
最容易混的一对。数据流图上的箭头表示数据在移动,流程图上的箭头表示执行顺序,还带菱形判断和回退。混的原因很实在:两者都长着箭头和方框,画在纸上远看差不多。
区分办法很简单:问一句「这条箭头上流的是什么」。能说出一个具体的数据名词,比如借阅请求、借阅记录、检索条件,那就是数据流;如果这条箭头表达的是「先做这个再做那个」,或者「如果失败就回到上一步」,那它就是控制流,不该出现在数据流图上。判断和循环要写进加工说明,而不是画进图里。
5.2 物理模型和逻辑模型分不清
混的原因在于两者经常同时出现在一张草图上:左边写着「管理员在借阅台登记」,右边画着数据库表,中间还夹着服务器部署。看着挺完整,其实三个层次糊在一起了。
区分办法是看它是否依赖具体实现。如果描述里出现「在哪个屋」「用什么设备」「几张表」「什么界面」,那是物理模型;如果只剩「输入什么、做什么判断、输出什么、存哪些数据」,那是逻辑模型。做需求分析时,先老老实实把逻辑模型画干净,再往物理模型落,顺序反了就会把实现细节当成需求本身,后面改一处牵动全身。
5.3 需求分析和需求定义当成同一件事
很多人把这两个词当同义词用。混的原因是两个阶段都在跟用户聊、都在产出文档,边界不明显。
区分办法看产出物的性质。需求分析偏「摸清楚」:调查现实环境、抽取逻辑模型、分析当前与目标的差别,产出的是模型和说明。需求定义偏「定下来」:确定数据领域、功能领域、行为领域三方面的模型,提出详细功能说明,确定设计约束,规定性能要求,产出的是可以拿去评审、签字、作为验收依据的东西。分析做完了不等于定义做完了,中间还差一次和用户的确认。
5.4 只写功能需求,把约束当注释
这是最容易在项目后期出问题的一条。功能需求写得很欢,借书还书增删检索一条不落,非功能需求就一句「系统要稳定、响应要快」。混的原因在于约束类需求不好写,写「同一时刻一本书不能既被借出又被借阅」比写「支持借书功能」费劲得多。
区分办法是拿一个笨办法逐条过:这个功能在什么情况下会失败?失败时系统该给什么反馈?同时有两个人操作会怎样?数据量涨十倍还撑得住吗?图书馆系统里那三条约束,本质上就是三个必须写进需求文档的失败条件。把这些当成注释随手记在页边,最后十有八九没人实现。
5.5 数据字典当成可选的装饰
图画得漂亮,字典随便写两行,觉得反正大家看得懂。混的原因在于图的直观性太强,让人误以为理解已经对齐了。
区分办法是做个测试:随便挑图上一个数据流名字,让三个人分别说出它由哪些数据项组成。说得一致,字典可以少写;说得不一致,说明这个名字背后藏着三种理解。数据字典的价值就在这种笨拙的地方,它把「大家应该都懂」变成「白纸黑字写着」。
6. 什么时候该画数据流图,什么时候别硬套
先说适合的情况。业务流程占主导、数据加工链条长、参与方多且不懂技术,这类需求用数据流方法梳理最顺。典型如信息管理系统、报表统计、审批流程、数据迁移——它们的共同点是「输入、处理、输出、存储」四件事能说清楚,而系统里真正复杂的不是对象关系,是流程分支和数据口径。这类场景里,一张 0 层图往往比十页文字更能让业务方点头,因为它把「你的数据从哪来、我加工完给谁」摆在了明面上。
再说别硬套的情况。实时控制系统、强交互产品、算法密集型模块,这三类都不太适合。实时控制里真正关键的是状态机和控制信号,数据流图根本没法表达「两秒内必须响应中断」这种时序约束;强交互产品关心的是界面状态和用户路径,用加工和数据存储去描述会非常别扭;算法密集型模块的重点在计算过程本身,画一堆数据流出来,信息量还不如一段伪代码。
拿图书馆系统做个具体判断。需求有六条:借书、还书、增删图书、按作者或专业领域检索、查某读者借出的书、查最近借走某本书的读者。三类用户权限清楚,两条硬约束明确。这些需求几乎全是「数据进—加工—数据出」的形状,画数据流图收益很高。但如果你要给这个系统加一个「扫码即借」的移动端,那部分涉及设备交互、权限弹窗、网络异常重试,就不该继续用数据流图硬画,交给用例和交互设计更合适。
还有一个更实际的判断法:看你的改动成本落在哪。如果需求变更主要是「流程加一个分支」「多一类数据来源」,数据流图改起来很轻,加一个加工、补两条数据流、同步数据字典就行。如果变更主要是「对象多了一种状态」「对象之间的关系变复杂」,那数据流图会越改越乱,这时候该换视角了。
注意:数据流图不是画得越细越好。每层控制在七上八下(七个左右加工)是人能读进去的上限,超过就该再分一层,否则评审时没人看得下去。
我自己的习惯是,任何需求文档交出去之前,先拿一张白纸把顶层图画一遍,只画系统边界和外部实体,逼自己回答两个问题:谁给我数据,我把数据给谁。画不出来,说明这需求压根没想清楚,先别急着开会。画得出来,再往下拆一层,看看有没有哪个加工我写不出一句准确的说明——写不出来的那个,通常就是后面会出问题的地方。这个笨办法救过我几次,从那以后我每次评审需求都强制走一遍,图可以不给人看,但那两个问题必须自己答上来。希望帮到你。
本文还有配套的精品资源,点击获取