软件建模26:Domain Service、Specification与Factory
租期至少提前一小时、最长四十八小时;报价按不足一小时向上取整;合同草案必须保存与租期及单价一致的金额。这三条教学规则都能写成条件语句,但放在哪里,会决定调用者能否绕过规则,以及修改一种政策会牵动哪些对象。 Aggregate与一致性边界 已把资源排他放进预留日历。本篇处理创建之前的规则、报价和完整性,直接复用既有 `EquipmentId`、`Period` 与第24篇的 `Money`。创建成功只表示一份内部一致的草案,不意味着已经预留、签署或付款。 用问题选择职责 “这份租期符合规则吗”需要一个候选和一组政策参数;“这份租期按当前单价是多少钱”需要计算;“能否交出一份完整草案”需要把前两者组合起来。它们的输入、失败方式和副作用不同,可以分别建立契约。 Eric Evans 在《DDD Reference》2015年版 Services 中讨论了不自然属于实体或值对象的领域操作;Factories 则关注完整对象的创建与内部约束。原文,印刷页14、18 这些职责不要求每个类都配一个接口,也不要求引入依赖注入框架。本例采用几个可直接构造的 Java 类。 flowchart L...
软件建模25:Aggregate与一致性边界
两个租赁合同各自合法,却可能承诺同一台设备在同一时间交付。合同甲租十点到十二点,合同乙租十一点到十三点;即使合同都有身份、金额和完整字段,把它们分别保存成功也不能保证设备不被重复占用。 计划、资源与承诺 已区分计划和资源承诺。本篇进一步检查承诺写入的竞争条件:先给出两个线程都会确认的反例,再把冲突检查与状态更新放进一个明确边界。时间仍采用 UTC 半开区间,实验不引入数据库或分布式锁。 先写出需要同时成立的条件 本例要求同设备的任意两条活跃预留不重叠。请求编号在整个租赁点日历内唯一:同编号同负载返回原结果,改设备或租期必须拒绝。取消只释放活跃承诺,历史回执保留;旧成功请求重放不能重新占用,旧拒绝请求也不能因空位出现就变成成功。 这几条条件共同决定需要保护的数据。若冲突检查只读预留表,写入却分开更新回执和占用,其他调用可能看见半完成状态。若取消删除回执,重试又可能重新建单。一个合理边界应让调用者只能看到操作前或操作后的完整状态。 Eric Evans 的《DDD Reference》2015年版在 Aggregates 中要求定义聚合整体的不变量,由根或指定机制维护,并让事务与分...
软件建模24:Entity、Value Object 与身份
两台同型号相机的描述完全相同,仍不能合并成一台;同一台相机更换标签、送检、退役以后,设备身份却没有改变。金额恰好相反:两个人民币十元的值通常可以互换,没有必要追踪“最初创建的那一个十元对象”。相等规则需要先服从业务含义,再选择语言机制。 时间、数量与身份 已讨论半开租期与金额表示。本篇在未修改的 Java 租赁基线上复用 `EquipmentId` 和 `Period`,新增设备实体、设备描述和金额值对象,测试生命周期、相等及别名;这些规则仍未接入预留用例,实验会直接暴露这个缺口。 身份连续性决定 Entity 的含义 Evans 的《DDD Reference》用身份和生命周期连续性描述 Entity:属性可能变化,不同表示仍可能指向同一对象。Value Object 则表达所关注的属性及相关行为,应作为不可变值使用。2015年模式摘要,印刷页11—12 本实验的设备实体 Equipment 以设备编号相等。E1 与 E2 即使型号、标签和状态全部相同,仍然不相等;从 E1 的快照重新构造一个对象,与原对象不是同一个 Java 引用,却仍代表同一台设备。这里的编号继承现有核心...
软件建模23:上下文地图与防腐层
维修接口返回 DONE,租赁系统能否立即接受这台设备的新预留?如果 DONE 只表示工单处理结束,设备可能尚未返还,也可能检验失败后被关单。把它直接复制成“可用”,会把维修流程里的一个结果扩大成租赁承诺。 统一语言与知识消化 已经拆开物况合格与租期可预留;事件时间线 保留了尚未确认的业务问题。本篇将同样的谨慎用于上下文之间:明确谁控制接口、谁负责翻译,再用实际反例检验维修数据进入租赁语言后的含义。 上下文地图还要表达协作权责 两个方框之间画一条 HTTP 箭头,只能说明存在调用,不能说明下游能否影响上游排期。Evans 的《DDD Reference》把 Customer/Supplier、Conformist 和 Anticorruption Layer 分别放在具名上下文关系中:前者让下游需求进入上游计划;Conformist 接受上游模型;防腐层则用下游自己的模型表达上游提供的能力。2015年模式摘要,印刷页32—34 本例假设维修供应方独立维护工单系统,租赁方不能要求它按本方优先级发布功能。于是维修为上游,租赁为下游,租赁方承担防腐层的开发和兼容成本。这是用于教学的组织...
软件建模22:子域与限界上下文
设备 E1 已归还,租赁操作员可以说“完成了”。维修人员刚更换零件,也可能说“完成了”,但质量检查还未通过。结算人员面对 120 元未付账款,同样不能把这笔业务标为完成。三个完成若共用一个状态,设备可能提前被放行,债务也可能被错误关闭。 子域帮助识别业务需要解决哪些问题;限界上下文规定某个模型和语言在哪个范围内成立。本篇在同一组租赁事实下运行两种边界方案,比较它们如何保持这些“完成”的不同含义。 业务问题与模型边界分别描述 Eric Evans 的《DDD Reference》要求明确模型适用的上下文,并在边界内保持概念与术语一致;描述边界时需要考虑团队、应用范围及代码、数据等实际表现。上下文地图还要记录模型之间的接触点和翻译。DDD Reference,2015,印刷页2、29 本例按业务问题分出租赁、维修和结算三个子域。租赁关心约定、交付与归还;维修关心故障处理和质量放行;结算关心应收、收款和未结金额。这种分析首先描述业务能力,不提前指定进程、数据库或服务数量。 解决方案可以为这些问题建立不同范围的模型。方案 A 把租赁和维修放入设备运营上下文,结算单独建模;方案 B 分出...
软件建模21:Event Modeling
客户在预留页面选择设备 E1、10 点开始、12 点结束,点击确认。结果页除了设备和租期,还显示客户编号、确认时刻和持续小时数。这七个字段从哪里取得?如果页面又增加“已收押金”,后端没有收款输入,也没有收款事实,字段就不能凭界面需要自动成立。 Event Modeling 可以把这个问题画成连续的信息路径,再用场景核对路径上的值。本篇给设备租赁增加一条可运行的预留流程,检查输入、命令、事件和读视图是否吻合。素材与业务规则均为教学构造,不代表真实参与者完成过工作坊。 一条路径需要哪些内容 Adam Dymitruk 在原始说明中以时间线组织信息,连接界面、命令、事件和视图,并要求追踪字段从输入到输出的变化。命令表达改变系统的意图,视图提供使用者需要的信息;场景可以围绕具体命令或视图展开。Event Modeling: What is it?,2019 本例的预留页面只有四个输入:预留编号、设备编号、开始和结束时刻。客户编号来自会话,确认时刻来自服务器时钟。为了结果可重复,实验把会话和时钟也固定在 JSON 中,分别放入 session 与 clock;它们是测试替身,未实现登录鉴...
软件建模20:EventStorming
“预留已取消”后面能否直接放“退款已完成”?如果预留没有收款,退款对象不存在;即使收过款,应退金额也可能取决于取消条款。这条看似顺畅的事件链,隐藏着至少两个尚未回答的问题。 统一语言与知识消化 检查了词义如何改变模型。本篇将同一租赁材料按事件组织,再补充命令、政策与热点,运行一段可复现的合成演练。它由单人编写,没有真实业务参与者,也没有经过跨职能工作坊确认。 方法的重点是共同校正理解 EventStorming 官方将它描述为协作探索复杂业务领域的灵活工作坊形式,并区分面向组织、服务和软件等不同用途。原作者 Alberto Brandolini 的书页使用“集体学习”描述其目的。不能把某次练习采用的便签数量、顺序或软件工具当成所有场景的固定流程。官方介绍、作者书页 Brandolini 在2019年 Leanpub 访谈中解释,参与者各自了解流程的一部分,先提供事件片段,再尝试排成一致的时间线;排列过程中,不同人会纠正先后关系并补充例外。他也明确提到早期博客描述的流程已经不同于其当时做法。因此,方法会演进,不能仅据早期介绍宣布一套永恒步骤。原作者访谈逐字稿 这次演练保留“用具体...
软件建模19:统一语言与知识消化
“客户要租一台可用设备,付款后结算。”这句话看似完整,却没有说明客户是签约组织、领取人还是付款方;可用指物况合格,还是指定租期没有冲突;结算是收到钱,还是费用与往来款已经核对。每个词都可能进入一个字段,然后把歧义带进运行结果。 计划、资源与承诺 已区分意图、承诺与实际动作。本篇从三个含混词出发,构造初稿和改进模型,用同一组输入观察行为差异。场景完全是教学设计,没有真实访谈;代码通过只能说明候选表达符合这组假设,不能证明某个组织已经达成共识。 统一语言需要能表达场景 Eric Evans 的《DDD Reference》2015年版在 Ubiquitous Language 中讨论了日常交流与代码术语脱节的问题,要求用模型表达场景,并让新的表达反馈到模型和实现。它限定在明确上下文内使用共享语言,并非要求一家企业所有部门只有一套词义。原文,印刷页3—4 词汇表可以记录暂时采用的含义,却无法单独证明这个含义能回答问题。“客户:使用系统的人”仍然无法决定账单属于谁。能推进理解的材料是具体关系与反例:甲组织签约、乙领取、丙付款,哪一个身份参与哪一项规则? 本次演练保存了一个有意简化的 I...
软件建模18:FDD 按 feature 设计与构建
预留 R1 占用设备 E1 的 [1,3),下一份预留 R2 从5开始。租赁人员把 R1 延到5时应当成功,延到6时应被拒绝。若程序只检查“新终点大于旧终点”,它会破坏已有承诺;若把旧区间也当成其他占用,它又会拒绝所有延期。 整体模型与计划 已把这个结果列为 F02。本篇完成它的一次独立 Python 增量,保存设计走查、失败基线、实现、测试和隔离目录集成证据。沿用 组件复用中的延期问题,但没有修改或接入 Java 租赁核心,也没有把单人实验描述成真实组织采用 FDD 的结果。 选择一个能交付的增量 FDD 的第四、第五个流程分别是 Design by Feature 和 Build by Feature。Palmer 的原作者教程将它们配对执行:先围绕选中的功能组织设计,再实现、测试、检查代码,并把合格结果纳入常规构建。原文没有要求测试一定写在代码之前。Palmer,第二部分 两项流程配对,意味着选中的行为最终要进入可运行版本。若只有顺序图完成,交付仍停留在设计;若代码只在一个演示入口跑通,却没有进入组合构建,旧功能与新功能是否共存也没有证据。本例据此选择一个范围较小的延期功...
软件建模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 清单说明用户...










