走近领域驱动设计(二)

上一篇讲了事件,以及为什么要使用事件,主要是为了解耦,但是有同学就问了,同步如果订阅事件的人太多,比如13亿人都关心上头条的事,那么RaiseEvent得等13亿人都处理完,那得多久呀,从此再也不敢发事件了。

事件驱动之异步事件

举个例子,你在网上下单,下完单要通知库房,甚至要通知供应商补货,如果都是同步的话,消费者还不等急死呀,实际上你在电商网站上下个单, 一般你很快就能到订单页面,那个页面告诉你:“兄弟,订单已经创建成功,订单号是xxxxx-xxxxx-xxxx-xxxx,你的订单已经提交到库房” 等。然后你就很快了的下另一单了。好吧,提问的同学,说好的妹子呢?

实现思路

我们先回顾一下同步事件驱动的代码:

发出事件

订阅事件

我们可以看到真正的事件协调者是EventBus, 之前的代码如下是同步的:

为了提高性能,我们可以先来第一步改进

我们可以看到,现在并行处理可以大大加快速度。但是有两个问题,第一个问题就是没有处理异常,所以让我们加上异常。

第二个问题,就是我们虽然用了并行加快了速度,但是还没有正真实现异步,整个程序还是等所有Handler处理完才返回。

这段代码执行完,竟然发现Handler没有执行,好吧,原因是IQueryable的延迟执行,所以我们需要调用一下ToList。

好了,我们就这样轻易的实现了一个AsyncEventBus,是不是感谢.Net的强大?

CQRS是Command Query Responsibility Seperation(命令查询职责分离)的缩写。 世上很多事情都比较复杂,但是我们只要进行一些简单的分类后,那么事情就简单了很多,比如我们把人分为男人和女人,也可以把人分为大人和小孩;还比如,我们说国内和国外,城市和农村。经过一些类似这样的划分,我们对不同的类就有不同的关注。 这样我们就会有妇女儿童医院专门让女人生孩子,而不会建一个医院让男女都生孩子。

CRUD

CRUD (Create, Read, Update, Delete) 增查改删,我们很多系统都是对数据的增查改删。过去我们很多系统比较简单,基本上增加的数据就是你要查询的数据,所以很多时候其实一个简单的Excel就能搞定。 而且增删改查也足够的简单,所以我们很多系统分层后在数据层Repository里仍是对单表的增删改查,这样对不少的系统都符合。

但是,系统规模稍微大一点,我们都知道我们的数据库里的数据模型很难和我们业务层需要的模型一致。 于是我们引入了Domain Model, Repository里就会做Domain Model的来回转换。

同时我们在UI层要的数据,往往又和具体的Domain不同,这个时候我们又要定义一个ViewModel. 而这些ViewModel又是组合不同的DomainModel得来的。

传统的代码里的问题:

领域里有很多分页和排序,尤其是Repository里。

查询的方法里暴露了很多不应该有的领域模型的属性,因为需要组装DTO。

如果使用ORM,预加载了很多数据以提高性能,但是占用大量内存,而且需要维护这些数据.

加载组合庞大的数据,比如页面是需要一个名字,我们也会把整个User数据取出来。

重要的原来把数据混在一起,复杂的查询相当难以优化。 尤其是数据库出现大量的Join 系统性能极速下降。

最重要的是我们把读写都放在了一起,显得责任不够清晰,代码也更复杂了一些,比如读数据是不太关心事物的,读数据是不需要验证的,只有写的时候才需要做数据校验,这也比较符合SRP(单一职责),但是用CRUD的思维是我们全都混在了一起。

CQRS

我们仔细看CRUD, 其实可以更简单的分为读(R)和写(CUD)。我们想想大部分情况都是,一个方法要么是执行一个Command完成一个动作,要么就是查询返回数据。 比如我们回答问题的人不应该去修改问题。

当我们读写分离后,我们对应的代码也会分离。

数据存储

写的一端需要保证事物,所以一般数据存储为第三范式,读的一端一般都是反范式可以避免Join操作,这样我们只需要把数据存储为第一范式。

扩展

大部分的系统里写数据要远远少于读数据,并且一般都是每次修改很少的一部分数据,所以在写这端扩展都不是特别紧迫,读数据基本都远大于写数据的次数, 所以扩展就更重要。 我们很难建立同一个Model 既能给写数据和读数据公用而且能够保证性能都比较好的。

查询端

查询端由于只是读数据,那么所有的方法应该都是返回数据,而且返回的数据就是界面直接需要的DTO,这样可以减少传统的方法中把DomainModel映射为ViewModel或者DTO。同时可以减少传统的领域里的一些混乱。

写端

由于把读分离出去,所以我们就只关注写,那么我们写这一段需要保证事物,数据输入的验证,另外一般写这一端都不需要及时的看到结果,所以大部分都需要一个void方法就可以,那么让我们系统异步就更加方便。这样使系统的扩展性大大增强

代码更容易集中处理

当我在一些系统中使用CQRS后,很多地方代码大大简化,比如我所有的写操作都是一个Command, 那么我定义一个UI Command, 让所有的Command集成这个,那么我可以在这个UI Command里做一些通用的处理,比如Validation。同时我只需要定义一个Command Bus, 然后把对应的Command Bus分发到对应的Handler里(我前面几篇有实例代码),那么代码的耦合度大大降低。

代码分工协作更容易

由于读这一端直接读数据,而且对数据库没有任何操作,那么我们可以根据UI定义对应的DTO,那么开发的时候我们可以用Mock数据,至于数据怎么存的,那么我们随后只要添加一层Thin Data Layer即可,实际上当我们使用CQRS后,很多时候我们把数据保存的时候都直接保存为Denormalize的,那么从数据里直接查询单表的数据就可以拿到页面需要的数据,大大提升读取数据的性能,同时代码也会极其的简化,开发读这一段代码的开发人员甚至都不需要对业务有太多了解。

实现

简单的实现

使用了Event后

使用了Event Source 和Service bus后

相关内容:

我们如何从领域驱动开发当中获益–王德水

领域驱动设计,遇见你之前 我们公司推行和实践敏捷已经很多年了,SCRUM已经成功应用于大部分项目,得益与业界敏捷开发大师以及国内很多优秀工程师的分享和宣传,我们使用了很多优秀的软件开发实践,比如测试驱动开发(TDD),行为驱动开发(BDD), 持续集成(CI)等等为我们带来了很多收益。由于我们公司以……

技术博客 技术趋势 敏捷实践 1027 阅读

Mind Matter项目分享——设计不仅仅是设计

Mind Matter软件旨在促进企业的战略发展,并帮助推动战略的实践。其核心业务是开发下一代战略软件和服务。与各种类型和规模的企业组织合作,共同定义、设计和执行战略。 目前开发的软件作为一款简单精巧的协助工具,帮助用户定义、设计、讨论、决策和交付发展战略。 Mind Matter项目自2017年9……

技术博客 敏捷实践 943 阅读

善用工具——成就高效沟通协作的团队

《敏捷软件开发宣言》  我们一直在实践中探寻更好的软件开发方法,身体力行的同时也帮助他人。由此我们建立了如下价值观: 个体和互动 高于 流程和工具  工作的软件 高于 详尽的文档  客户合作 高于 合同谈判  响应变化 高于 遵循计划 也就是说,尽管右项有其价……

技术博客 敏捷实践 1027 阅读

敏捷实践系列(三):代码管理流程

我们已经从SVN切换到Git很多年了,现在几乎所有的项目都在使用Github管理。对于那些还在坚持使用SVN的,我实在想不出原因,权且称作守旧派吧。 Git的优点 Git的优点很多,但是这里只列出我认为非常突出的几点。 感兴趣的,可以去看一下Git本身的设计,内在的架构体现了很多的优势,不愧是出资天……

技术博客 敏捷实践 820 阅读

敏捷实践系列(二)

大话西游里有一段因为没有沟通的经典, 结局如何大家都知道。 唐僧:你想要啊?悟空,你要是想要的话你就说话嘛,你不说我怎么知道你想要呢,虽然你很有诚意地看着我,可是你还是要跟我说你想要的。你真的想要吗?那你就拿去吧!你不是真的想要吧?难道你真的想要吗?…… 悟空:… 一. 敏捷项目沟通尤其重要 敏捷开……

技术博客 敏捷实践 732 阅读

敏捷实践系列(一)

开篇: 悟空:师傅,为什么你写东西,喜欢写系列呢? 师傅:因为很多东西需要长期的实践呀。 悟空:怎么又开始说敏捷了 师傅:就像一本好书,常读常新,人生不同阶段过的都是不同的人生呀。 悟空:师傅,为什么你原来用上、中、下呢? 师傅:因为原来只写了个上中,别人一直问下,现在如果只写一二,别人要问,我就说……

技术博客 敏捷实践 771 阅读

走近领域驱动设计(一)

从我做过的项目来看,似乎欧洲已经有很多的公司开始实施领域驱动设计了,而我本人了解领域驱动设计也有些时间了。但是网上不管是文章还是代码,都显得太过高大上,一谈领域驱动设计,一大堆的概念一股脑的给你上上来,搞的有点晕头转向,而我想在一些中小项目中实施领域驱动也遇到了不小的障碍,大家对很多新的东西总是处于……

技术博客 技术趋势 743 阅读

我从项目实践中看到的ODC演变

几年以前,我曾经很关注国外的招聘价格,刚毕业的新人月薪可以低到1,500美元,而普通项目经理价格又可以达到10,000美元以上,项目中技术骨干则要高出更多。而在当时我们的ODC小时报价达到30美元(月报价约4,800美元)的已经是很厉害的程序员了。 假设国外市场更成熟稳定,为什么这几个角色价格差要远……

技术博客 技术趋势 敏捷实践 1461 阅读

Elasticsearch – 让你的搜索飞起来

接触Elasticsearch是两年前因为项目的需要。客户位于西雅图,对于新技术有着敏锐的洞察力,正好项目需要实现搜索功能,客户就想尝试采用Elasticsearch来实现整个网站的检索功能,然后就被迫去学习了一下。一开始我是排斥的,但还是忍不住想看一下为什么客户要推荐它。随着深入的使用,Duang~~,才发现这货果然是个神器,只需要轻轻松松的简单配置一下,就可以让你的程序的搜索功能插上翅膀,带着用户在你的应用里翱翔。

技术博客 技术趋势 604 阅读