用途
本技能面向“跨聚合约束检查”这一常见设计难题:当出现“在聚合 A 的用例中想确认聚合 B 的状态”这类需求时,帮助做出设计判断。典型例子是“只要有一个商品关联到某品牌,该品牌就不能删除”,即 Brand 聚合(想删除)与 Product 聚合(确认关联)之间的约束。技能强调不要急于跳到技术解决方案,而是按步骤推进:先质疑需求,再理解技术约束,最后做出取舍。
主要能力
技能提供一套分步判断框架:
-
质疑需求:在动技术之前先重新审视业务需求本身。用“该约束真的必要吗 → 放到整个生命周期看会怎样 → 实际运用中实质是什么约束 → 是否值得为此付出复杂实现的代价”的框架追问。以品牌删除为例:品牌注册时商品为零、可删除;运用中几乎都有关联商品;实质等同于“品牌不可删除”,因此应重新考虑是否值得构建复杂的约束检查机制。需求缓和选项包括:逻辑删除(改为“非活跃”)、废除约束(直接禁止删除)、修改条件(如“N 天以上无关联商品才可删除”)、接受无关联的垃圾数据。
-
判断是否为建模问题:若跨聚合约束看似必要,可能是聚合边界划错了。判断流程:A 与 B 的关系为 1:1 时考虑合并为同一聚合(如 Task 与 TaskReport,可在一次事务中维持不变量);1:N(少量)时考虑通过需求调整缩小规模后合并;1:N(大量)时采用独立聚合加最终一致性,通过领域事件协作;若 B 只是纯查询需求,则用 CQRS 读模型(投影)应对,B 不作为聚合而作为视图构建。
-
避免 Saga 误用:Saga 本意是按顺序执行多个操作并在失败时补偿(如接单→库存预留→支付→配送安排)。把“确认品牌是否关联商品、有关联则拒绝删除”这类单纯约束检查当作 Saga 使用是误用。技能给出区分标准:目的(多步分布式事务管理 vs 单纯数据存在检查)、性质(长时间多操作协调 vs 同步约束确认)、失败时(补偿回滚 vs 拒绝操作)。
-
理解 CQRS/ES 技术约束:大原则是命令侧只用命令侧解决。命令不得依赖查询侧读模型,因为事件异步性会产生延迟、存在竞态条件、违反职责分离、与最终一致性矛盾。技能给出反例(命令侧依赖读模型做存在检查)与允许做法:通过聚合直接询问(Actor 模型消息)、或通过命令侧仓库/领域服务只读参照其他聚合。应用层原则:参照其他聚合 OK、其他聚合的更新(不同事务)OK、其他聚合的更新(同一事务)NG。事件存储基本只能按聚合 ID 访问,无法直接做“某品牌 ID 下有哪些商品”的反向查询;若需反向查询,需额外准备索引读模型并在商品增删改时同步更新,成本较高。
-
做出取舍:采用 CQRS/ES 需接受事件处理延迟导致的临时不一致、补偿事务失败时的垃圾数据、读模型与写模型临时偏差,并将其作为分布式系统的基本特性在设计阶段纳入。应接受:临时不一致数据、无关联数据、读模型延迟;不应接受:聚合内部不一致、破坏业务规则、永久性数据不一致。
使用方式
技能给出整体判断流程:跨聚合约束检查出现 → 1. 该约束真的必要吗(质疑需求,不必要则废除)→ 2. 是否建模问题(1:1 合并同一聚合;一方为查询需求则用 CQRS 读模型;确需独立聚合则继续)→ 3. 是否误用 Saga(约束检查用 Saga 不恰当)→ 4. 能否只在命令侧解决(可以则用仓库/消息参照其他聚合,不可依赖读模型)→ 5. 能否接受读模型的“尽力而为”检查(接受则参照读模型并容忍竞态与最终一致性)→ 6. 是否绝对需要强一致性(是则需重新审视聚合边界;否则最终一致性加容忍垃圾数据)。
技能还提供评审清单,覆盖需求(是否追问约束必要性、验证全生命周期实效、探讨缓和可能)、设计(是否误用 Saga、是否考虑合并同一聚合、纯查询需求能否用读模型、是否理解事件存储反向查询限制、命令侧是否依赖读模型、是否通过命令侧仓库/消息参照其他聚合、应用层是否在同一事务更新多个聚合)、实现(反向查询的读模型成本是否估算、是否设计为容忍临时不一致、是否评估复杂度与业务价值是否匹配)。
适用场景
代码评审、架构设计、需求分析中遇到跨聚合约束问题时使用。
限制
资料未提供该技能的具体安装方式、运行环境、平台支持、收费与价格信息,暂未提供。相关技能(aggregate-design、aggregate-transaction-boundary、cqrs-tradeoffs、cqrs-aggregate-modeling)为建议并读内容,其具体细节暂未提供。