引言

Udi Dahan曾在2017年阿姆斯特丹的DDD欧洲年会上发表过一篇演讲——if (domain logic) then CQRS, or Saga。视频是UP主从Youtube搬运的,我听力水平一般,所以以下内容有所偏颇的话,还请见谅。

在演讲中,他提到了Sandbox、Private Domain、Public Domain和Collaboration Domain等一些概念,为更好地应用DDD开辟了不同视角。以下便是我的思考与收获。

正文

Udi用级联删除的例子,引出了沙盒Sandbox。错误的级联删除操作,特别是在数据库中Table级别上的删除操作,对任何一个系统而言都可谓灭顶之灾。所以顺理成章的,我们会使用给数据行打上某种删除标志的方法,称之为“软删除”,避免数据被彻底删除。这就象操作系统里的回收站一样,给了我们一次反悔的机会。如果在所有的软件系统里都有这样一个安全沙盒,是不是就完全解决了删除问题?

  • 对此,我认为,对于系统中的所有删除操作,首先都应该有领域行为上的具体含义,比如解雇员工、取消订单、停产产品等等。其次,还要考虑受到删除操作影响的数据,要限定在哪个范围,它们是否有留存下来的业务价值。比如解雇员工后,与之相关的薪酬记录就不能删除,否则会导致账面错误。反之,只在薪酬记录里有个员工ID,却查不到这名员工的姓名、职务等具体信息,也会发生错误。再或者,这名员工先被裁员,之后在招聘时被优先聘用时,如何处理其原有信息,等等。所以,“删除”操作不能简单论之,必须是从业务领域的角度去思考和命名——其究竟是何种业务操作,这种操作在业务上应导致何种后果。比如雇员被解雇后,其所有数据被冻结,其雇员信息不再会更新,其薪酬不会再发放。

随后,Udi用博客作为例子,引出了Private DomainPublic Domain的概念,并阐述了Sandbox与二者之间的联系。一篇随笔被正式发布前,博主可以在编辑页面随便折腾。而在随笔正式发布后,所有的修改和删除操作就需要慎重了。此处,发布前的随笔处于Private Domain,发布后则进入了Public Domain。对处于Private Domain范围内的私有数据,我们可以随意地增删查改,而不用顾忌任何的业务规则和约束。而当私有数据被推送到Public Domain时,则必须顺利通过各种规则的审核与验证,进而成为构成系统的固定组成部分。其中,每个Private Domian对应一个Sandbox,用户可以为所欲为,而不必担心对系统造成实质影响。

  • 对此,我认为,每个Sandbox都对应某个具有领域含义的实体,并可以用与之相关的领域事件作为Private Domain与Public Domain的划分界线。比如一份菜谱,你可以随意修改菜谱里各种菜品的价格、名称,甚至新增或者撤掉某个菜品。而在正式提交更新前,所有人仍旧会使用旧的定价和菜名。这里的菜谱,就是所有菜品所在的Sandbox边界。而最终MenuUpdated事件的触发,才标志着操作对系统产生了实质性改变,数据已经进入Public Domain。如果没有这个提交的步骤,让所有的增删查改都立即产生效果,那顾客一定会开骂了。另一方面,如果没有暂存修改结果的这个Sandbox,也意味着完全不给饭店老板活路——要改就一口气改完,还不能自相矛盾。回到前述的删除操作也是同理。当数据还在Private Domain时,我们可以放心地删除之。而当数据已经进入Public Domain后,就必须去发掘删除操作背后的领域含义了,并由此衍生出更复杂的领域逻辑和领域行为。

Udi接着商品被删除的例子,延伸到购物车中已加入的商品售罄或被停售的情况,提出Collaboration Domain的概念。在竞态条件(即并发条件下的竞争条件)下,即表明有多个参与者需要对同一个数据进行操作,此时属处的领域即Collaboration Domain。这样的协作领域,通常可以围绕if语句进行发掘。有if判断涉及其他的实体,则通常表明该数据也可能会被其他参与者改变。此时,CQRS成为很自然的选择。因为命令执行的环境是经过事先检验的,所以命令总是能成功执行。在这样的设定下,把一个用户下单的操作分割为多个步骤,在放入购物车和提交订单时分别进行一次商品有效性的检验。

  • 对此,我认为,引入CQRS是因为将命令与查询分离后,检验执行环境的部分将由一组查询构成,改变系统状态的部分则由一组命令组成,这样将更容易发现竞态条件,从而做出合理的选择。

为了减少检验的次数,Udi借Shopping Cart Timeout的例子引出了Collaboration Timeout的概念。给购物车一个活动状态的超时设定:用户放入商品时,购物车进入激活状态,跨入协作领域,此时因商品在售,订单可以成功提交;用户未在超时前提交订单的,购物车进入失活状态,退出协作领域,之后商品将因售罄或停售而无法再加入购物车。

  • 对此,我认为,此时的购物车更象是一个愿望清单(Udi在演讲里也有提及),这样的Timeout与超卖都是解决最终一致性条件下的不同解决方案。MSDN CQRS Journey第164页提到的方案,是根据代价大小,选择对客户做出赔偿或者在付款前加锁判定,让其他人等待一小段时间。当席位较多时,因为竞争风险小,可以将席位是否够用的查询交付异步执行,使用户等待时间减少;当席位紧张时,允许提交失败的用户修改订单。唯品会采用的方式,是在商品加入购物车后,将该商品暂时锁定,保证用户在超时前能成功下单。

由于Collaboration Domain和CQRS的存在,Udi指出,必须改变传统的思考方式,因为Saga将更普遍地出现在模型之中。对此不能有退缩和犹豫,应当与领域专家深入交流,使自己也成为业务专家,确保每个流程都完全可控。最后,Udi提出消息中间件是实现Saga的重要工具,于是顺手推介了一下自己维护的NServiceBus框架。

  • 对此,我认为,以用户购物这个Saga为例,将由用户注册->查看商品详情->放入购物车->提交订单->完成支付等多个流程协作完成,而不是简单地放在一个或几个数据库事务里完成。在不同聚合之间以消息或事件为纽带,是处理Saga的核心与关键。所以CQRS、Event Sourcing以及Message Queue都将是实现DDD的利器。

观《if (domain logic) then CQRS, or Saga?》所悟的更多相关文章

  1. domain logic approaches

    领域逻辑组织可以分为三种主要的模式:事务脚本(Transaction Script).领域模型(Domain Model)和表模块(Table Module)” 1.domain logic appr ...

  2. Domain logic approachs

    1.transaction script(事务脚本) 概述: 很多企业应用可以看成一系列的事务,每一个事务可以通过使用一个Transaction Script来处理. 用法: 使用Transactio ...

  3. CQRS FAQ (翻译)

    我从接触ddd到学习cqrs有6年多了, 其中也遇到了不少疑问, 也向很多的前辈牛人请教得到了很多宝贵的意见和建议. 偶尔的机会看到国外有个站点专门罗列了ddd, cqrs和事件溯源的常见问题. 其中 ...

  4. 关于CQRS(老外经典好文)

    CQRS means Command Query Responsibility Segregation. Many people think that CQRS is an entire archit ...

  5. Introduction to CQRS

    原文链接:  http://www.codeproject.com/Articles/555855/Introduction-to-CQRS What is CQRS CQRS means Comma ...

  6. 翻译:wiki中的business logic词条

    Business logic 业务逻辑 From Wikipedia, the free encyclopedia 来自Wikipedia,自由的百科全书 In computer software, ...

  7. Domain Driven Design and Development In Practice--转载

    原文地址:http://www.infoq.com/articles/ddd-in-practice Background Domain Driven Design (DDD) is about ma ...

  8. 领域驱动设计(Domain Driven Design)参考架构详解

    摘要 本文将介绍领域驱动设计(Domain Driven Design)的官方参考架构,该架构分成了Interfaces.Applications和Domain三层以及包含各类基础设施的Infrast ...

  9. [转载]领域驱动设计(Domain Driven Design)参考架构详解

    摘要 本文将介绍领域驱动设计(Domain Driven Design)的官方参考架构,该架构分成了Interfaces.Applications和Domain三层以及包含各类基础设施的Infrast ...

随机推荐

  1. sqlite 数据库与mysql 数据库使用区别记录

    遇到了就记点儿. 1.sqlite 中,设置外键关联,没啥用.只有mysql 中可用.

  2. web文件包含

    web安全~文件包含总结   文章来自freebuf,作者总结的很好,所以拿来做笔记用!!! 0×01 文件包含简介 服务器执行PHP文件时,可以通过文件包含函数加载另一个文件中的PHP代码,并且当P ...

  3. 深海 => 暴力扫描挖掘机

    平时总是联动这个联动那个,写一些小脚本,感觉零碎又没啥意思,想把市面上一些比较知名的工具集合一下,弄个方便点的躺着挖洞的工具,看看效果会不会更好,暂时名字取深海吧,估计又是一个迟迟不填的坑,灌灌灌灌水

  4. 分布式存储系统-HDFS

    1 HDFS 架构 HDFS作为分布式文件管理系统,Hadoop的基础.HDFS整体架构包括:NameNode.DataNode.Secondary NameNode,如图: HDFS采用主从式的分布 ...

  5. RocketMQ开发者指南

    1. 概念和特性 概念:介绍RocketMQ的基本概念模型 1 消息模型(Message Model) RocketMQ主要由 Producer.Broker.Consumer 三部分组成,其中Pro ...

  6. Tomcat启动报错org.apache.catalina.core.StandardContext.startInternal One or more listeners failed to start. Full details will be found in the appropriate container log file

    错误: 今天SVN导入新项目后启动项目时控制台报错,之后在网上搜了很多方法.下面列了一些大佬的解决方案: 1. 检查日志配置文件-logging.properties:https://www.cnbl ...

  7. 题解-FJOI2014 树的重心

    FJOI2014 树的重心 \(Q\) 组测试数据.给一棵树大小为 \(n\),求有多少个子树与其重心相同.重心可能有多个. 数据范围:\(1\le Q\le 50\),\(1\le n\le 200 ...

  8. 把java编译成exe和安装包

    由于某些项目甲方迟迟不结算尾款,这就很烦,只能想一些办法 我们知道java,python之类的代码是没有隐私可言的,那么怎么办,总要发给甲方验收,这就要做一些操作来确保自己的利益. 通过在源代码里加上 ...

  9. 在github上删除项目或某个文件(两种方式)

    一.使用命令删除 首先先上传一个文件到远程仓库,测试一下 输入命令git rm -r --cached 文件名 删除本地跟暂存区的文件,如下图 再输入命令 git commit -m "删除 ...

  10. Linux下安装mysql-5.7.24

    Mysql数据库的安装对于开发者来说,是我们必然会面对的问题,它的安装过程其实并不复杂,并且网络上的安装教程也非常多,但是对于新手来说,各种不同形式的安装教程,又给新手们带来了要选择哪种方式进行安装的 ...