🏺 第19章 企业人事管理系统
📄 一句话概括

系统分析要回答三个问题:谁用、用来干什么、先做哪个。 前两个在 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 秒实验

  1. 把 score 里的减号改成加号,再排一遍。 看「报表导出」跳到第几名——这演示了「把成本算成收益」会造成什么后果。
  2. 把「工资计算与发放」的难度从 4 改成 5,看它还稳不稳在第一。
  3. 给 score 加第四个权重「合规风险」,把「权限管理」的风险分设成 5, 看排名怎么变——这就是「合规需求必须前置」的量化方式。

常见误区

  1. 「加权分能算出正确答案」。 它算不出, 它只是把争论从「我觉得」搬到「权重该多少」上——后者更容易达成一致。
  2. 「权重是技术细节,开发定就行」。 权重决定谁先做,这是业务决策,必须业务方签字。
  3. 「用例写得越细越好」。 细到控件行为就【过早】了,那时候还没有原型,写下的细节八成会改。
  4. 「非功能需求等上线再说」。 数据量决定索引,索引决定表结构,表结构定完再改就是返工。
自测三问(点开对答案) 1. 为什么难度在公式里是减号? —— **因为它代表成本。** 把成本加成收益,**等于奖励「做得慢的功能」,排序会彻底反过来。** 2. 两套权重下排名变了,说明加权分不可靠吗? —— **不能这么说。** 它说明【排名依赖权重】,**所以权重必须显式定下来并写进文档,不能临时改。** 3. 差距只有 1 分的两项,应该怎么处理? —— **当成并列。** 差 1 分在评分误差之内,**可以并行开发,或者按人力空闲随便挑一个先做。** 4. 用例写到什么细度算够? —— **一句话能对应一个按钮/菜单项。** 再细就属于原型阶段的事。

下一篇把用例变成结构:功能树、业务流程图、目录结构。 三张图定完,编码才有地方落。

相关笔记