一份租赁需求可以同时借助分析模式辨认资源承诺,用四色区分参与角色与交易活动,用领域驱动设计确定一致性责任,再按 FDD 组织可交付特征。它们关注的问题存在重叠,不能通过“哪一张类图更短”评出统一名次。

本篇使用相同输入运行三个教学候选,检查它们分别遗漏什么。候选代表具体设计决定,不代表某种方法的全部能力;过程方法另用特征与验收结果的关联来评价。所有数据均为合成案例,没有真实团队工作坊或交付效率统计。

先固定需要解释的事实

申请 r1 希望租用 camera-A,时间为 UTC 十月三日十点到十二点。party-A 提出申请,party-B 承担付款角色。现行目录每小时十元,确认后更新为十五元。模型应能说明谁参与了这次活动、何时产生占用,以及哪一个价格仍然约束旧草案。

这组需求沿用半开区间:十二点结束的租期与十二点开始的租期相邻,不重叠。计划本身不占用设备;确认才产生承诺。取消释放占用,但原请求重试仍返回历史确认,不能重新占用;原来因冲突失败的请求,释放后重试也仍返回历史失败。

八个场景分别检查计划与承诺、重叠拒绝、相邻允许、取消后确认重放、失败重放、双重参与角色、旧费率保留和相同请求号的负载变化。对三个候选都执行同样的场景,按场景组建立独立实例;组内共享必要历史,防止不同组之间相互污染。

flowchart LR
  I[同一租赁需求] --> S[八个可执行场景]
  I --> C[目录改价变化卡]
  S --> A[Flat 扁平候选]
  S --> B[Semantic 语义区分]
  S --> D[Bounded 回执边界]
  C --> A
  C --> B
  C --> D
  A --> E[真实行为差异]
  B --> E
  D --> E
  E --> F[特征验收映射]

实验有意缩小范围,只接收内部可信的 UTC 整秒输入,金额使用 Python Decimal,币种固定为人民币,所有操作串行。它与既有 Java 模型共享规则语义,不是27累计应用的替代品;没有把 Python 字典的封装宣传成数据库事务。

分析模式促成哪些区分

Flat 只保存活动申请,计划也调用确认入口。结果是计划先占用了设备,真正申请随后被拒绝。Semantic 把计划放到独立 proposals 集合,只有 reserve 成功才进入 active,首个场景因这项变化从失败变为通过。

分析模式中的行动与资源分配结构提供了检查线索。Fowler 网站的第八章 UML 补充材料区分 Proposed Action、Implemented Action 与资源分配,并进一步区分资源类型和指定资源。原材料并没有替这个教学系统规定取消、重试和锁的政策;“本例计划不占用”是已经声明并执行的需求选择。行动与资源补充图。

这里暂未采用按类型容量预订,因为需求明确指定 camera-A。若业务允许先订“任意一台相机”,再于交付时分配具体设备,当前 equipment 字段就不足以表达两阶段承诺。模式的作用是暴露这个缺口,不能把图上的所有类都复制进目前只需要指定设备的程序。

四色帮助检查遗漏的关联

Flat 的角色查询只返回 customer=party-A,因此无法回答谁付款。Semantic 返回 requester 与 payer 两个具名关系,让同一个参与者可承担不同职责,也允许两个角色由不同参与者承担。参与者身份与当前活动中的责任由此分开。

四色材料把时刻或时段活动、角色、参与者或事物、描述区分开。出版商提供的原书第五章样章包含粉色项目与黄色项目角色、蓝色文档模板与绿色文档等实例。本篇把申请活动、申请人和付款人角色、参与者与设备、费率描述映射到这些检查视角,这是租赁教学推演,没有复制原书组件作为本系统规范。原书第五章样章。

目录改价揭示另一处关联问题。Flat 每次通过现行目录计算旧申请金额,改价后旧报价由二十变为三十。Semantic 在确认时保留不可变 Rate,其中同时包含 revision 和 hourly;以后查旧草案用约定版本,新申请才用目录新值。运行结果分别为旧单二十、新单三十。

仅把费率框涂成蓝色无法保证历史正确。若保存的仍是指向可变目录对象的引用,目录更新同样可能改变旧事实。实验通过替换目录值、再次读取旧价来验证快照语义;颜色只是要求检查“描述和使用它的活动之间是什么关系”的提示。

领域驱动设计追问谁维护历史

Semantic 已能分清计划、角色和费率,却仍在取消时删除唯一活动记录。重试时已经找不到旧请求,便重新确认,重新占用设备。这个失败表明概念区分充分与操作规则完整是两个问题。

Bounded 在相同结构外增加 receipts,按请求号保存完整申请与结果。reserve 先比较历史负载,完全相同便返回原结果;改变设备、时段或角色则拒绝。取消只删除 active 中的占用,保留 receipts。重试不再经过当前空闲判断,因此取消不会把旧命令变成新承诺。

DDD 的聚合讨论要求明确一致性边界和受控访问。本例把重放与活动记录放在同一个顺序操作入口;它展示边界内需要维护哪些事实。代码没有锁、并行执行和持久化,不能据此声称已经实现25的并发保证或27的提交保证。Evans 的 DDD Reference,Aggregates。

领域模型也可以吸收前两种视角产生的概念。保留费率版本、角色关系与历史回执并不要求分别建设三个系统。反过来,分析模式或四色候选也可以实现同样的回执规则;实验中没有实现,是为了隔离设计决定的效果,不能归因成那些方法必然缺少一致性。

flowchart TD
  CMD[确认命令] --> H{请求号已有回执}
  H -->|是| P{完整负载相同}
  P -->|是| OLD[返回历史结果]
  P -->|否| ERR[拒绝号复用]
  H -->|否| CHECK[检查当前占用]
  CHECK --> REC[保存成功或失败回执]
  REC --> ACT[成功才保存占用与约定费率]
  CANCEL[取消命令] --> REMOVE[只解除活动占用]
  REMOVE --> KEEP[历史回执保留]

FDD怎样组织这些验收结果

FDD 的五个流程是开发总体模型、建立特征列表、按特征规划、按特征设计、按特征构建。Jeff De Luca 的原始演讲列出了这些流程;Stephen Palmer 的说明强调初始模型先覆盖领域广度,深度随特征迭代增加,四色是常用建模方式而非强制条件。De Luca 演讲、Palmer 的方法介绍。

实验没有虚构第四个“FDD 状态模型”,而是把八个场景归入三个小特征:确认租赁、取消并重放结果、保留参与角色与约定价格。每个特征只有其关联场景全部满足才通过门禁。Flat 三个特征均未通过;Semantic 的确认和角色价格通过,取消重放仍失败;Bounded 全部通过。

这个门禁由实际运行结果计算,不接受人工填入的“已完成”。执行 flat 参数时,程序打印完整差异后退出一;执行 bounded 时退出零。默认入口则确认预期反例确实出现,所以默认通过与 Flat 可交付是两个不同的判断,原始输出保留了各自字段。

这样的映射有助于把建模发现带入交付检查,但不等于真实执行了完整 FDD 过程。实验没有领域专家协商、类所有权安排、设计检查会议或团队并行协作,更无法推断某种方法节省了多少工期。过程的组织效果需要另一种现场证据。

比较结果怎样影响下一次修改

当前候选的差异可以直接定位到数据与入口。计划误占用应修改计划保存路径;旧价漂移应补约定费率快照;重放复活应补历史回执与负载比较。只增加术语表或统一图形颜色,都不会改变这三个实际输出。

评审顺序也会影响讨论效率。先确认场景是不是共同接受的需求,再核对模型能够保存哪些事实,最后定位执行入口的约束。如果参与者尚未同意取消后保留历史确认,直接讨论回执表如何分库就过早了;实验通过只能说明实现符合这份约定,无法代替约定本身。

目录改价卡还要求同时检查旧申请和新申请。只断言旧价不变,会漏掉新申请仍误用旧目录;只断言新价正确,则会漏掉旧事实被覆盖。变化卡把两个观察组合起来,才说明“更新目录”与“修改既有约定”已在模型中分开。

这些判断也有成本:新增集合意味着要定义保存、恢复与迁移的一致性;增加角色意味着导入旧数据时可能缺少付款人;固定费率版本意味着目录清理不能破坏历史引用。候选通过八个场景后,这些尚未实现的工作仍然存在,不能把绿色结果当作全部架构问题已经解决。

源码、场景与范围说明分别位于 examples/software-modeling/labs/36/、models/36/。运行:

1
2
bash examples/software-modeling/labs/36/run.sh
bash examples/software-modeling/labs/36/run.sh flat

第一条检查二十四个候选场景结果及两项特征门禁;第二条是有意失败的交付反例。输出与退出码位于 evidence/36/。下载比较实验与原始证据 后可直接复跑,再从 一致性边界实验 核对串行候选尚未承担的并发责任。