ddd架构浅析
背景介绍
什么是ddd架构,是以ddd思想为参考,做出一份符合ddd思想的框架。
随着技术的迭代升级,越来越多的瓶颈暴露出来,性能瓶颈,系统复杂度瓶颈,这些都逐一被迭代出的技术产物解决。最终的一个产物微服务,几乎完美解决了性能和系统复杂度的问题,保证服务性能的前提下,还简化了系统的复杂度,降低开发难度,让系统更加容易维护。
但是对于B端企业来说,单单解决性能和系统复杂度问题还远远不够,极度复杂的业务,让系统难以维护,动辄几百上千行的方法,让开发人员头疼。每一个简单逻辑的背后,都会存在多个业务方,多个业务方的兼容使得逻辑变得复杂,加上业务的变化频繁这一特点,让系统的复杂度极速提高。
ddd很早就出现了,由于过于复杂难以理解,一直没有很好地最佳实践。ddd的核心思想,就是为了解决B端企业的业务复杂度而生,近些年ddd的突然爆火,是因为有了最佳实践的落地,比较出名的比如cola的应用分层框架。
ddd核心分模块思想
ddd的思想核心是通过领域建模、分层分包的模式来进行降低业务复杂度,简化开发逻辑,清晰业务流向。
通过cola的最佳实践,可以把ddd进行落地,并且由核心和拓展几个点来进行分析。
核心模块
核心分包为 适配器、领域、基建包,
三个包都不相互依赖,形成相互隔离的几个单独模块,让每一个模块都只有很单一的能力,这样就可以很好的把业务限制在领域中,极好的来沉淀建立自己的核心业务能力。
适配器层:
由于B端业务多样性且复杂,所以需要单独的适配器来做,将不同的业务来进行适配,进入自己的核心且单一的能力中。
通过将单一能力,增加多个适配器,提高业务的适配能力。b端业务的多样性,往往体现在数据及命名的多样性,但核心的业务大体相同,所以通过适配器,可以极大降低因多样性带来的复杂度。
领域层:
领域层的单独存在,一方面是为了限制核心业务不会散落的到处都是,另一方面是让开发更加聚焦在核心业务的开发上。通过一些策略及拓展模式,就可以实现核心业务及其不同的特性。
B端企业级对外提供的能力一定是单一的,只有这样才能逐渐沉淀自己在行业内的影响力,如果什么都能支持,反而会觉得什么都不强,都不稳定。而且随着差异太大的业务,会导致成本剧增。
单一的能力,会逐渐去完善产品能力,最终沉淀产出一个标准的行业产品。
在大能力不变的情况下,不同的特性处理,通过一些拓展点,就可以快速实现接手。
基建层:
在B端业务中,三方依赖的侵入性变动也是对业务稳定性的一个侵蚀,比如业务前期,使用某种组件可以满足业务需求,随着发展需要更换另一种组件,这种组件变更给系统带来的稳定性影响是非常重要的,因为组件的变更导致业务宕机是非常不合理的,为了避免这种情况,将三方组件完全隔离是非常必要的。
三方组件包括但不限于:数据库、缓存、mq、三方接口、三方sdk、三方rpc等。
可以认为所有和外部交互的都应该限制在基建层,以此来进行隔离,保证系统的稳定性。
domain模块
domain是三个模块的轴承,通过依赖倒置,让三个模块相互隔离,全都由domain拉着,通过domain进行交互。
domain的必要性:
从物理层面进行隔离,让其他人不能使用其他模块的东西。
pom的变更应该提起cr人员的注意,切实做好每一个pom变更,避免在代码中引入坏味道。
引入之后通过规约来限制是很不合理的,根据墨菲定律,只要存在,就一定会被人使用到。
非核心模块
client模块:
如果系统有对外提供的能力,比如rpc接口,mq实体定义等。
这些内容是切面与系统存在的,需要提供给外部引用,应该单独出来,避免把自己的核心内容给外部使用。
优势:
- 避免由于外部使用不当,导致自己内部的实体变更,让交互不稳定。
- 避免由于提供依赖太大,导致对方系统的负担
- 避免核心能力让对方引用,增加安全风险
遵守规则:
- client包中,不应有任何三方依赖,只是一个简单接口及实体的定义
- 不应有内部使用的包,只需要提供外部所需的即可,遵守最小可用原则
- 统一出参封装,所有对外提供的接口应统一封装,方便框架层面做统一处理。
common模块
对应本应用而言,在不同模块中都有使用到的工具,分别定义是不合适的,通过common包来抽象出共有能力,来降低代码重复率。
ext模块
如果业务的多样性非常复杂,对每一个特性的处理都需要大量的业务逻辑,那么ext模块单独抽出就很有必要。多样性处理的太多,和核心业务掺杂在一块,随着业务的发展,就会产生特性分支和主分支分不清的情况,混用,职责不清晰,能力不单一。即使规约的再好,根据墨菲定律,这种问题一定会发生。
另外一些高阶的玩法,ext模块外置,核心能力很稳定,拓展能力变动较大时,ext模块会成为热插拔组件,通过快速迭代更新来满足业务,做到完全的系统热插拔,不影响当前业务,新的业务快速上线。
也为了避免不同特性分支相互影响,通过这种做到完全隔离。
sop模块
核心业务稳定,且领域模型较为完善,业务进入后期阶段,新的业务接入就不再依托于编码,而且通过流程引擎来做编排,让新的业务进入。
同一个业务能力,有多种处理,且都为核心能力,此时就应该把这个作为一个sop,把这些提出来一个sop模块单独处理,原本核心的领域层,做流程编排及其他前置业务处理。拓展点再次升级为某个sop的拓展能力。
一般情况下,sop是ext的发展产物,某个ext的特性分支业务发展很好,逐渐成长为核心业务,趋于稳定,此时该特性分支就会成为核心能力分支。
最佳实践讲解
本节主要来解析每一个模块中,应该放些什么,每一层的依赖如何处理等。
分层模块
适配器模块
本层定位是系统入口,所有的业务起点,都应该在这里。
比如:controller接口、rpc接口实现、mq消费者实现等。
本层依赖:
内部依赖:核心领域模块,client模快、common模块。
三方依赖:核心框架、rpc和mq等必要框架、基础组件。
禁止依赖:业务模块、基建模块
特殊说明:
本层的模型定义在本层内、或者取自client。
本层调用领域层之前,需要做好模型转换,将模型转换为领域层里面定义的模型,然后再定义,这层的转换器应该写在这层。
业务模块
本层定位为核心业务逻辑处理,所有的业务处理都应在这里。
比如:业务流程判断走向、业务逻辑判断、根据不同的数据做不同的处理、调用数据库接口、调用mq接口、和外部交互的逻辑等。
本层依赖:核心领域模块、common模块。
三方依赖:核心框架
禁止依赖:适配器模块、基建模块、client模块、任何非必要三方依赖
特殊说明:
本层不需要做任何类型转换,进来就是自己所需要的模型。
本层不允许引入其他模块的模型,这层的模型都应该非常稳定,不能有三方注解(比如rpc注解、fastjson注解、mybatis注解、mq注解等)
基建模块
本层定位为防腐基础设施,所有和外部的交互都应该在这里,这里应该为单条线的末端。
比如:从数据库中获取数据的最终实现,从缓存中获取数据的最终实现,发送mq的实际实现,调用rpc接口的最终实现等。
本层依赖:核心领域模块、common模块。
三方依赖:核心框架、外部sdk、外部client模块、任何三方所需要的依赖。
禁止依赖:适配器模块、client模块、业务模块
特殊说明:
本层的模型可以用到领域模型或者三方交互模型。进来都是领域模型,根据需求转换为对应的三方接口模型。
处理完如果有数据透出,必须要使用类型转换器,不可把本层模型透出,也不能把三方接口模型定义到领域模块中。
领域模块
本层定位是不同模块的轴承,所有的核心交互接口定义及数据模型定义都在这里,这里联通各个模块。
比如:核心业务处理的接口(DomainService),基础建设中的能力透出接口(InnerService/Gateway)。
本层依赖:common模块
三方依赖:无
禁止依赖:几乎不允许依赖任何内容
client模块
本层定位是本系统对外提供的能力点透出。
比如:对外提供的rpc接口,对外提供的mq模型等。
本层依赖:无
三方依赖:无
禁止依赖:几乎不允许依赖任何内容
common模块
本层是不同模块之间通用的工具内容。
比如:字符串处理工具,各种util类,各种通用处理能力。
本层依赖:无
三方依赖:非常稳定的三方工具包(原则上需要自己重写一套),几乎不能引用其他三方依赖。
start模块:
应用的启动模块,定义启动器及启动所必须得一些内容。
比如:spring boot启动器,启动配置,项目中的一些配置。
本层依赖:所有的模块
三方依赖:基础框架依赖
ddd框架实践
一套最基础的增删改查实践
╔ adapter
║ ╟ java
║ ╟ ╟ RpcXXXServiceImpl.java
║ ╟ ╟ XXXController.java
║ ╟ ╟ XXXConsumer.java
║ ╟ resource
║ ╚ pom.xml
╟ biz
║ ╟ java
║ ╟ ╟ XXXDomainServiceImpl.java
║ ╚ pom.xml
╟ infra
║ ╟ java
║ ╟ ╟ XXXConverter.java
║ ╟ ╟ XXXClient.java
║ ╟ ╟ XXXInnerServiceImpl.java
║ ╟ ╟ XXXDO.java
║ ╟ resource
║ ╟ ╟ mapper
║ ╟ ╟ ╟ xxxMapper.xml
║ ╚ pom.xml
╟ domain
║ ╟ java
║ ╟ ╟ XXXDomainService.java
║ ╟ ╟ XXX.java
║ ╚ pom.xml
╟ client
║ ╟ java
║ ╟ ╟ RpcXXXService.java
║ ╟ ╟ XXXDTO.java
║ ╚ pom.xml
╟ common
║ ╟ java
║ ╟ ╟ XXXUtil.java
║ ╚ pom.xml
╟ start
║ ╟ java
║ ╟ ╟ Application.java
║ ╟ ╟ config
║ ╟ ╟ ╟ Config.java
║ ╟ resource
║ ╟ ╟ application.properties
║ ╟ ╟ META-INF
║ ╚ pom.xml
╚ pom.xml
实际demo
TODO...