DDD项目的Maven模块布局

mar*_*usk 6 java domain-driven-design maven

在进行DDD项目时如何布局Maven模块?您是否将所有图层(演示文稿,应用程序,域,基础结构)放在一个模块中,或者您是否为每个图层创建了一个单独模块的多模块布局?或完全不同的东西?

我注意到由Domain Language和Citerus公司开发的DDD示例应用程序使用单个Maven模块,每个层作为该模块内的单独Java包.这是既定的最佳实践,还是应该考虑更精细的模块布局?

Kyr*_*kos 10

通常,模块分离和封装是部署和开发实用性的问题.还有谁会要求代码?如果我想更改功能Y,是否在包X中?

警告:示例应用程序打包为单个应用程序,以便于作为学习工具使用.但是这里有一些推荐使用它作为一个例子并假装它是 真实的. 为了说明的目的,我会在真空中做出一些假设,但DDD的负责任的实践者会抓住一个域专家并采访开发团队来验证关于域,上下文边界和这些上下文之间关系的任何和所有假设. 你不能单独做DDD.

获得正确的建模

第一步是专注于建立正确的建模和定义的上下文边界.我不担心基础设施层,因为我担心域内的各种上下文及其模型.示例应用程序中的关键区别是这些不同上下文之间的区别,此应用程序中有三种上下文

  • 预订
  • 路由
  • 第三方供应商/港口/船舶等

如果你注意到那些被root java包清楚地分开了

  • se.citerus.dddsample
  • com.pathfinder
  • com.aggregator

层次主要是为了促进这些环境之间的通信,并将基础设施问题与域名工作分开,使测试更容易,域名责任更加简单.基础设施很重要,但是样本应用程序在这里使用XML而JMS存在并且在那里进行休眠的事实是域建模的次要问题.

示例应用程序使这种分离非常清晰,很容易看到聚合根的位置:

  • 货物
  • HandlingEvent
  • 地点
  • 航程

通过Aggegrate Roots打破java包是很有实践的.一条腿在货物集合之外没有任何意义,计划意味着在Voyage集合之外没有任何东西,一个HandlingHistory在HandingEvent集合之外没有任何意义.保持域模型与基础架构隔离和可测试是一种很好的做法.但是你可能不会将这种解耦扩展到模块级别.将所有域对象放在一个jar中并将所有基础结构放在另一个jar中并不是一个规则.开发和版本负担可能会变得很痛苦.

识别有界上下文

关键是各种上下文的模型是如何分开/不共享的.在预订环境中,路线是具有一组腿的行程.在路由域中,它是真正的计算机科学意义上的图形,因此域可以使用经过充分研究的图形遍历算法解决路由问题.

两种情况下,预订和路由都处于密切的合作伙伴关系中,它们都在两个边缘和节点以及行程和腿之间保持共享接口.在TransRPath成为行程的ExternalRoutingService中管理模型之间维护此转换.显然,这是一个非常关键的集成点,应该在测试中得到很好的覆盖,并通过持续集成进行管理

另一个上下文是第三方集成,用于向应用程序报告关于货物状态的HandingEvents.这是通过名为Published Language的模式实现的.简而言之,我们不关心第三方的货物模型是什么样的,只要他们按照我们的Publish XML规范HandlingReport向我们报告处理事件.

第三方上下文与预订域之间的关系称为Conformist,它们按照我们定义的规范提交数据,我们不会改变我们的模型以使它们更容易.他们的责任在于他们与我们保持一致.也就是说,这是我对这种情况的猜测,可能是那里有一个非常重要的供应商,他们实际上是定义了XML模型而不是我们.只有对虚构团队的采访才能真正体现出这一点.

所以在汇总组中所有类都与Aggregate密切相关(也许是相同的包).明确定义上下文边界并确保有明确的集成点,定义上下文伙伴关系,共享内核,已发布语言,开放主机服务,一致性等的关系.

基于该示例,我们可以将各种上下文打包在单独的maven模块中,用于货物预订,路径路径查找和处理事件聚合.如果考虑到开发方法和团队组织的实际情况,这是有道理的,并且只有在这种情况下才是这样.

在有界上下文中查找模块

获取您的上下文边界权限.将您的聚合正确定义为漂亮的垂直.减少耦合以清除定义良好的接口.

在您的上下文中查找模块.它们是单独模块的最自然候选者,分离可能有助于更严格地执行和记录上下文边界.然而,像软件设计这么多,它并不是一个硬性规则,而是真正取决于具体案例.我可以设想并编写/编写具有不同写入模型和读取模型的应用程序(对于报告来说,认为规范化和非规范化)以及每个应用程序的上下文,对于实际问题,可能仍然打包在单个模块中.

另外一点要警惕在上下文之间共享聚合根,这是DDD共享内核模式,应该非常谨慎地使用,因为它可以快速地进入一个不能很好地满足任何上下文需求的大型混乱域模型.请注意,示例应用程序不在RoutingService和BookingService之间共享模型.将所有域的聚合根植入单个模块可能会无意中鼓励这种做法.