软件建模36:同题比较——分析模式、四色、DDD与FDD怎样配合
一份租赁需求可以同时借助分析模式辨认资源承诺,用四色区分参与角色与交易活动,用领域驱动设计确定一致性责任,再按 FDD 组织可交付特征。它们关注的问题存在重叠,不能通过“哪一张类图更短”评出统一名次。 本篇使用相同输入运行三个教学候选,检查它们分别遗漏什么。候选代表具体设计决定,不代表某种方法的全部能力;过程方法另用特征与验收结果的关联来评价。所有数据均为合成案例,没有真实团队工作坊或交付效率统计。 先固定需要解释的事实 申请 r1 希望租用 camera-A,时间为 UTC 十月三日十点到十二点。party-A 提出申请,party-B 承担付款角色。现行目录每小时十元,确认后更新为十五元。模型应能说明谁参与了这次活动、何时产生占用,以及哪一个价格仍然约束旧草案。 这组需求沿用半开区间:十二点结束的租期与十二点开始的租期相邻,不重叠。计划本身不占用设备;确认才产生承诺。取消释放占用,但原请求重试仍返回历史确认,不能重新占用;原来因冲突失败的请求,释放后重试也仍返回历史失败。 八个场景分别检查计划与承诺、重叠拒绝、相邻允许、取消后确认重放、失败重放、双重参与角色、旧费率保留和相...
软件建模35:函数式领域建模——类型、纯函数与显式状态变化
同一条租期规则可以写成对象方法,也可以写成接收数据、返回结果的函数。两种写法都必须拒绝提前量不足的申请,也必须解释拒绝后原有状态是否改变。把方法改成静态函数,并不会自动得到更可靠的领域模型;差别要落在输入、结果和状态变化的表达上。 本篇沿用 24:身份与值对象 的设备生命周期,以及 26:规则与工厂 的租期、报价和合同草案。实验用 Java 21 编译两组实现,逐项比较结果,再让两份有意写错的程序进入编译器。 相同规则,两种调用形状 教学规则保持不变:租期至少提前一小时,最长四十八小时;按实际时长向上取整到小时报价;费率版本和金额保存在草案中。设备可以从待检进入在役,从在役回到待检,待检或在役均可退役,退役后不能恢复。报价成功只表示生成草案,不能证明设备已经被预订。 对象方案直接编译既有的 Equipment、RentalPeriodSpecification、PricingService 和 RentalContract.Factory。Factory 持有规则对象与报价服务,调用 create 后返回草案,违反租期规则时抛出异常。设备对象则通过方法修改自己的状态;身份在操作...
软件建模34:漂移、往返与版本
生成的设备程序被手工补上一条规则:活跃设备暂时不允许退役。补丁运行有效,但下一次按旧模型生成,规则就消失了。另一种修补方式是从代码读回迁移表,可这张表仍然允许退役,新增限制实际藏在函数分支里。 本篇实际执行这两种失败,再构造模型与代码同时修改同一迁移的冲突。最后把状态名从 ACTIVE 改成 READY,检查旧快照能否继续使用。实验讨论的是有限状态工具的演化,不承诺通用往返工程。 先区分四种会变化的内容 生命周期模型表达状态和迁移;生成逻辑决定如何把它们写成 Python;生成物是某次转换的结果;手写政策表达暂未进入 DSL 的规则。它们有不同的修改入口,不能只靠文件扩展名判断谁应被覆盖。 Fowler 的 Generation Gap 说明通过继承将生成与手写部分分开,以便重新生成。本例沿用第33篇的函数组合:生命周期函数可重建,理由政策保留在独立文件。这个实现借鉴分离原则,没有使用生成基类与手写子类。Generation Gap,作者说明 初始源码由第33篇构建入口产生,仍经过第32篇校验和第31篇平台转换。实验随后只修改本章保存的副本,不编辑被冻结的工具或累计 Java ...
软件建模33:模型到代码,生成、解释与手写如何分工
同一份设备状态模型,可以生成带详细错误信息的新程序,也可能因为模板的一行修改,把“禁止退役”变成“保持原状态并成功返回”。两份文件都能编译,生成过程也都可以稳定重复。要判断转换是否保持业务含义,必须执行允许和拒绝两类合同。 本篇承接前面的有限状态工具,固定设备模型,改变生成逻辑,比较手写、解释和生成路径。另加一条手写政策:退役必须填写理由。这项新增政策放在生成物之外,检验自定义行为怎样与生命周期规则组合。 三部分分别负责什么 Fowler 的 Semantic Model 条目将其定位为由 DSL 填充的模型。本例相应区分输入文本、解析得到的有限状态模型以及执行该模型的代码;JSON 本身不负责决定某次操作是否合法。Semantic Model,作者目录 输入继续使用第30篇的三个状态、三个操作、四条迁移。parse_model 提供结构与有限状态语义,设备合同再约束准确的迁移集合。第32篇的 audit_model 返回各层检查结果,生成入口据此决定是否继续。 通过检查后,第31篇的 pim_to_psm 补入固定 Python 平台选择,psm_to_python 生成源码...
软件建模32:模型校验与业务约束
一个状态模型可以是合法JSON,所有引用都能找到,每个操作也只有一个目标,却仍然允许退役设备恢复在役。错误没有藏在逗号或类型里,而是模型选择的业务规则与既定合同不同。把所有检查统称为“模型合法”,会掩盖已经证明和仍未证明的部分。 受限模型转换 已经执行模型到代码的转换。本篇在转换输入之前区分语法结构、通用状态机语义和设备业务合同,并用实际可执行的错误策略检验这三层。另以租期和设备引用说明,模型约束与实例数据约束也有不同对象。 解析成功只排除了一类问题 JSON首先提供一种数据表示方式。states 写成字符串仍可能通过JSON解析,但当前语言要求它是标识符数组;迁移少了目标字段也没有形成完整模型。结构检查必须落实到选定语言的字段、类型、版本和标识符规则。 本章先完整执行 validate_structure,检查对象字段集合、数组形状及每条迁移的三个字段。它也拒绝重复JSON键和非标准数值常量,这是本工具的严格输入政策。不能因为常见解析器恰好保留最后一个同名键,就把含混输入当作确定模型。 flowchart TD I[输入模型文本] --> S[语法与完整结构检查] ...
软件建模31:CIM、PIM与PSM的受限转换
“待检设备验收通过后进入在役,退役后不能恢复”是一条业务约定。把它画成状态图,再画成带英文名称的类图,最后贴一段代码,仍然缺少一个可检查的环节:哪些输入经过什么规则,产生了哪些输出,又有哪些原信息没有进入实现? 本篇只转换设备生命周期的一个小片段。输入是人工整理的中文业务条款,输出经过有限状态模型、Python平台模型和实际可执行代码。预留、金额、设备身份都不在转换范围,聚合一致性边界 中的并发保证也不会因为生成了状态机就自动出现。 三个视角需要同一条转换线 本文采用 OMG 于2003年发布的《MDA Guide》1.0版术语。该版将 CIM 的关注点放在环境与需求,PIM 隐藏指定平台的实现细节,PSM 再加入使用具体平台的方式;平台无关具有相对范围。原文,2.2.9—2.2.15节 业务人员关心验收后能否继续使用设备;有限状态模型关心状态、操作和允许迁移;Python目标还要决定状态用什么值表示、如何查找迁移,以及操作被拒绝时返回还是抛异常。三者围绕同一组约定,却各自回答不同问题。 flowchart LR C[CIM 中文条款与业务环境] -->|显式词汇映射...
软件建模30:模型、元模型与DSL
一份 JSON 可以正常解析,却把退役设备重新审批成活跃设备。另一份 JSON 把 ACTIVE 写了两次,程序若直接放进集合,重复项就会悄悄消失。格式正确、结构符合约定和业务正确,是三个不同的检查问题。 本篇为设备生命周期建立一个受限 DSL,提供真实解析器、模型校验器与执行入口。输入只有状态和迁移,不接受任意表达式。它将为后续转换和生成实验提供稳定接口,而不是扩展成通用建模平台。 语言需要表达什么 Fowler 将 DSL 描述为聚焦软件某一方面的小语言,并区分独立解析的外部 DSL 与宿主语言中的内部 DSL。JSON 只是本例选用的外部表示;状态、操作和迁移的含义由本例自己的规则定义。Domain Specific Languages,作者说明 模型是具体的设备生命周期:有哪些状态、从哪里开始、哪些操作可以改变状态。元模型在这里规定允许出现哪些概念及关系:一个模型有状态与操作,一条迁移引用来源状态、操作和目标状态,并受确定性等约束。Schmidt 对领域专用建模语言的讨论也将元模型与概念关系、语义约束联系起来。Model-Driven Engineering,页27 本...
软件建模29:Model-Driven Design、MDD、MDE与MDA
设备退役后不能重新审批为可用。这个规则可以写进 Java 方法,也可以放入状态迁移表,由解释器执行,或者转换成另一份程序。三种做法都使用模型,模型在执行链里的位置却不同。把它们都简称为 MDD,会掩盖谁负责实现规则、修改以后需要重新运行哪一步。 本篇沿用第24篇的设备生命周期合同,制作手写、解释执行、转换生成三条路径。实验只比较三个状态和三个操作,不把设备身份、描述、仓储与整个租赁应用一并生成。 相近名称下的不同问题 Evans 的 Model-Driven Design 强调设计与领域模型之间直接、清楚的对应,让术语和职责进入代码,同时让实现经验反馈到模型。这种关系可以通过手写实现维持,不以自动生成代码为成立条件。DDD Reference,2015,印刷页6 为避免缩写混淆,本系列将 MDD 用作 Model-Driven Development,讨论模型如何参与开发工件的产生;MDE 用作 Model-Driven Engineering,讨论建模语言、约束、转换和工具链的工程安排。这是行文约定,不把两者划成没有交集的标准分类。Schmidt 的原论文将领域专用建模语言、...
软件建模28:深层模型与持续重构
“这台设备可用”至少省略了三个条件:它是否具备出租资格,询问的是哪个时间窗口,那个窗口内是否已有承诺。设备当前没有被拿走,也可能已经预订给明天的顾客;维修完成的设备,也可能尚未通过租赁方检验。一个没有参数的布尔属性难以表达这些差别。 应用用例与仓储 已把资格、租期规则和日历接到同一个预留流程。本篇在这份可运行应用上抽出可用性评估,保留旧实现作对照,逐步比较返回值、快照和事件,检查概念变得清楚以后,已有业务契约是否仍然成立。 深层模型来自更准确的问题 Evans 在《DDD Reference》的“Refactoring Toward Deeper Insight”中,将领域理解的深化与模型、代码表达的改进联系起来。深层模型需要捕捉真正影响设计的领域含义,类更多或继承层次更深并不构成证据。2015年摘要,印刷页8 设备租赁场景中,模糊的“可用”同时混合了设备性质和某段时间的承诺。把它改为 available(设备, 租期, 当前条件),首先暴露了查询缺少的输入。本章进一步保留各个条件的判断结果,使一次否定能够说明究竟缺了什么。 这仍是合成教学场景,没有真实租赁人员的访谈,也不声称...
软件建模27:应用用例、Repository 与领域事件
设备检验通过、维修限制解除、租期合法,仍不足以说明一次预留已经完成。预留还会产生占用、历史回执和合同草案;其中一项保存失败,其他项应该怎样处理?成功结果已经保存,通知发送失败,重复请求又该返回什么?这些问题需要一个明确的应用用例来协调。 聚合与一致性边界 已证明日历内的互斥,规则、报价与创建 则生成合法草案。本篇将它们接到同一个 Java 应用中,复用设备实体和金额类型,实际检查仓储往返、请求回放及提交与发布之间的故障。 用例协调已有领域行为 RentalApplication.reserve 接收完整命令和显式时钟。命令包含请求编号、设备编号、租期、费率及费率修订号。设备状态继续由第24篇的实体保持,租期规则和报价使用第26篇实现,占用仍由第25篇日历判断,应用层负责调用顺序与结果保存。 新请求必须找到设备,设备须为 ACTIVE,维修评估须为 RELEASED,租期须满足提前一小时、最长四十八小时的教学参数。费率仍按完整小时向上取整。工厂生成的对象只是合同草案;它没有证明签署或收款,也不能绕过日历的重叠检查。 flowchart TD C[预留命令与当前时间] --...















