saas

微服务架构风格的DDD

2021-04-06  本文已影响0人  红茶码字

领域驱动设计的源头书籍

关于DDD能找到的最早的一本书是《领域驱动设计 软件核心复杂性应对之道》,2003年Eric Evans 著,Martin Fowler作序。是的,你没看错,是差不多20年前的了。所以DDD不是什么新技术,而是老技术,但历久弥新,即使时代变迁,今天依然是经典。另一本《实现领域驱动设计》太厚了,转而学习同一作者[美] Vaughn Vernon 著的《领域驱动设计 精粹》。但感觉 Vaughn Vernon所理解的未必完全是 Eric Evans所表达的。 截图Eric Evans 的概念,后面再结合我自己的经验理解。

一、Layered Architecture分层定义

《领域驱动设计 软件核心复杂性应对之道》分层访问关系
《领域驱动设计 软件核心复杂性应对之道》分层定义

二、 时代变迁了哪些?

从上面的图示可以看出,20年前基本是桌面应用的时代,web应用也没有非常广泛,更不用说现在的云时代+移动时代。虽然现在依然流行桌面应用,但作为更广泛的业务应用系统,这里只讨论新时代下基于微服务架构风格如何应用DDD及20年前的不同点。

基于微服务架构风格的应用组件
  1. 前后端分离。云+移动的时代,注定了前后端需要分离。单独看前端应用(例如Android App),也可以很复杂,除了界面展示的部分,也会有缓存、也会有远程API调用,也会有手机硬件设备(摄像头、指纹)等的基础设施访问。也是一个独立的完整的应用,也可以单独讨论DDD。但客户端应用架构风格上与桌面应用也差不多,不是这里讨论的主题。从更高的层面上,这里将frontend app与BFF app都看作是DDD分层的UI层。在Naresh Bhatia的文章中,认为SecurityWebService、TradingWebService 、MarketPriceListener 、ExchangeMessageListener 都属于UI层。我不太认同。我认为MarketPriceListener 、ExchangeMessageListener 属于Application Layer,而SecurityWebService、TradingWebService 一般在BFF里,属于UI层。是的,我将UI层从微服务架构风格的后端应用(下文简称“微服务应用”)里踢出去了,归到前端与BFF,微服务应用里只剩下三层。
  2. UI层不能再访问基础设施层,不能再访问领域层。参照图1各层访问关系,但其它各个箭头表达的访问关系仍然是成立的。
  3. 从分层定义来看,基础设施层,不再为用户界面层绘制屏幕组件。其它各层定义,依然成立。

三、 各层都包括了哪些?

1. UI Layer

2. Application Layer:

可以协调Domain Service ,访问Domain Layer,作为IOC 或Bean Factory 装配各种Bean (一般由Spring 代劳了,但java Configuration 应当在此层)。 可以调用RPC ,监听消息队列。

3. Domain Layer:

领域层实际是Domain Business Model 领域业务模型,不是简单的数据模型,不能理解为E-R图中的E。这一层实际也是业务应用系统中六边形架构的核心。这个模块作为Artifact只需要Mock Repository接口,而不需要依赖于任何第三方库、第三方框架、中间件(Servlet容器、MQ中间件、DB服务器),就可以单独测试,并且验证当前Domain所有业务逻辑的正确性。如果某一个Class需要依赖于除了JDK之外的框架(log日志框架例外)才能编译通过或者单元测试,则这个Class很可能不属于Domain Layer。

4. Infrastructure Layer:

四、FAQ

1. Repository 属于Domain Layer 还是Infrastructure Layer?

阿里殷浩认为Repository的接口是在Domain层,但是实现类是在Infrastructure层。我也认为如此。Eric Evans 提到“REPOSITORY应该让客户感觉到那些对象就好像驻留在内存中一样”,所以Repository Interface 表达的仍然是当前Domain 的业务逻辑。但在具体实现时,这往往有些争议,因为要实现这个Repository Interface,implementation class 肯定要依赖于更底层的DB Driver或ORM,并且屏蔽技术细节。例如业务刚发展时性能需求不高,后来用户量激增,需要缓存了,单个关系型数据库不能满足了,于是用了Redis作缓存,部分数据可能又改为了MongoDB做NoSQL文档存储。假设Domain Model 做成一个单独的Artifact,为了保持其更纯粹的业务模型不被技术细节与底层设施所侵蚀,一般不希望这个artifact依赖于mybatis或Redis client。在六边形架构或洋葱圈架构,可以让这个infrastructure artifact 依赖于 domain model artifact。现在普遍流行MyBatis,可以认为mybatis mapper的xml配置文件属于Infrastructure Layer,是Repository Implementation。

2. 有哪些Artifact?构建时是怎样的依赖关系(maven depend)

3. 六边形架构关于输入输出的依赖

XxxDomian作为六边形架构的核心,不会直接依赖于外部。但

  1. 定义了Oberserver接口用于间接输出Domain Event到MQ,相当于定义了一个六边形架构的输出端口;
  2. 定义了Repository接口用于间接持久化到数据库或者缓存,相当于定义了一个六边形架构的输出端口;
  3. 定义了DomainService接口用于接受外部的rpc输入,或者接受MessageListener消息输入,相当于定义了一个六边形架构的输入端口。

具体的MessageListener实现类,Application Service 实现类,将外部的消息/rpc适配给到Domain Service,并协调相关资源装配相关流程。Observer具体实现类、Repository具体实现类作为适配器,由Applicaiton Layer注入到Domain Layer ,(当然实际Java项目有时候由Spring IOC代劳了一部分工作)。
Domain 不关注任何的技术框架与具体的技术细节,不关注任何的输入输出设施,只专注于业务逻辑,并且清楚的知道业务的生命周期,在流程的重要环节设置了接口,具有很大的可扩展性。如果人力有限,只能逐个Artifact开发,那么XxxDomain必须是第一个。

五、参考

  1. 《领域驱动设计 软件核心复杂性应对之道》[美]Eric Evans 著
  2. 《技术人的百宝黑皮书》阿里技术专家详解 DDD 系列(作者:殷浩)
  3. 《领域驱动设计 精粹》[美] Vaughn Vernon 著
  4. archfirst.org/domain-driven-design Naresh Bhatia
  5. 殷浩详解DDD系列 第三讲 - Repository模式
上一篇 下一篇

猜你喜欢

热点阅读