
我们团队一直在持续推进业务系统的体系化治理工作,在这个过程中我们沉淀了自己的 DDD 脚手架项目。脚手架项目是体系化治理过程中比较重要的一环,它的作用有两点:
(1)可以对新建的项目进行统一的规范;
(2)对于指导老项目进行 DDD 的改造提供指导。
本文主要是梳理和总结了 DDD 脚手架使用中的编码规范以及遇到的问题。
DDD 相关的应用架构有很多种,比如四层架构,洋葱架构,六边形架构,整洁架构等。这些应用架构都有各自的特点和不同。但是他们的总体思想都是相似的,主要是通过分层来实现功能和关注点的隔离。达到的目标是领域层不依赖任何其他外部实现,这样就能保证核心业务逻辑的干净和稳定。
左图是整洁架构的示意图,左图为分层,右图表示各个分层的变化频率和抽象层级。整洁架构主要分为 4 层:
(1)Frameworks&Drivers 层:这一层表示系统依赖的外部系统,比如数据库、缓存、前端页面等。这一层是变化频率最高的,也是需要和我们的核心业务逻辑做隔离的。
(2)Interface Adapters 层:这一层是一个适配层,主要负责外部系统和内部业务系统的适配,这一层的主要作用就是外部系统和内部系统的适配和协议转换。
(3)Application Business Rules: 应用业务规则层,可以理解为用例层,这一层表示整个应用可以提供哪些用例级别的功能和服务。这一层也是对第 4 层中的核心业务规则的编排层。
(4)Enterprise Business Rules: 这一层就是最为核心的业务逻辑层,这一层不包含任何和技术相关的内容,只包含业务逻辑。
使用命令如下:
生成完的项目结构如下:
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:最好是定义防腐层对象,短期可能降低一些开发效率,但是从长期和代码标准话的角度看,还是值得的。
