DDD vs CQRS架构
今天主要简单介绍下DDD结合CQRS架构实现的这么一个营销服务,这个项目是公司项目,目前是我一个人在做,可能有些东西不便多说,希望理解吧。介绍分三部分,首先简单说下概念(因为我也不知道多少),然后说下实际应用情况,最后简单说下实现。
DDD领域驱动设计,很高大上的一套方法论,比如领域专家,够高大上吧,其实也未必要那么专业,产品和业务能力强的开发人员也是可以的。我的理解它其实就是一套设计方法论,而且这套方法论有一定的门槛,概念多,业务强,业务架构能力也要好,同时需要团队整体实力。DDD这几年火的一塌糊涂,火是有原因的啊,因为微服务,可能这句话说的有些片面,我的理解就是这样的。简单来说微服务是架构,但是它并没有给出如何对复杂系统进行拆分的具体方法论,而DDD刚好就是指导微服务架构落地的这么一个具体的解决方案,可以这么说,没有DDD方法论的指导,微服务是肯定很难落地的。那可能有人会说,我不做微服务架构,就没必要采用DDD设计了?当然不是,即便你是单体架构,利用DDD方案,只要合理,复杂系统也会简单化、模块化,这么说吧,DDD这个指导方法论,大到领域边界划分,小到聚合单元划分,代码既设计,工程既设计,方案既设计,领域既设计,如果后期想做微服务架构迁移,也能很轻松的落地。
CQRS,命令查询职责分离,简单来说就是读写分离(核心就是消息),这个分离分两个维度,代码级别和数据级别的分离,命令和查询模型分离,仅此而已,一切只是为了设计更简单、单一而已,同时它也引出了诸多问题,如一致性问题、幂等性问题,事务问题等。对于CQRS命令消息我这边的实现比较简单,基于MediatR实现的消息管道分发,数据库也未做读写分离,只是做了模型分离,相对来说是一个极简的CQRS架构,如果要实现一套稳定成熟的框架,需要一定的技术支撑,CQRS只是架构,它并不是框架,目前我了解到的好像.NET是没有成熟的框架(我也没怎么关注)。
实现,下面这张图是我目前做完的一个营销服务,本身业务也比较简单,公司项目不便多说,简单说下技术实现吧
基于.NET5.0,DDD VS 极简CQRS架构实现,整个解决方案简单分了四层,参考DDD分层设计。Service层其实就是api接口层,很轻薄的一层,没有任何业务逻辑,App层我这里实现的比较重,包括业务聚合和实现,Infrastructure基础设施层,仓储实现在这一层。这里简单介绍下Domain层吧,因为它是比较核心的一层吧,领域层包括领域事件、领域模型和领域相关的基础类库。模型层包含了一些聚合,聚合之间通过聚合根id关联,一个聚合根对应一个respository仓储,并且拥有领域事件的分发能力。内部聚合采用强一致性策略,也就是说聚合根控制着整个聚合的不变性和事务一致性,外部聚合采用最终一致性策略,这个主要是考虑性能问题,死锁问题,同时在多聚合一致性上又做了一些额外的设计,主要是确保核心域的数据强一致性。并发控制,因为我这边有个特需的业务需求,库存的问题,我这边采用的是乐观锁结合降级策略实现,Domain层大概就是这些东西,我这边主要是给需要做DDDvsCQRS落地的一些参考,不要纠结,什么样的需求就会设计什么样的方案。
模型分离,主要是命令和查询模型分离,命令关注的是增删改,它会修改模型状态,查询是单独的一套模型,这样在代码层面也做了分离。我这边命令实现是基于MediatR管道实现,同时也做了幂等性处理,命令校验部分基于FluentValidation库实现,并纳入Behavior管道处理,持久化ORM基于EFCORE5.0。查询相对来说比较简单,基于Dapper实现。
事件,我这边主要实现的有领域事件和集成事件,领域事件主要解决的是领域模型状态的变更,解耦聚合之间的业务,同样基于MediatR管道实现。集成事件主要解决的是微服务各子系统之间完整业务的变更,解耦微服务之间的业务,集成事件主要是自己实现的一个极简的事件总线。
顺便提一下,前两天同事问的一个问题,异常提醒持久化方案,我简单说下我这边的处理方案吧,我把异常分为三个类型,面向用户的异常、领域模型异常、系统异常。面向用户的异常,一般为校验类的,这种主要是面向用户提醒的,不记录日志。领域模型异常,此类异常一般情况为领域业务异常,记录日志。最后一种系统异常,也就是未知异常了,统一提醒为系统异常并记录日志。怎么统一处理?在.NETCORE框架里面有两种方案,基于筛选器、或者中间件都可以,还可以完美结合资源筛选器实现多语言功能。
好了大概就这么多吧,因为是公司项目,具体细节不便多说,明天还的上班,就这样吧。