从混乱到高雅:根据DDD的六边形架构的代码创新攻略
前语
趁着双十一备战封板,总算又有一些时刻可以整理一下最近的心得。
最近这半年跟搭档评论比较多的是分层架构,然后就会遇到两个触及魂灵的问题,一个是怎么做好分层架构,二是DDD在架构层面该怎么落地。
为了说好分层,咱们需求了解架构的含义。
杰出的架构是为了确保一下两点:
- 办理运用杂乱度,下降体系熵值;
- 从为所欲为的混乱状况,走向有条不紊的有序状况。
比方,你去图书馆借阅书本,关于纷乱凌乱的各类书本,假如不能很好的办理和分类,必然会导致图书馆办理混乱,功率低下,使得图书馆不能正常运维。而分层架构的含义也在于此,当咱们面临杂乱的事务需求时,需求更好的规划咱们的包结构和依靠规约,可以更好的办理咱们的服务,进步服务的可维护性,可扩展性,做到咱们的架构以事务为中心,解耦外部依靠,别离事务杂乱度和技能杂乱度。
传统分层架构有MVC,而这些年盛行的六边形架构,也是伴随着DDD的鼓起而逐渐被咱们所承受。假如说DDD和六边形架构的联系,他俩归于不同层级的概念,DDD更倾向办法论,重视范畴建模和事务逻辑的规划,着重将事务需求和范畴常识转化为软件规划;而六边形架构更重视体系的全体架构和模块化规划,着重别离内部和外部体系的交互。他们俩的结合是一种非常好的实践经验, DDD中的范畴模型是中心,其他层(如运用层、基础设施层)依靠于范畴模型;而六边形架构正好为DDD供给了一种非常好的分层落地。
浅聊DDD落地
关于DDD,并没有一种所谓的结构或许脚手架可以对应,其根本原因在于,DDD其实是一种办法论,而非所谓的结构,它给咱们供给了一种应对事务杂乱度时的办法:
- 经过架构规划来别离事务杂乱度和技能杂乱度;
- 经过限界上下文去做到分而治之,将大体系拆解为若干个高内聚低耦合的子域;
- 经过面向目标的规划办法,将事务子域的常识进行笼统。
总结一下:
- DDD的战略建模重视子域的区分和限界上下文的界说。对应到落地便是包的拆解, 以及包之间的依靠和组合联系。
- 而DDD的战术建模首要重视的是结构块和柔性规划。结构块便是咱们常说的,类,目标,组合。而柔性规划便是咱们面向目标的规划准则,得到一个高内聚低耦合的体系。所以说,DDD的战术建模落地,必定伴随着开发人员对规划办法的深刻了解和运用。
六边形分层架构
1. App层
运用层是DDD中的顶层,担任协谐和安排范畴目标的交互。它接纳来自用户界面或外部体系的恳求,并将其转发给范畴层进行处理。运用层担任界说运用的用例(Use Cases),处理事务鸿沟和协调范畴目标的操作。它不包含事务逻辑,而是将恳求转化为范畴目标的操作。运用层还可以包含获取输入,拼装上下文,参数校验,反常界说,发送事情告诉等。
2. Domain层
首要是封装了中心事务逻辑,并经过范畴服务(Domain Service)和范畴目标(Domain Entity)的办法对App层供给事务实体和事务逻辑核算。范畴是运用的中心,不依靠任何其他层次。一同范畴层会有一个facade层,当范畴服务对外部有调用依靠时,经过界说facade接口完成操控回转。
3. Adapter层
担任与外部体系进行或许服务进行适配和集成,包含通讯,数据缓存,接口适配等功能。
此外着重, RPC consumer调用放在适配器层。适配器层专心于与外部体系的集成和适配,将外部体系的接口和数据格式转化为运用程序可以了解和处理的办法。将RPC调用放在适配器层可以更好地将与外部体系相关的技能细节与运用程序的事务逻辑和范畴目标进行解耦,进步运用程序的可扩展性和可维护性。
关于一切出站适配层,都需求经过完成facade接口完成操控回转。
4. 基础设施层
担任供给支撑运用程序运转的基础设施,包含与详细技能相关的完成。基础设施层一般包含与数据库、音讯行列、缓存、外部服务等进行交互的代码,以及一些通用的东西类和装备,也包含filter等完成。
基础设施层和适配器层之间的联系是:
- 基础设施层供给了与详细技能相关的完成,例如数据库拜访、音讯行列衔接、缓存操作等。适配器层可以运用基础设施层供给的功能来与外部体系进行交互。
- 适配器层经过适配器办法或相似的机制,将外部体系的接口和数据格式转化为运用程序可以了解和处理的办法。适配器层还担任将运用程序的恳求转发给基础设施层进行详细的操作。
- 基础设施层和适配器层一同作业,使得运用程序可以与外部体系进行集成,而且将与外部体系相关的技能细节与运用程序的事务逻辑和范畴目标进行解耦。这样可以完成运用程序的可扩展性、可维护性和可测验性。
关于一些无杂乱逻辑的,也可以直接让上游掉基础设施层,不用必定经过Adapter层。
脚手架的落地实践
以上首要是理论介绍,根据以上的阐明,在实践中,我搭建了两套分层架构的java脚手架。详细来说分为单module版别和多module版别。关于微服务体系来说,假如你的每个服务事务杂乱度不高,主张运用单module版别;假如你是个杂乱事务场景的单体运用,主张选用多module版别。
1. 单module脚手架
--root
--application: 运用层是程序的进口,整合和组合domain供给的才能。
--rpc: JSF provider对外供给的接口完成
--controller: springMVC供给的controller
--listener: MQ音讯监听器
--task: 调度使命
--translate: 将内部的BO映射为外部的VO/Entity
--model: VO目标
--adapter: 适配器层
--rpc: JSF consumer,外部服务
--mq: 音讯行列sender模块
--translate: 将外部数据结构映射为内部的DTO/BO
--domain: 范畴层
--service: 范畴服务可以依照自己状况灵敏规划
--facotry: 工厂
--event/command: 事情驱动
--model: 目标和实体
--translate: 目标实体映射转化
--infrastructure:
--repository: 耐久化层,包含db模型,sql读写等
--cache: Redis缓存读写
--producer: MQ音讯生成,即发送MQ音讯。
--config: 装备信息,例如ducc装备、数据库、缓存装备等
--translate: 将存储层的数据结构PO映射为内部的BO
--utils: 东西调集
--common: 公共层
--exception: 首要分为事务反常和体系反常。体系反常需求研制处理。事务反常需求具有监控才能。
--utils: 东西类
--enums: 枚举类
--common: 大局公共常量池
--worker: 异步服务
--client: JSF SDK
maven私服拉取脚本如下:
单module版别maven私服拉取脚本如下:
mvn archetype:generate \
-DarchetypeGroupId=com.jd.magnus \
-DarchetypeArtifactId=magnus-single-archetype \
-DarchetypeVersion=1.0.0-SNAPSHOT \
-DinteractiveMode=false \
-DarchetypeCatalog=remote \
-Dversion=1.0.0-SNAPSHOT \
-DgroupId=com.jdl.sps \
-DartifactId=bff-single-demo1
2. 多module脚手架
此处有一个主张,在多module版别下,由于是杂乱单体运用,所以主张内部进行拆包处理。每层内也可以根据不同范畴场景也可以进行拆包操作,每个场景下层级结构是相同的。如下图举例,其间app层平分别有两个事务场景,包含产品和订单:
多module版别的maven私服拉取脚本如下:
mvn archetype:generate \
-DarchetypeGroupId=com.jd.magnus \
-DarchetypeArtifactId=magnus-multi-ddd-archetype \
-DarchetypeVersion=1.0.0-SNAPSHOT \
-DinteractiveMode=false \
-DarchetypeCatalog=remote \
-Dversion=1.0.0-SNAPSHOT \
-DgroupId=com.jdl.sps \
-DartifactId=bff-demo1
小结
本结构是结合了DDD思维和六边形架构思维,但脚手架不会约束咱们才能和发挥。
假如你通晓DDD,你可以在domain层选用规范的充血模型和子域拆分办法编写你的代码; 假如你通晓MVC,该结构也可以简化为咱们了解的MVC开发办法。关于model的处理,也可灵敏应对,在不影响全体代码架构的状况下,答应不过度规划及目标多度封装,鼓舞灵敏迭代和定时重构。
但有一个中心思维需求谨记:
咱们尽量确保咱们的代码开发契合开闭准则,可以经过添加类和办法的办法完成新功能迭代,尽量就要防止频频修正某个办法或许某个类,包与包之间要确保高内聚,低耦合。由于DDD思维的中心便是子域的拆分和对规划办法的合理运用。
作者:京东物流 赵勇萍
来历:京东云开发者社区 自猿其说 Tech 转载请注明来历