学生成绩管理系统软件结构图:功能层次、数据流与模块调用推演
简介:《学生成绩管理系统软件结构图》是一份面向软件工程课程设计、系统分析与设计学习者的结构图文档,适合正在完成课程作业、撰写设计报告或梳理成绩管理模块划分的读者参考。压缩包内共1个docx文件,约235KB,集中呈现软件功能层次图、以数据为中心的体系结构、数据流图以及教师服务子系统和学生服务子系统结构图,便于按章节对照理解模块关系。已有5765人学习,说明其在同类课程资料中具有一定参考价值。文档围绕身份验证、成绩录入查询、排序处理、统计分析与系统初始化等模块展开,可帮助读者掌握从需求分析到软件结构图绘制的表达方式,并用作报告插图、结构梳理和设计思路借鉴。
1. 学生成绩管理系统软件结构图画不出来,问题往往不在代码
很多人做学生成绩管理系统的课设,代码能跑、登录能进、成绩能查,可一到要交软件结构图这一步就卡住了:功能层次图上列出的模块,软件结构图里找不到对应;数据流图里画的数据存储,数据库表里没有对应字段;教师端和学生端画得像两份不同的系统。答辩时被问一句“这个模块扇入是几、为什么放在这一层”就答不上来。这套方案要解决的其实只是从需求分析到四张图的完整推演路径,即“怎么让需求条目、数据流、模块调用三层彼此对得上”这个问题,并非“怎么写出一个能跑的系统”。它适合正在做软件工程课设、需要交一整套结构设计文档的人,也适合接手一个以数据为中心的管理系统、想先把结构拆干净再动手写代码的开发者。
2. 功能层次图:教师与大学生的权限边界怎么划
功能层次图是第一张要交的图,也是最容易被判“层级混乱”的一张。它只回答一个问题:这个系统由哪些功能组成、这些功能怎么分层归属。它不涉及调用顺序,也不涉及数据怎么流动。很多人画错,是因为把后面结构图的模块调用关系提前塞了进来,结果图上出现了“查询成绩调用排序成绩”这种带方向的箭头。功能层次图通常用树形结构表达,父节点是上层功能,子节点是它的细化,同一层节点之间是并列关系,不表达先后。
2.1 需求条目到功能分解的三层落法
拿到需求文字后,先不要急着画矩形框。我的习惯是逐句把需求拆成“角色 + 动作 + 对象”的短句,再往上归并。成绩管理系统的需求大致能拆出这么几条:
- 教师输入账号密码登录,系统验证身份,无效提示原因
- 学生输入账号密码登录,系统验证身份,无效提示原因
- 教师按学号插入学生信息和成绩
- 教师按学号查询学生信息和成绩
- 教师对成绩做排序处理
- 教师横向比较、分析学生成绩
- 学生按学号查询本人信息和成绩
- 学生查看本人成绩的排序结果与自身统计
- 系统启动时完成运行环境搭建
- 系统向不同角色展示对应菜单
这十条落到功能层次图上,按“系统级—子系统级—功能级”三层归并。系统级只有一层:学生成绩管理系统。子系统级按角色切两块:教师服务子系统、学生服务子系统,外加一块不属于任何角色的公共支撑(身份验证、系统初始化、菜单显示)。功能级就是上面每条短句对应的具体动作。三层的好处是粒度自洽:子系统级的节点是“给谁用”,功能级的节点是“能干什么”,两层职责不重叠。
这里有一个反直觉的点:身份验证不放在子系统里,而是提到公共层。原因是教师和学生走的是同一套验证逻辑,只是校验后的分支不同。如果把它复制进两个子系统,功能层次图上就会出现两个完全相同的子树,这在评审里是典型的冗余扣分项。通常的做法是画成公共支撑节点,两个子系统通过一条无箭头的归属线挂在它下面,表示“共用”。
2.2 教师端与学生端的功能差异用一张表压住
功能层次图画完,紧接着要解释“为什么教师有、学生没有”。这张差异表我每次都会附在图的后面,它比图上任何一条线都更能说明设计的合理性。
| 功能点 | 教师端 | 学生端 | 设计依据 |
|---|---|---|---|
| 身份验证 | 支持 | 支持 | 公共模块,按角色分流 |
| 学生信息插入 | 支持 | 不支持 | 学生无建档权限 |
| 成绩录入 | 支持 | 不支持 | 录入是教师专属写操作 |
| 成绩查询 | 任意学号 | 仅本人学号 | 数据范围由登录态决定 |
| 成绩排序 | 按课程、班级 | 仅本人成绩序列 | 学生端不需要横向对比 |
| 成绩分析 | 平均分、及格率、分段分布 | 本人总分、均分、排名 | 分析维度不同,共用统计内核 |
| 系统初始化 | 不感知 | 不感知 | 启动阶段执行,角色无感 |
| 菜单显示 | 教师菜单 | 学生菜单 | 菜单项由角色动态生成 |
表格里“数据范围由登录态决定”这一行很关键,它把权限控制从“功能有没有”变成了“同一功能的数据边界不同”。这样做的好处是功能层次图上教师端和学生端可以共用“成绩查询”这个功能节点,只是标注不同的数据范围,图面干净,也不会被质疑“两个子系统为什么长得一模一样”。
2.3 层级判定的三个自查问题
功能层次图画完,拿这三个问题过一遍,基本能挡住大部分返工。
第一,每个叶子节点是不是一个可独立测试的动作。“成绩管理”不是叶子,它下面还得拆出插入、查询、修改;“成绩查询”是叶子,因为它对应一次完整的输入输出。如果叶子上出现“处理”“管理”“操作”这类词,说明粒度还不够细。
第二,有没有跨层调用。父节点直接调用孙节点、或者孙节点反向调用父节点,都会让层级失效。系统初始化归公共层,它只负责建连接、加载配置、初始化菜单,不参与任何成绩业务;一旦它去调成绩查询,整棵树就乱了。
第三,同一层节点的粒度是否一致。“成绩管理”和“成绩排序”并列是错的,前者是集合,后者是子集。要么都写成“成绩插入”“成绩查询”“成绩排序”,要么统一收在“成绩管理”之下。这个错误在课设里出现频率极高,答辩时几乎必被点出来。
把这三条落到图上,功能层次图的骨架大致是:根节点下挂三个分支,教师服务子系统下挂身份验证入口、学生信息维护、成绩录入、成绩查询、成绩排序、成绩分析、菜单展示;学生服务子系统下挂身份验证入口、个人信息查询、本人成绩查询、本人成绩排序、个人统计、菜单展示;公共支撑下挂系统初始化、数据库连接、日志记录。到这里,第一张图才算立住。
3. 数据为中心的体系结构:数据流图为什么要用事务分析
功能层次图解决“有什么”,软件体系结构解决“靠什么串起来”。成绩管理系统的特点很明确:教师录、学生查,两边操作的是同一份成绩数据,业务逻辑之间几乎没有直接调用关系。插入成绩不需要通知查询模块,查询也不依赖排序模块的执行结果。所有模块围绕同一份数据存储协调工作,这就是典型的以数据为中心的体系结构。它的优点是模块之间松耦合,新增一个“成绩导出”模块时不用改任何已有模块,只要它能读这张表就行;代价是数据模型必须先设计稳定,一旦成绩表的粒度变了,所有模块都得跟着改。所以后面的数据流图和表结构必须一次对齐。
3.1 从顶层数据流到事务分支的分解
数据流图要分层画。顶层图只有三个元素:外部实体(教师、学生)、加工(学生成绩管理系统)、数据存储(成绩库)。教师和学生分别向系统提交登录凭证和业务请求,系统返回结果。这一层不展开任何内部细节。
到了 0 层,就要引入身份验证这个环节了。原文在这里做了一个很关键的处理:在原有数据流之上增加用户身份验证,然后对关联图做细化和修改。这一步的实质是把“一个入口”改成“带分支的入口”,也就是事务分析。
事务分析适用于数据流图里存在一个明显的事务中心,它根据输入数据的类型选择一条处理路径。在这个系统里,验证模块就是事务中心:它接收登录请求,判断角色,然后分派到教师处理路径或学生处理路径。两条路径后续互不交叉,直到最后写回同一份数据存储。用文字描述这个 0 层图的结构是这样的:
- 加工 P1 身份验证:输入为登录请求(账号、密码、角色声明),输出为验证结果和角色标识
- 加工 P2 教师业务处理:输入为教师请求和角色标识,访问学生信息存储与成绩存储,输出教师视图数据
- 加工 P3 学生业务处理:输入为学生请求和角色标识,只读访问成绩存储,输出学生视图数据
- 数据存储 D1 学生信息表、D2 成绩表、D3 用户表
- 数据流:登录请求 → P1;P1 的验证结果 → P2 或 P3(二选一,这是事务分支);P2 ↔ D1/D2;P3 → D2(单向读)
需要强调的是,数据流图里不要出现判断菱形和循环箭头。事务分支在 DFD 里表现为同一个加工的多条输出流,各自标注条件,而不是流程图的控制结构。把 DFD 画成流程图的,是课设里第二常见的翻车点,评审一眼就能看出来。
3.2 数据字典与表结构的对齐
图上的每一个数据存储和数据流,都要在数据字典里有条目,并且能落到具体的表字段。成绩管理系统的最小表集合是四张:学生表、课程表、成绩表、用户表。下面这段建表语句可以直接拿去改,字段顺序和命名我都按数据流的方向排过。
-- 学生成绩管理系统核心表结构,与数据流图中的 D1/D2/D3 一一对应 CREATE TABLE student ( stu_id VARCHAR(12) PRIMARY KEY, -- 学号,同时是查询入口参数 stu_name VARCHAR(32) NOT NULL, class_id VARCHAR(16) NOT NULL, -- 班级,教师端排序和统计的分组依据 major VARCHAR(32) ); CREATE TABLE course ( course_id VARCHAR(12) PRIMARY KEY, course_name VARCHAR(48) NOT NULL, credit DECIMAL(3,1) NOT NULL ); CREATE TABLE score ( stu_id VARCHAR(12) NOT NULL, course_id VARCHAR(12) NOT NULL, score DECIMAL(5,1) CHECK (score BETWEEN 0 AND 100), term VARCHAR(16) NOT NULL, -- 学期,区分同一门课的多次修读 PRIMARY KEY (stu_id, course_id, term), FOREIGN KEY (stu_id) REFERENCES student(stu_id), FOREIGN KEY (course_id) REFERENCES course(course_id) ); CREATE TABLE sys_user ( user_id VARCHAR(12) PRIMARY KEY, -- 教师工号或学生学号,与业务表同源 password VARCHAR(64) NOT NULL, -- 存加盐哈希,不落明文 role CHAR(1) NOT NULL CHECK (role IN ('T','S')) -- T 教师,S 学生 );几点说明。第一,score 表用(stu_id, course_id, term)做联合主键,而不是另加自增 id,原因是“一个学生一门课一学期只有一条成绩”这条业务约束本身就是主键,用联合主键可以省掉一次唯一性校验,也让数据流图上“按学号查询”能直接走主键索引。第二,score 表不加冗余的姓名和课程名字段,展示时靠连接查询取,避免数据流图上出现两个来源的同一数据。第三,sys_user 的 role 字段是事务分析的物理落点,P1 加工判断角色时读的就是它,不用去两张业务表里猜身份。第四,成绩字段加了 0 到 100 的检查约束,这条约束在数据字典里要写成“成绩取值范围 0 到 100,越界由 DBMS 拒绝”,不要写成“由程序判断”。把校验放在数据库层,是让数据流图上的加工不必重复承担校验职责,图面会更干净。
3.3 数据流图与表结构的双向校验
画完图和表,做一次双向校验,能省掉答辩现场一半的追问。正向看:每一条数据流,它的组成项能不能在表字段里找到落点。比如“成绩查询请求”的组成是学号加学期,对应 score 表的 stu_id 和 term,能找到,通过;“教师分析请求”如果只写了课程号,却要输出分段分布,那就得再补一个学期参数,否则同一门课多个学期的成绩会混在一起统计。反向看:每一张表的每个非空字段,是不是至少有一条数据流会写入它。class_id 由学生信息插入流写入,通过;如果某张表里有个字段既不被任何流写入,也不被任何流读取,那它就是冗余字段,要么删掉,要么在图上补一条流说明它的来源。
这个校验做下来,通常会暴露两类问题:一类是图上画了但表里没建的存储,另一类是表里建了但图上没画的数据流。前者补建表,后者要么补流要么删字段,二选一,不要留着。我一般会在文档里附一张对照表,左边是数据流名,右边是涉及的表和字段,一眼就能看出哪里断了。
4. 软件结构图:从数据流图映射到模块调用关系
软件结构图也叫 SC 图,是四张图里唯一直接对应代码组织方式的一张。它由模块、调用关系、数据信息和控制信息构成,衡量指标是扇入、扇出、深度和宽度。从数据流图到结构图的映射有两条路:变换分析适合“输入—处理—输出”串行的部分,事务分析适合“根据类型分流”的部分。这个系统两种都要用:身份验证之后是按角色分流的,属于事务型;进入各自子系统后,成绩录入、查询、排序、分析是围绕数据的串行加工,属于变换型。
4.1 变换映射与事务映射的分工
先处理事务部分。数据流图上的事务中心是身份验证,结构图上对应的就是一个调度模块:它接收登录信息,校验,然后调用教师主控或学生主控。这个模块的扇出是 2,扇入是 1(由顶层主控调用),职责单一,不带任何业务逻辑。
再处理变换部分。以教师端为例,从数据流上能识别出三段:输入段(接收学号、课程号、成绩值)、变换中心(写入成绩、计算统计量)、输出段(格式化展示)。映射到结构图上是三层:教师主控负责协调,下面挂录入、查询、排序、分析四个业务模块,再下面挂一个公共的数据访问模块。这里要特别注意,数据访问模块的扇入会很高,四个业务模块都要调它。扇入高本身不是坏事,它意味着复用充分;真正要控制的是扇出:一个模块直接调用的下级模块不要超过七个,超过就说明它承担的职责太多,需要拆。
结构图的深度和宽度也要看一眼。这个系统合理的深度是四层:顶层主控 → 角色主控 → 业务模块 → 数据访问,再加一层叶子级的工具函数就是五层。如果画出来只有两层,说明分解不足;如果超过六层,多半是中间加了没有实际职责的转发模块,这种模块在评审里叫“空壳模块”,是扣分项。
4.2 教师服务子系统的模块划分与接口定义
把教师端拆成模块,每个模块给出编号、职责、输入、输出和扇入扇出,这张表比图更耐看,也方便后面写代码时对号入座。
| 编号 | 模块名 | 职责 | 输入 | 输出 | 扇入 | 扇出 |
|---|---|---|---|---|---|---|
| M1 | 系统主控 | 初始化、调度角色主控 | 启动信号 | 主界面 | 1 | 2 |
| M2 | 身份验证 | 校验账号密码,返回角色 | 账号、密码 | 角色标识、提示 | 2 | 1 |
| M3 | 教师主控 | 接收教师指令并分派 | 角色标识、菜单指令 | 业务结果 | 1 | 4 |
| M4 | 成绩录入 | 按学号写入或更新成绩 | 学号、课程号、分数、学期 | 写入结果 | 1 | 1 |
| M5 | 成绩查询 | 按条件检索成绩记录 | 学号或课程号、学期 | 成绩记录集 | 2 | 1 |
| M6 | 成绩排序 | 对记录集排序 | 记录集、排序键 | 有序记录集 | 1 | 1 |
| M7 | 成绩分析 | 计算均分、及格率、分段分布 | 课程号、学期 | 统计结果 | 1 | 1 |
| M8 | 数据访问 | 统一封装增删改查 | SQL 参数 | 结果集 | 4 | 0 |
M8 的扇入是 4,说明它是这个子系统里复用最充分的模块,也意味着它一旦出问题,四个业务模块全挂。所以数据访问模块要做两件事:参数化查询,禁止拼字符串;统一异常转换,把数据库异常翻译成业务层能识别的错误码。这两件事写在结构图下面的注释里,评审看了会加分。
对应的接口骨架大致如下,函数名和表里的模块名一一对应,参数里凡是带operator_id的,都是为了在业务层做一次数据范围校验:
# 教师服务子系统接口骨架,一个函数对应结构图上的一个业务模块 def verify_user(user_id: str, password: str) -> dict: """M2 身份验证:返回 {'ok': bool, 'role': 'T'/'S', 'msg': str}""" def insert_score(operator_id: str, stu_id: str, course_id: str, score: float, term: str) -> bool: """M4 成绩录入:operator_id 用于确认调用者具备教师角色""" def query_score(operator_id: str, stu_id: str = None, course_id: str = None, term: str = None) -> list: """M5 成绩查询:教师可传任意学号,参数为空表示按课程批量查""" def sort_score(records: list, key: str = "score", reverse: bool = True) -> list: """M6 成绩排序:稳定排序,同分时保持原始录入顺序""" def analyze_score(course_id: str, term: str) -> dict: """M7 成绩分析:返回均分、最高分、最低分、及格率、分段人数"""参数设计上有两个点值得说。第一,query_score的学号做成可选参数,教师不传学号就按课程批量查,这是教师端“整体宏观比较”的需求落点;如果做成必填,教师想看全班分布就得循环调用,接口和需求对不上。第二,sort_score接收的是记录集而不是查询条件,排序和查询彻底解耦,这样学生端也能复用同一个排序模块,只是传进去的记录集不同。这就是结构图上“扇入”设计的实际价值:复用不是靠复制代码,而是靠把模块的输入抽象成数据本身。
4.3 学生服务子系统的裁剪与公共模块复用
学生端的功能是教师端的子集,但直接复用会带来一个隐蔽的越权问题。假设学生端也调query_score,而这个函数接受外部传入的学号,那么只要改一下请求参数,学生就能查到别人的成绩。这类问题在课设里不一定会被发现,但一旦被问到“你怎么保证学生只查到自己的”,答不上来就很难看。
我的处理方式是在学生端加一层薄封装,把学号来源从“外部传参”改成“登录态取值”:
# 学生服务子系统:不新增业务模块,复用公共模块并收紧数据范围 def student_query_score(operator_id: str, term: str) -> list: # 学号直接取自登录态,函数签名里根本不给外部传学号的机会 return query_score(operator_id, stu_id=operator_id, term=term) def student_view_rank(operator_id: str, course_id: str, term: str) -> dict: # 先查本人成绩,再在课程范围内算排名,排名只返回名次不返回他人明细 mine = query_score(operator_id, stu_id=operator_id, term=term) return build_rank_view(course_id, term, mine)这段代码的价值不在实现,而在它体现的结构决策:学生端在结构图上不新增独立模块,只增加一个“范围约束”层。反映到 SC 图上,就是学生主控的扇出比教师主控少,且所有业务调用最终都汇入同一个数据访问模块。好处是公共逻辑只有一份,改一处全生效;代价是每次调用都要多一次角色校验,性能上有微小开销。对成绩管理这种数据量在万级以内的系统,这点开销可以忽略,但如果哪天要扩到全校十几万条记录,就该考虑把角色校验提到数据访问层统一拦截。
5. 避坑与排查:结构图文档里五个高频翻车点
结构设计文档不像代码,跑不起来会报错;它的问题往往要到答辩现场才暴露。下面这五条是我见过的、也是自己踩过的,按“现象—原因—解决”写,照着排查一遍能省不少返工。
5.1 功能层次图和软件结构图画成了同一张
现象:两张图几乎一样,都是树形,都有“成绩查询”“成绩排序”这些节点,只是箭头画法略有差别。
原因:没分清两张图的语义。功能层次图表达的是“系统具备哪些功能、怎么分层归属”,节点之间是组成关系;软件结构图表达的是“模块之间谁调用谁、传什么数据”,节点之间是调用关系,还带数据信息和控制信息。
解决:功能层次图上不出现任何带方向的调用箭头,同一层节点互不调用;软件结构图上必须有调用箭头,箭头上标注数据流名称,模块旁标注编号。最省事的验证办法是:把结构图上的每个模块名念一遍,如果念出来是“查询成绩”这种动宾短语,说明它更像功能而非模块;模块名应该是“成绩查询模块”这种名词性结构,并且能在代码里找到一个函数或类与之对应。
5.2 数据流图里混进了判断和循环
现象:图上出现菱形判断框、回到上一步的循环箭头,甚至画出了“输入错误则重新登录”的回环。
原因:把 DFD 当成了流程图。DFD 描述的是数据流动和加工,不描述控制流程和执行顺序;分支在 DFD 里表现为同一个加工的多条输出流,各自标注条件,而不是判断符号。
解决:删掉所有菱形和回环。事务分支改成从一个加工引出两条带条件标注的数据流,比如“验证通过(教师)”“验证通过(学生)”“验证失败”三条流,其中失败流指向一个提示加工,提示加工只输出信息、不写数据存储。如果确实需要表达“重新输入”,那属于界面交互,不该出现在 DFD 层,放到模块实现里说就行。
5.3 漏掉系统初始化和菜单显示,主控模块悬空
现象:结构图顶层的主控模块下面没有可调用的下级,或者下级直接就是业务模块,启动过程无处安放。
原因:只盯着业务功能,忘了非功能性模块。系统要连数据库、要读配置、要按角色渲染菜单,这些都是实实在在的模块,漏了它们,结构图在启动阶段就是断的。
解决:在公共支撑层补两个模块——系统初始化和菜单显示。初始化模块负责建立连接、加载配置、检查表结构,扇出指向数据访问模块;菜单显示模块接收角色标识,返回对应菜单项,被教师主控和学生主控共同调用,所以它的扇入是 2。补完之后再检查一遍:从顶层主控出发,能不能沿调用链走到每一个叶子模块,走不到的就是悬空模块。
5.4 扇出失控,一个模块挂十几个下级
现象:某个主控模块下面直接挂了录入、查询、排序、分析、导出、打印、备份、权限、日志一大串,图面像把扇子。
原因:把“主控”当成了万能入口,所有请求都从它分派。扇出过大意味着这个模块的职责不单一,任何新功能都要改它,违反开闭原则。
解决:按角色或按业务域二次分解。教师主控的合理扇出是四到五,超出的部分先归并成组,比如把导出、打印合并成“报表输出”,再由它往下分。经验值是单个模块扇出控制在七以内,超过就拆一层中间主控。拆的时候注意别拆出空壳模块——如果一个中间模块只是原样转发调用、不加工任何数据,那就不要拆,宁可让上级多一个扇出。
5.5 学生端直接复用教师端查询,越权却查不出来
现象:功能上一切正常,学生登录后也能查到成绩,测试时用自己的账号试也没问题。
原因:测试只用了本人账号,没试过篡改参数。学生端如果直接调用了接受外部学号的查询接口,把请求里的学号改成别人的,就能拿到他人成绩。
解决:在学生端和公共查询模块之间加一层范围约束,学号从登录态取,函数签名里不暴露这个参数;同时在数据访问层加一条规则,凡是学生角色的查询,SQL 必须带stu_id = 当前登录学号的条件,两个条件同时成立才放行。验证方法是构造三条用例:查本人(应成功)、查他人(应拒绝)、不传学号(应拒绝)。这三条过了,才算真正测过。
6. 验收与答辩:用一张“图—表—码”对照清单自证设计成立
结构设计文档的验收标准其实很朴素:别人拿着你的图,能不能不问你一句话就把系统搭起来。答辩现场最有效的自证方式,是准备一张三列对照表,左列是图上的元素,中列是对应的数据表或字段,右列是对应的代码位置。评审随手点一个模块,你能在三秒内指出它落在哪张表、哪个函数,可信度立刻不一样。
| 图纸元素 | 数据结构落点 | 代码落点 | 检查方法 |
|---|---|---|---|
| 功能层次图叶子节点 | 无直接对应 | 每个叶子对应一个函数 | 数叶子数和函数数是否一致 |
| 数据流图数据存储 | student / score / sys_user | 数据访问模块 | 每个存储能否找到建表语句 |
| 数据流图数据流 | 字段组合 | 函数入参与返回值 | 每条流能否找到字段来源 |
| SC 图模块 | 无直接对应 | 类或函数 | 模块编号与函数注释是否对齐 |
| SC 图调用箭头 | 无直接对应 | 函数内部调用 | 扇出是否与代码实际调用数一致 |
这张表我建议在答辩前一晚逐行过一遍,尤其是最后一行。图上的扇出是 4,代码里实际调了 6 个函数,这种不一致一旦被翻出来,前面所有图的严谨性都会被打折扣。反过来,如果你能主动说“这里图上标 4,实际代码里多调了一个日志模块,因为日志不算业务模块,我在图里合并到公共支撑了”,这就是加分项,说明你想过边界。
还有一个小技巧:准备一页“变更记录”。结构设计不是一次成型的,数据流图从初版到加了身份验证、结构图从三层拆到四层,这些改动本身就是设计过程的证据。把每次改动的原因写清楚,比如“增加身份验证环节,因为原始数据流图没有区分角色,导致教师和学生共用一条加工路径”,比单纯展示最终版更有说服力。评审问“为什么这么设计”时,你答的是演进逻辑,而不是事后解释。
从那以后我每次交结构设计文档,都强制走一遍“图—表—码”三向核对:图上的每个模块要在表里找到数据落点,在代码里找到函数落点,三者缺一个就补。这套习惯救过我两次,一次是发现数据流图里有个“成绩修改”加工,代码里根本没有对应函数,另一次是结构图上标了扇入 2 的模块,实际只有一个地方调用。希望帮到你。
本文还有配套的精品资源,点击获取