目前我们的服务是使用多层架构实现的,将整个服务分为三个部分:
- API 业务
- 持久性
然而,这在我们的系统中引入了很多冗余。在这个行业里有一句谚语叫"DRY"(不要重复自己)。冗余增加了开发时间,使系统更加脆弱,并使我们的代码与"复制"方法混淆。
为了更好地说明,假设我们有一个Person
服务。这将需要以下内容:
-
Person
实体- JPA注释类用于ORM - 存储库服务请求——包含Person域对象要持久化的字段值,并带有其他持久化选项
- 存储库服务响应——包含Person实体的字段值
-
Person
-类与业务逻辑,域字段和计算字段 - 域服务请求—包含
Person
资源的字段值和附加业务选项 - 域服务响应——包含
Person
业务对象的字段值,不包括那些不应该对API用户可见的字段值 -
Person
资源类,表示API用户可以看到的内容
当考虑嵌套对象时,情况会变得更糟。
当前的设计促进了关注点(业务、API、持久性)之间的区别,但是:
- 目前,差异非常小。这导致我们有非常相似的类,只有微小的差异
- 服务返回带有字段的服务响应对象,而不仅仅是对象本身阻碍了其他服务依赖其他服务
问题:
- 这个设计值得吗?
- 我们有什么替代方案?
- 我们可以改变什么来改善我们的状况?
我知道你是从哪里来的。我的简短建议是:阅读Eric Evans的《领域驱动设计——解决软件核心的复杂性》。
DDD的中心部分是包含大多数业务逻辑的域pojo。构建模块或多或少是你已经提到过的。
有三种服务:
- 负责编排、事务管理和授权的应用程序服务
- 域服务包含不适合其他域构建块的业务逻辑:实体、策略、工厂、值对象。如果不能使用其他域机制,只创建。
- 基础设施服务。最常见的是负责根聚合持久化的存储库(这个角色扮演一些实体),并且仅它们。这与为任何实体创建的dao形成对比。其他基础设施服务可能是应用程序正在使用的Web服务的客户端。
由于域中的逻辑是最容易重用的,所以这种不同类型服务的丰富性以及将逻辑尽可能向下推的想法,为开发人员提供了构建全面且可维护的复杂软件所需的工具。注意,对于简单的CRUD应用程序来说,DDD可能太重了。
系统的入口点要么是Web服务端点,要么是控制器(对于UI在后端生成的Web应用程序,比如jsp或jsf的情况)。
对于中等规模的系统,我喜欢使用受CQRS启发的方法,也就是说,为了避免在加载多个根聚合用于显示目的(读端)时不可避免的缓慢,我编写了专门的查询服务,直接从DB返回dto,在JPA使用select new
机制的情况下。