系统分析要回答三个问题:谁用、用来干什么、先做哪个。 前两个在 19.1 已经答了,第三个最容易吵架。 这一篇用加权分把「先做哪个」变成算术,让争论有落点。
19.1 给了一张功能矩阵,它回答了「做什么」,没回答「先做什么」。 这一篇补的就是顺序。 顺序错了不会报错,只会让人在项目后期发现「核心功能还没做」。 后面 19.7~19.9 三个模块的排期,依据就是这一篇算出来的序。
一、三个问题,第三个最难
「谁用」和「用来干什么」都有客观答案——问人、看流程,就能定下来。 「先做哪个」没有客观答案,所以它会变成一场会议。 而会议上声音最大的,往往不是最懂业务的那个。 把它变成算术,不是为了算得准,是为了让每个人都有同一把尺子。 尺子本身可以争,但争的是权重,不是「我觉得这个重要」。 这一步的产出是一张有序的用例清单,后面所有排期都从它出。
二、三个权重:价值、频率、难度
每个用例打三个分,都取 1 到 5。 第三个分数的方向要反过来用,因为它代表成本。
| 权重 | 问的问题 | 打分依据 |
|---|---|---|
| 业务价值 × 3 | 不做行不行 | 不做系统就没意义=5 |
| 使用频率 × 2 | 一天用几次 | 每小时都用=5 |
| 实现难度 | 做起来多费劲 | 要一周=5,要半天=1 |
公式是:价值 × 3 + 频率 × 2 − 难度。 难度前面是减号,因为「难做的」应该往后排。 3 比 2 这个权重是【决策】,不是真理。 它表达的是「价值比频率更重要」这个判断。 换成 2 比 1,排名就会变,Demo 里两套都算了一遍。 所以权重必须写下来、写进文档。 只在脑子里定权重,等于没有标准——下次讨论时谁也说不清上次是怎么排的。
三、算出来的序说明什么
第一名是「工资计算与发放」,21 分。 它三项都不低:价值 5、频率 5、难度 4。 这就是核心用例的样子:不做,系统就没有意义。 最后一名是「报表导出」,8 分。 它的难度是 4,是全场最高——但难在格式和字体,不难在逻辑。 这类「难但价值一般」的功能,正确做法是放到二期。 一期用「导出 CSV」顶上,二期再做带格式的报表。 换一套权重后,变化最大的是「员工档案增删改查」。 它从 20 掉到和「工资计算」并列 11——因为它频率高、价值也高,但难度不低,权重一变就吃亏。 这说明一个道理:权重不是「调参」,它决定谁赢。 所以权重必须由业务方拍板,不能由开发顺手定。
四、用例写到什么细度够用
细度不对,后面的设计就会缺信息或者被绑死。 一个反例和两个正例对比最清楚。
| 写法 | 内容 | 能不能验收 |
|---|---|---|
| 太粗 | 管理员工信息 | 不能 |
| 够用 | 新增、修改、删除、按部门筛选 | 能 |
| 太细 | 输入框失焦时校验身份证号 | 能,但过早 |
中间那行是标准:写到「一个动作一句话」就停。 第三行不是错的,是【时机不对】。 界面上控件的行为,等画原型时再定,写在这里只会变成返工的负担。 判断细度有个简单办法:这句话能不能直接变成一个按钮? 能,就够了;不能,就还太粗。
五、非功能需求:被忽略最多的那一栏
功能需求写得再全,系统也可能不能用。 因为非功能需求常常没人写。
| 类别 | 这个系统的要求 | 不满足会怎样 |
|---|---|---|
| 并发 | 同时在线 30 人以内 | 几乎不用担心锁 |
| 数据量 | 员工 5 万、工资每年 60 万 | 要建索引 |
| 响应 | 查询 2 秒内 | 再慢人就不用系统了 |
| 安全 | 普通员工只能看自己 | 这是合规红线 |
| 备份 | 每日全备,保留 30 天 | 出事就是大事 |
第二行那个「每年 60 万」是全篇最实用的一个数。
5 万员工 × 12 个月=60 万条工资记录,三年就是 180 万。
这个体量决定了 tb_wage 上必须有 (emp_id, 年月) 的联合索引。
没有这个数,就会有人写出「先全表查出来再在内存里过滤」的代码,
然后在第三年崩掉。
这五条里,「响应 2 秒」和「数据量 60 万」是最容易吵起来的。
因为它们互相拉扯:数据量涨了,响应就保不住。
所以这两个数必须在同一份文档里出现,不能分开写。
六、动手 Demo:加权分排序,以及换一套权重之后的排名变化
Demo 把八个用例按加权分排一遍,再用另一套权重排一遍。
两套权重只差一个数,排名就动了。
代码里的 score 就是那把尺子,一行算术。
重点是看两次排序的差异,而不是看分数本身。
cases = [
("工资计算与发放", 5, 5, 4),
("员工档案增删改查", 5, 4, 3),
("登录与身份校验", 5, 2, 2),
("部门树维护", 4, 3, 2),
("用户与权限管理", 4, 3, 2),
("数据备份恢复", 3, 4, 3),
("工资条查询", 3, 2, 1),
("报表导出", 2, 3, 4),
]
def score(v, f, d, wv=3, wf=2):
return v * wv + f * wf - d
for name, v, f, d in sorted(cases, key=lambda c: -score(*c[1:])):
print("%-18s %2d" % (name, score(v, f, d)))
print("--- 权重改成 2 比 1 ---")
for name, v, f, d in sorted(cases, key=lambda c: -score(*c[1:], 2, 1)):
print("%-18s %2d" % (name, score(v, f, d, 2, 1)))
实跑输出:
--------------------------------------------------------------------
第八十五课:系统分析——用例排序靠加权分,不靠感觉
--------------------------------------------------------------------
**系统分析要回答三个问题:谁用、用来干什么、先做哪个。**
**前两个好办,第三个最容易吵架。这一课用加权分把它量化。**
一、用例清单与三个权重
--------------------------------------------------------------------
**三个权重是:业务价值、使用频率、实现难度(难度取反面)。**
用例 价值×3 频率×2 难度 加权分
------------------------------------------
工资计算与发放 5 5 4 21
员工档案增删改查 5 4 3 20
登录与身份校验 5 2 2 17
部门树维护 4 3 2 16
用户与权限管理 4 3 2 16
数据备份恢复 3 4 3 14
工资条查询 3 2 1 12
报表导出 2 3 4 8
已选择 8 行
**算法写在这里:`价值 × 3 + 频率 × 2 − 难度`。**
**难度前面是减号,因为「难做的」应该往后排。**
**权重 3 比 2 是我定的,不是教材的。**
**换成 2 比 1 再算一遍,排名会变**——**权重本身就是一种决策,所以必须写下来,不能只在脑子里。**
二、排序结果说明什么
--------------------------------------------------------------------
**第一名是「工资计算与发放」,加权分 21。**
**它三项都不低:价值 5、频率 5、难度 4。**
**这就是核心用例的样子——不做,系统就没有意义。**
**最后一名是「报表导出」,加权分 8。**
**注意它的难度是 4,是全场最高。**
**报表导出难在格式和字体,不难在逻辑。**
**这类「难但价值一般」的功能,正确做法是放到二期。**
三、用例写到什么细度够用
--------------------------------------------------------------------
**一个反例和两个正例对比最清楚。**
写法 内容 能不能验收
------------------------------------------------
太粗 「管理员工信息」 不能
够用 「新增、修改、删除、按部门筛选」 能
太细 「输入框失焦时校验身份证号」 能,但过早
已选择 3 行
**中间那行是标准:写到「一个动作一句话」就停。**
**第三行不是错的,是【时机不对】。**
**界面上控件的行为,等画原型时再定,写在这里只会变成返工的负担。**
四、非功能需求被忽略最多
--------------------------------------------------------------------
类别 这个系统的要求 不满足会怎样
-------------------------------------------------------
并发 同时在线 30 人以内 几乎不用担心锁
数据量 员工 5 万、工资记录每年 60 万 要建索引
响应 查询 2 秒内 再慢人就不用系统了
安全 普通员工只能看自己 这是合规红线
备份 每日全备,保留 30 天 出事就是大事
已选择 5 行
**第二行那个「每年 60 万」是全篇最实用的一个数。**
**5 万员工 × 12 个月 = 60 万条工资记录,三年就是 180 万。**
**这个体量决定了:`tb_wage` 上必须有 `(emp_id, 年月)` 的联合索引。**
**如果没有这个数,就会有人写出「先全表查出来再在内存里过滤」的代码,然后在第三年崩掉。**
第一套权重(3 比 2)排出来,第一名叫 21 分,最后一名 8 分。 注意中间有两组并列:16 分的「部门树维护」和「用户与权限管理」。 并列不是问题,它说明这两个可以并行开发、或者任意先后。 真正要小心的是【差距太小】的两项—— 比如 20 和 21,差 1 分,这种排序其实说明「两个都该早做」。 第二套权重(2 比 1)之后,「工资计算」和「档案增删改查」并列 11。 原来第一名领先 1 分,现在打平。 原因是频率的权重降了:工资计算频率 5,档案增删改查频率 4, 频率权重从 2 降到 1,这两项的差距就被抹掉了。 这张表最该看的不是排名,是【差多少】。 差 1 分的两项,实际上没有先后;差 5 分以上的,才是真的该排前面。 最后一行「报表导出」两套权重下都是最后一名,3 分。 这种「怎么调权重都垫底」的功能,就是最安全的延期对象。
30 秒实验
- 把
score里的减号改成加号,再排一遍。 看「报表导出」跳到第几名——这演示了「把成本算成收益」会造成什么后果。 - 把「工资计算与发放」的难度从 4 改成 5,看它还稳不稳在第一。
- 给
score加第四个权重「合规风险」,把「权限管理」的风险分设成 5, 看排名怎么变——这就是「合规需求必须前置」的量化方式。
常见误区
- 「加权分能算出正确答案」。 它算不出, 它只是把争论从「我觉得」搬到「权重该多少」上——后者更容易达成一致。
- 「权重是技术细节,开发定就行」。 权重决定谁先做,这是业务决策,必须业务方签字。
- 「用例写得越细越好」。 细到控件行为就【过早】了,那时候还没有原型,写下的细节八成会改。
- 「非功能需求等上线再说」。 数据量决定索引,索引决定表结构,表结构定完再改就是返工。
自测三问(点开对答案)
1. 为什么难度在公式里是减号? —— **因为它代表成本。** 把成本加成收益,**等于奖励「做得慢的功能」,排序会彻底反过来。** 2. 两套权重下排名变了,说明加权分不可靠吗? —— **不能这么说。** 它说明【排名依赖权重】,**所以权重必须显式定下来并写进文档,不能临时改。** 3. 差距只有 1 分的两项,应该怎么处理? —— **当成并列。** 差 1 分在评分误差之内,**可以并行开发,或者按人力空闲随便挑一个先做。** 4. 用例写到什么细度算够? —— **一句话能对应一个按钮/菜单项。** 再细就属于原型阶段的事。下一篇把用例变成结构:功能树、业务流程图、目录结构。 三张图定完,编码才有地方落。
- ☐ (本篇完,下一篇 19.3 系统设计)
相关笔记
- 开发背景
- 系统设计
-
- 🐬 MySQL必知必会/00-索引
- 🏺 Oracle从入门到精通 · 索引