软件建模17:FDD 的整体模型与计划
设备租赁已经有设备、租期和预留对象,开发清单却仍可能写成“完成数据库”“开发服务层”“补齐页面”。这些任务有技术用途,但完成其中一项以后,租赁人员未必能完成一次新的操作。模型要进入交付,需要把对象之间的协作整理成可以验收的业务结果,再据此安排开发顺序。
场景、用例与规则 提供业务输入,OO 分析与 CRC 区分对象责任,四色建模 帮助检查概念类别。本篇把这些材料转成 FDD 的整体模型、feature 清单和初始计划,实验只检查计划一致性,尚未证明 feature 已交付。五个流程中的三个准备活动
Jeff De Luca 在2013年 Agile Singapore 演讲的第3张幻灯片列出五个流程:Develop an Overall Model、Build a Features List、Plan by Feature、Design by Feature、Build by Feature。它们依次涉及整体模型、功能清单、开发计划,以及反复进行的具体设计和构建。原始演讲资料
前三项分别解决不同问题。整体模型使“某台设备被哪份预留占用”有共同解释;feature 清单说明用户需要哪些结果;计划把依赖和责任放到可执行顺序中。把三者合并成一张任务表,会很难看出某项开发工作究竟修改哪个概念,又接受什么场景的检验。
整体模型也有停止条件。本例只需要解释设备身份、预留身份、租期以及冲突判定责任,就能讨论下一项延期功能。价格结算尚未进入范围,没有必要在延期之前设计完所有账单字段;但“预留等不等于实际交付”不能省略,否则取消预留的含义会直接影响库存判断。
三个产物还承担不同的变更成本。发现“按型号预订,稍后才指定实物”的需求时,整体模型需要加入型号需求与实物分配的关系,feature 清单需要说明什么时候完成分配,计划则要考虑分配能力是否成为延期的前置。只在清单里追加一个页面任务,无法表达这条贯穿语义、行为和顺序的变化。
从租赁场景提取整体关系
教学场景继续使用设备 E1、E2,租期采用半开区间。数字1、3、5表示相对同一起点的日边界:[1,3) 与 [3,5) 可以相邻,同设备上的 [1,4) 与 [3,5) 则冲突。这是模型假设,不代表日租业务普遍允许无清洁间隔的连续出租。
Equipment 表示可识别的实物;Rental 在本例中只表示已确认预留,带设备编号与区间;Period 负责区间规则。ReservationBook 是设计时引入的协调对象,负责汇集预留并检查冲突。它不代表仓库员工,也不等于一张数据库表。
classDiagram
ReservationBook "1" --> "0..*" Rental : 管理预留
Rental "0..*" --> "1" Equipment : 指定实物
Rental "1" --> "1" Period : 占用区间
Period : start
Period : end
Period : overlaps(other)
Rental : id
ReservationBook : 检查同设备其他预留
图中混合了业务概念与为实验选择的协调类,因此属于本篇设计模型,不是完整租赁领域图。它没有型号规格、参与方角色或合同金额;这些概念在前文各有用途,删去它们只为缩小这一轮交付范围,不能据此判断真实业务不需要它们。
场景也要保留失败结果。E1 已有 R1 [1,3) 和 R2 [5,8),把 R1 延到5应成功,延到6应被拒绝,并且 R1 不能留下半次修改。若清单只有“支持延期”,对象模型虽然齐全,也无法判断后一个结果是否属于本次交付。
feature 的粒度来自可观察结果
Stephen Palmer 在2009年的原作者教程中把 feature 表述为小型、对客户有价值的功能,名称采用动作、结果、对象的结构。该文还说明,一小组 feature 的设计与构建迭代不超过两周,通常更短。这个时间界限不能直接换算成本实验的运行时间或自动生成的工期估算。Palmer,第一部分
本例按“资源预留”主题划分建立、调整、取消三个活动。feature 名称使用中文业务句子,不机械照搬英文词序:F01“确认指定设备在租期内的预留”,F02“延长既有预留的可用租期”,F03“释放取消预留所占的租期”。三项都能够用操作前后的记录差异验收。
“实现 Period 类”适合作为实现任务,却没有独立的租赁结果;“完成租赁系统”又包含过多尚未定义的结果。粒度合适的清单需要同时避开这两端。延期仍可涉及多个类,但不包含同时改价、替换设备和补签合同,因而有一个清楚的失败边界。
| feature | 模型关系 | 验收场景 | 前置能力 |
|---|---|---|---|
| F01 确认预留 | 设备、预留、租期及协调对象 | 相邻区间允许创建 | 无 |
| F02 延长租期 | 预留及其租期、协调对象 | 延到5成功,延到6拒绝且不变更 | F01 |
| F03 取消预留 | 预留与协调对象 | 取消后可预留原区间 | F01 |
这张表是多对多映射。同一个 Period 支持创建和延期;一个延期 feature 又涉及多个对象。用“一类对应一个 feature”的方式分工,会把跨对象的不变量留在清单之外。反过来,仅记录功能名称而不保留模型引用,类责任调整后就难以找到受影响的验收。
映射还需要区分“参与读取”和“需要修改”。F02 会读取设备编号,但本轮不改变设备目录,所以它的修改范围没有列入 Equipment。把所有间接读取都算作类修改,会无差别扩大 feature 团队。只记最终写入的表,又会漏掉区间语义的责任。表格在此记录需要参与设计检查的对象,而不是调用图中可达的全部节点。
计划中的依赖与负责人
附件的 plan.json 保存模型节点、场景、feature 及其依赖。每个模型节点还分配一个逻辑责任角色:目录、区间和预留。角色名称用于教学排程,没有对应的虚构成员,也没有记录真实多人会议。
flowchart LR
E[Equipment] --> F1[F01 确认预留]
P[Period] --> F1
P --> F2[F02 延长租期]
R[Rental 与 ReservationBook] --> F1
R --> F2
R --> F3[F03 取消预留]
F1 -.能力前置.-> F2
F1 -.能力前置.-> F3
F02 与 F03 在能力上都只依赖 F01,形式上可以同时开始。但它们都会修改预留相关对象,如果同一负责人同时承担两项完整工作,就产生排程冲突。本例把它们放进不同 slot;slot 只是互斥工作时段,没有日历日期,也不表示两周固定冲刺。
这一容量规则是实验的保守选择,并非 FDD 规定每人绝不能参与多个 feature。真实安排还需要知道可用时间、技能、风险和优先级。模型引用只能帮助发现可能争用的责任,不能替人算出可信交付日期。为了并行而随意拆开同一对象的责任,也可能增加合并和解释成本。
业务优先级也不能由依赖边自动推导。F02 和 F03 都能接在 F01 后面,先交付哪项仍要比较实际需求。本例选择先延期只是为了延续既有场景。若取消操作是首批使用者的必要能力,就应先安排取消;调整顺序不要求推翻对象模型,但需要重新检查共享负责人的容量和相应验收材料。
用反例检查计划
下载 本篇实验与模型,在解压后的根目录运行,要求 Python 3.10 或更高版本,无第三方依赖:
1 | |
脚本先读取真实 JSON,推导三项 feature 涉及的负责人集合,再复制计划,逐项注入错误。重复编号、未知模型节点、空场景、未知依赖、依赖环、负责人冲突等修改都必须引发指定错误;单纯打印“校验通过”无法让这些断言成功。
本次在 Python 3.14.4 上执行,得到12项检查通过,进程退出0。原始输出在 evidence/17/run.txt,最后一行明确保留 business behavior NOT_EXECUTED。F02 的两个场景目前只是计划中的验收文字,检查器验证它们有对应关系,没有执行延期算法。
依赖环的负例通过严格的 slot 前置关系被拒绝,检查器没有实现通用图调度器。它也不会理解中文名称是否真的有客户价值:把名称改成一句非空但无意义的话仍可能通过。客户价值、遗漏需求以及设备实际交接规则,需要领域参与者审阅。
正例与负例都从同一份文件读取数据,负例修改的是深复制,因此一个错误场景不会污染后续检查。预期错误文本也被断言:未知模型节点必须因引用缺失被拒绝,不能因另一个偶然错误失败就算通过。这让实验能够检验所声称的约束,同时把检查器未涉及的领域判断留在人工审阅范围内。
模型变化以后,检查应当重复运行。例如把区间检查移到独立策略对象,需要同时修改模型引用和负责人映射;只改类图,JSON 仍可能保持旧关系。这份可执行材料减少的是引用漂移,不能自动发现所有语义漂移。下一轮交付必须用同一个 F02 标识,把场景落到设计、程序和真实输出上。






