it编程 > 软件设计 > 领域驱动设计

【实践篇】DDD脚手架及编码规范

122人参与 2024-05-12 领域驱动设计

一、背景介绍

我们团队一直在持续推进业务系统的体系化治理工作,在这个过程中我们沉淀了自己的ddd脚手架项目。脚手架项目是体系化治理过程中比较重要的一环,它的作用有两点:

(1)可以对新建的项目进行统一的规范;

(2)对于指导老项目进行ddd的改造提供指导。

本文主要是梳理和总结了ddd脚手架使用中的编码规范以及遇到的问题。

二、脚手架的理论基础

ddd相关的应用架构有很多种,比如四层架构,洋葱架构,六边形架构,整洁架构等。这些应用架构都有各自的特点和不同。但是他们的总体思想都是相似的,主要是通过分层来实现功能和关注点的隔离。达到的目标是领域层不依赖任何其他外部实现,这样就能保证核心业务逻辑的干净和稳定。

左图是整洁架构的示意图,左图为分层,右图表示各个分层的变化频率和抽象层级。整洁架构主要分为4层:

(1)frameworks&drivers层:这一层表示系统依赖的外部系统,比如数据库、缓存、前端页面等。这一层是变化频率最高的,也是需要和我们的核心业务逻辑做隔离的。

(2)interface adapters层:这一层是一个适配层,主要负责外部系统和内部业务系统的适配,这一层的主要作用就是外部系统和内部系统的适配和协议转换。

(3)application business rules: 应用业务规则层,可以理解为用例层,这一层表示整个应用可以提供哪些用例级别的功能和服务。这一层也是对第4层中的核心业务规则的编排层。

(4)enterprise business rules: 这一层就是最为核心的业务逻辑层,这一层不包含任何和技术相关的内容,只包含业务逻辑。

三、脚手架介绍及使用

使用命令如下:

mvn archetype:generate     
-darchetypegroupid=com.jd.jr.cf     
-darchetypeartifactid=ddd-archetype     
-darchetypecatalog=local     
-darchetypeversion=0.0.1-snapshot     
-dinteractivemode=false     
-dgroupid=com.jd.demo.test        //从这一行开始需要根据项目名称修改 
-dartifactid=demo-test     
-dversion=1.0.0     
-dpackage=com.jd.demo.test     
-dappname=demo-test  -s d:/git/settings.xml      // 本地 git配置文件

生成完的项目结构如下:

|--- adapter                     -- 适配器层 应用与外部应用交互适配
|      |--- controller           -- 控制器层,api中的接口的实现
|      |       |--- assembler    -- 装配器,dto和领域模型的转换
|      |       |--- impl         -- 协议层中接口的实现
|      |--- repository           -- 仓储层
|      |       |--- assembler    -- 装配器,po和领域模型的转换
|      |       |--- impl         -- 领域层中仓储接口的实现
|      |--- rpc                  -- rpc层,domain层中port中依赖的外部的接口实现,调用远程rpc接口
|      |--- task                 -- 任务,主要是调度任务的适配器
|--- api                         -- 应用协议层 应用对外暴露的api接口
|--- boot                        -- 启动层 应用框架、驱动等
|      |--- aop                  -- 切面
|      |--- config               -- 配置
|      |--- application          -- 启动类
|--- app                         -- 应用层
|      |--- cases                -- 应用服务
|--- domain                      -- 领域层
|      |--- model                -- 领域对象
|      |       |--- aggregate    -- 聚合
|      |       |--- entities     -- 实休
|      |       |--- vo           -- 值对象
|      |--- service              -- 域服务
|      |--- factory              -- 工厂,针对一些复杂的object可以通过工厂来构建
|      |--- port                 -- 端口,即接口
|      |--- event                -- 领域事件
|      |--- exception            -- 异常封装
|      |--- ability              -- 领域能力
|      |--- extension            -- 扩展点
|      |       |--- impl        -- 扩展点实现
|--- query                       -- 查询层,封装读服务
|      |--- model                -- 查询模型
|      |--- service              -- 查询服务

整体的分层架构图如下:

四、脚手架编码规范

1、api模块编码规范:

2、adapter/controller模块编码规范:

3、app模块编码规范:

4、domain层编码规范:

5、adapter/repository和rpc模块编码规范:

五、常见问题及解决办法

**q1、**api模块对外提供的jar包中是否要引用其他应用的jar包?

a1: 有一些场景,a应用的api接口的入参需要引用其他应用的包中的类。比如a应用发出了一个事件,b应用提供了一个接口来处理这个事件,那b应用是否要引用a应用的包中的事件定义类呢? 理想情况,最好是b应用定义一个自己的类,这样b应用就不会依赖a应用的包。

**q2、**api包中是否能包含枚举类的定义?

a2:最好不要在api包中对外暴露内部的枚举值定义。因为枚举值是需要在domain模块中定义和使用的,不适合通过jar包的形式暴露给外部。 如果确实有需求要暴露给外部应用(比如为了让接口调用方方便的知道入参中的值有哪些),可以将枚举类的定义放在同一的common包中。这样domain模块和对外提供的jar包都可以引用common包。

**q3、**数据存储是否要使用统一版本号?

a3: 对于新应用,最好是使用统一的版本号,这样在更新数据库的时候就可以统一使用版本号当做乐观锁。但是对于遗留系统而言,启用版本号的成本比较高,因为需要梳理所有对实体进行变更的点,要求所有的点都统一使用版本号。所以要根据情况来确定是否使用。

q4、对于一些偏流程性的业务,频繁的调用外部rpc接口。如果每个rpc接口都添加一个防腐层对象的话,会降低开发效率。是否可以不定义防腐层对象?

a4:最好是定义防腐层对象,短期可能降低一些开发效率,但是从长期和代码标准话的角度看,还是值得的。

作者:京东科技 史纪军

来源:京东云开发者社区 转载请注明来源

(0)
打赏 微信扫一扫 微信扫一扫

您想发表意见!!点此发布评论

推荐阅读

快速理解DDD领域驱动设计架构思想-基础篇

05-12

从混乱到优雅:基于DDD的六边形架构的代码翻新指南

05-12

DDD学习与感悟——向屎山冲锋

05-12

领域驱动设计之银行转账:Wow框架实战

05-16

【python量化交易】qteasy使用教程04 -使用内置交易策略,搭积木式创建复杂交易策略

06-01

猜你喜欢

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论