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

2023-11-02

一、背景介绍

我们团队一直在持续推进业务系统的体系化治理工作,在这个过程中我们沉淀了自己的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模块编码规范:

  • Api模块是专门用于定义对外接口的模块,所以这个模块中只包含接口定义,出入参定义,尽量不依赖其他包。
  • Api中的接口定义类以xxxxResource(或者xxxxService)结尾。这条规范完全是为了和老的应用保持一致。
  • Api接口的入参尽量不要使用Java中的原子类型(Primitive Type), 需要将入参定义为单独的类。 最好是继承现有的BaseRequest类。
  • Api接口的出参统一使用泛型类对真实的返回类型进行包装。
  • 出入参类都以DTO结尾。
  • 出入参中尽量不适用枚举值类型的成员变量。

2、Adapter/Controller模块编码规范:

  • 这一层中需要将出入参的DTO和业务层的VO/DO对象进行转换。
  • 这一层不要包含任何的业务逻辑,只包含参数转换和业务无关的校验逻辑。
  • 接口返回值缓存类的逻辑,可以放在这个模块中实现,因为这个动作不包含业务逻辑。

3、App模块编码规范:

  • 这个模块中的类统一以Case结尾。
  • 这一层主要是对底层业务逻辑进行编排。可以直接调用Domain层的port定义。跨域的服务调用也可以放在这个模块中。
  • 这一层可以直接调用Domain模块中定义的Repository服务。
  • 事务处理:如果是跨多个聚合的业务逻辑需要放在一个事务中,需要在这一层开启和提交事务。

4、Domain层编码规范:

  • DomainService命名统一以Service为后缀。
  • Entity实体类的命名不用后缀。 值对象类的定义统一以VO结尾。
  • DomainService逻辑中可以调用Repository和Port中定义的接口。
  • DomainService可以操作多个聚合,实体和值对象。
  • Entity实体类可以有构造函数,builder,getters。 不要直接放开所有属性的setters,防止业务代码随意修改实体的属性。
  • 编写业务逻辑需要遵守原则:优先将业务逻辑放在Entity和VO中,然后才是放在聚合中,最后才放在DomainService中。
  • 依赖反转原则:Domain层依赖的外部接口都要定义在Domain模块的port包中。Domain层只面向接口编程,不依赖接口实现类。

5、Adapter/Repository和Rpc模块编码规范:

  • Repository实现类中需要将接口入参中的DO对象转换为PO对象后再调用数据库存储。
  • Repository和聚合的关系是一对一的关系。一个Repository有唯一的对应的聚合。
  • 如果Repository中需要开始事务可以在Repository实现类中开启事务。
  • Rpc层最好是对外部接口的出参和入参定义一个防腐层对象,命名统一以DTO结尾。

五、常见问题及解决办法

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

作者:京东科技 史纪军

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【实践篇】DDD脚手架及编码规范 的相关文章

  • 编码规范C/C++

    一 命名 1 类型名 使用首字母大写的驼峰命名法 如StudentGrade MyClass 命名由单词组合而成 其中每个单词以大写字母开头 不包含下划线 宏 常量 enum 结构中的成员命名全部大写 2 变量 语义上应该是一个名词或名词短
  • 架构师日记-深入理解软件设计模式

    作者 京东零售 刘慧卿 一 设计模式与编程语言 1 1 什么是设计模式 设计模式 Design pattern 由软件开发人员在软件开发中面临常见问题的解决方案 是经过长时间的试验积累总结出来的 它使设计更加灵活和优雅 复用性更好 从实用的
  • 精准测试之过程与实践

    作者 京东工业 宛煜昕 一 怎样的技术 百度百科 精准测试是一套计算机测试辅助分析系统 精准测试的核心组件包含的软件测试示波器 用例和代码的双向追溯 智能回归测试用例选取 覆盖率分析 缺陷定位 测试用例聚类分析 测试用例自动生成系统 这些功
  • 买彩票能中大奖?用Java盘点常见的概率悖论

    引言 双色球头奖概率与被雷劈中的概率哪个高 3人轮流射击 枪法最差的反而更容易活下来 让我们用Java来探索ta们 悖论1 著名的三门问题 规则描述 你正在参加一个游戏节目 你被要求在三扇门中选择一扇 其中一扇后面有一辆车 其余两扇后面则是
  • Velocity不用愁!Velocity系统的前端工程化之路

    Velocity是一个基于Java的Web页面模版引擎 十多年前 Velocity将Java代码从Web页面中分离出来 使得开发者能够并行网页开发和Java开发 随着十年前后端分离的浪潮涌动 回首再面对这些基于Velocity的旧系统 无论
  • 用jemalloc代替glibc默认ptmalloc进一步提升服务器性能和负载

    启动redis时 无意中看到redis的启动信息有一个jemalloc的版本信息 处于好奇了解了一下 它是一个进一步提升服务器负载和性能的神器 一 Ptmalloc Linux 系统在装载 elf 格式的程序文件时 会调用 loader 把
  • 设计模式SOLID

    一 单一职责原则 一个类或者一个模块只完成一个功能 class UserInfo userId username email telephone 二 开闭原则 对扩展开放 对修改关闭 class Alert void check error
  • Nacos使用域名做为服务地址遇到的问题及解决方案

    一 发现问题 应用启动时 增加Nacos服务端的配置信息 应用使用IP加端口连接Nacos服务器时 运行一切正常 启动参数增加以下Nacos参数 Dspring cloud nacos discovery namespace DEV Dsp
  • 【实践篇】推荐算法PaaS化探索与实践

    作者 京东零售 崔宁 1 背景说明 目前 推荐算法部支持了主站 企业业务 全渠道等20 业务线的900 推荐场景 通过梳理大促运营 各垂直业务线推荐场景的共性需求 对现有推荐算法能力进行沉淀和积累 并通过算法PaaS化打造通用化的推荐能力
  • 量化交易框架开发实践(二)

    我们通过分析代码可以看出 PyAlgoTrade分为六个组件 Strategies Feeds Brokers DataSeries Technicals Optimizer 从业务流上看也是比较容易理解的 Feed 数据源 gt Data
  • 思考:如何保证服务稳定性?

    最近一直在忙618大促的全链路压测 稳定性保障相关工作 结果618还未开始 生产环境就出了几次生产故障 且大多都是和系统稳定性 性能相关的bad case 生产全链路压测终于告一段落 抽出时间将个人收集的稳定性相关资料整理review了一遍
  • 【Spring Boot 集成应用】 OAUTH2统一认证单点登录中的各种模式说明

    1 OAUTH2统一认证介绍 OAuth 2 0 是一个行业的标准授权协议 OAuth 2 0 专注于简化客户端开发人员 同时为 Web 应用程序 桌面应用程序 手机等各种设备接入提供特定的授权流程 2 传统登陆认证 传统登陆方式是在每个服
  • Weblogic 12c 集群部署和session复制

    在上一篇Weblogic12c集群搭建的基础上 这一篇介绍Weblogic12c集群应用的部署和session复制 1 启动服务 首先在weblogic12c控制台 启动受托管服务server1 server2 server3 2 将要部署
  • DDD-笔记

    先说下传统系统设计 大部分从数据库开始 自底向上的设计 这种设计会使系统的设计受到数据库的影响 会有比较大的局限性 比如说 数据库仅有数据 没有行为 而对现实世界的描述则会更加抽象 更加远离业务 开发团队通过与产品或客户的沟通 直接设计表模
  • 量化交易框架开发实践(一)

    量化交易平台指支持通过对数据进行多维度的定量分析 结合发现的特征定制策略 并能够基于历史数据对策略进行回测 最后支持实盘买卖的交易平台 从业务流上看 量化交易可以分解成 行情获取 gt 数据清洗 gt 指标计算 gt 策略开发 gt 策略回
  • 领域驱动设计:DDD分层架构

    文章目录 DDD 分层架构 DDD 分层架构最重要的原则 DDD 分层架构推动架构演进 三层架构如何演进到 DDD 分层架构 微服务架构模型有好多种 例如整洁架构 CQRS 和六边形架构等等 每种架构模式虽然提出的时代和背景不同 但其核心理
  • 从架构师的角度看服务器端架构点滴

    任何服务器端的架构设计 都是性能 一致性和成本三者的权衡 从我在目前的大规模互联网视频公司的负责APP服务器端的角度来讲 我主要关注以下几个点 业务 可靠性 性能 可维护性 一 业务 框架上保证业务的快速迭代 在性能要求不高的情况下 同步架
  • kubeadm集群化部署多master节点(生产环境适用)

    一 背景介绍 k8s通过master集中式管理worknode的容器编排系统 而在生产环境为了维护高可用性 master的地位起到举无轻重的作用 一旦master节点失守 则会导致整个集群服务不可用 因此配置多master集群在生产环境非常
  • Redis——Redis简介

    Redis是目前最流行的键值对 key value 数据库 以出色的性能著称 官方提供的数据是可以支持100000以上的 QPS Redis具有高性能的主要原因如下 Redis是基于内存的存储数据库 绝大部分的命令处理只是纯粹的内存操作 内
  • Redis HyperLogLog:数据统计的轻量级解决方案

    引言 在现代数据驱动的应用中 Redis 以其出色的性能和灵活性成为了不可或缺的工具 特别是在统计大量数据时 传统的计数方法往往既耗时又占用大量存储空间 这次 阿七将介绍一种名为 HyperLogLog 的算法 它在 Redis 中的实现让

随机推荐