gpt4 book ai didi

java - DDD 项目的 Maven 模块布局

转载 作者:搜寻专家 更新时间:2023-10-31 19:35:46 24 4
gpt4 key购买 nike

在做 DDD 项目时,你如何布局你的 Maven 模块?您是将所有层(表示、应用程序、领域、基础设施)都放在一个模块中,还是创建一个多模块布局,每个层都有一个单独的模块?或者完全是别的什么?

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

最佳答案

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

Caveat: the sample app is packaged as single app to make it easy to consume as a learning tool. But here are some reccomendations using it as a example and pretending it's real. I will make some assumptions about it in a vacuum for illustrative purposes, but a responsible practitioner of DDD would grab a Domain Expert and interview the development team to validate any and all assumptions about the domain, context boundaries and the relationship between those contexts. You can't do DDD alone.



正确建模

第一步是专注于正确建模和定义上下文边界。我不会担心基础设施层,因为我会担心各种 上下文 以及他们在领域内的模型。示例应用程序中的关键区别在于这些不同上下文之间的区别,此应用程序中有三个上下文
  • 预订
  • 路由
  • 第三方供应商/港口/船舶等

  • 如果您注意到它们被根 java 包清楚地分开
  • se.citrus.dddsample
  • com.pathfinder
  • com.aggregator

  • 这些层主要是为了促进这些上下文之间的通信,并将基础设施问题与领域工作分开,使测试更容易,领域职责更明确。基础设施很重要,但示例应用程序在这里使用 XML,在那里使用 JMS,在那里使用 Hibernate 这一事实是正在进行的域建模的次要问题。

    示例应用程序使这种分离非常清晰,很容易看出聚合根在哪里:
  • cargo
  • 处理事件
  • 地点
  • 航程

  • 通过 Aggregate Roots 分解 java 包是一种可靠的做法。航程在 Cargo 聚合之外没有任何意义,时间表在 Voyage 聚合之外没有任何意义,HandingHistory 在 HandingEvent 聚合之外没有任何意义。在没有基础设施的情况下保持域模型隔离和可测试是一个很好的做法。但是您可能不会将这种解耦扩展到模块级别。将所有域对象放在一个 jar 中,将所有基础结构放在另一个 jar 中,这不是一条规则。开发和版本负担可能会变得痛苦。

    识别有界上下文

    关键是各种上下文的模型如何分离/不共享 .在预订上下文中,路线是具有一组航段的行程。在路由域中,它是真正的计算机科学意义上的图,因此该域可以使用从大学算法课中学习得很好的图遍历算法来解决路由问题。

    Booking 和 Routing 这两个上下文处于密切的合作关系中,它们都在 Edges 和 Nodes 以及 Itineraries 和 Legs 两个模型之间维护一个共享接口(interface)。这种转换在模型之间维护,在 ExternalRoutingService 中管理,TransitPath 变成了 Itinerary。显然,这是一个非常关键的集成点,应该在测试中很好地涵盖并通过持续集成进行管理

    另一个上下文是 3rd 方集成,用于向应用程序报告有关 cargo 状态的 HandingEvent。这是通过一种称为 Published Language 的模式实现的。简而言之,我们并不关心 3rd 方的 cargo 模型是什么样的,只要他们按照我们的 Publish XML 规范 HandlingReport 向我们报告处理事件即可。

    第 3 方上下文和预订域之间的关系称为 Conformist,他们按照我们定义的规范提交数据,我们不会更改我们的模型以使其更容易。他们的负担是要顺从我们。也就是说,这是我对情况的猜测,可能有一个非常重要的供应商,他们实际上定义了 XML 模型,而不是我们。只有对虚构团队的采访才能真正体现这一点。

    因此,在汇总组中,所有与聚合密切相关的类(也许是同一个包)。明确定义上下文边界并确保有明确的集成点,定义上下文伙伴关系、共享内核、发布语言、开放主机服务、符合者等的关系。

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

    在有界上下文中寻找模块

    获取您的上下文边界权限。将您的聚合正确定义为漂亮的垂直行业。减少耦合以清除定义明确的接口(interface)。

    在您的上下文中查找模块。它们是分离模块的最自然候选者,分离可能有助于更严格地执行和记录上下文边界。然而,就像很多软件设计一样,它不是一个硬性规定,实际上取决于具体情况。我可以设想并且已经看到/编写了具有不同写入模型和读取模型(认为是标准化和非标准化的报告)和每个上下文的应用程序,对于实际问题,这些应用程序可能仍被打包在单个模块中。

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

    关于java - DDD 项目的 Maven 模块布局,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5377234/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com