在模块化单体中,在哪里绘制有界上下文线?

Where to draw the bounded context line, in a modular monolith?

原来是这样,它是一个简单的工厂备件软件。由以下限界上下文组成,所有上下文都位于它们自己的模块程序集中,遵循干净的体系结构。

一切都通过休息暴露出来api。

我的问题是,如何select零件并将它们添加到检测对象中?我是否必须保留所有部分的副本,包括语言等。还是不应该将它们视为单独的上下文? 或者有其他设计?

你有巨石,对吧?如果是,那么您至少有 2 个选项。

您可以遵循纯粹的方法,因此您在另一个域中拥有一个域的所有相关信息的副本。复制是使用其余 api 完成的,因为这是三个域将自己暴露给外部的方式。这个copy什么时候执行也是个问题,用这个办法。 您需要传达每个更改吗?然后你需要一种偶数总线(外部)来通知每一个机会。由于使用旧信息执行的操作,您还需要一种方法来管理不一致。

另一种方法是在基础设施层(您使用干净的架构,因此无论如何都不会污染域)内实现对来自另一个域的信息的管理。在那里,您将使用查询或您在另一个域的基础结构层内的任何其他代码来呈现当前域内的信息。简而言之,您允许在基础设施层与两个或多个域进行交互,以避免实现所有代码,否则您需要使用其余代码 api。在这里你也可以选择直接从持久化中获取信息而不需要副本。

两者皆有可能。对于第一个,如果将来您需要拆分项目,工作已经完成。但是您要付出额外代码的代价。如果你选择第二个,你可以在整体内部重用你已经实现的东西,而不会暴露更多计划的 API。但是,如果以后需要拆分代码,就得自己实现域间通信的所有管理。

这真的要看未来的打算了。无论如何,我建议让事情保持简单。您可以拥有一个没有太多开销的工作系统,并在将来需要时计划额外的工作。

如果您在有界上下文中拆分应用程序,无论您如何实现它(整体或单独的服务),设计的关键部分是决定哪些信息进入哪些有界上下文。如果您发现您需要在不同的上下文中复制信息,或者一个上下文需要从另一个上下文获取信息以执行其工作,那么这表明您的边界可能不正确。

也就是说,您有一个产生一些概念并给它们一个 Id 的有界上下文,而另一个上下文保留对这些 Id 的引用以与它们一起操作,这是正常的。在您的场景中,SpareParts 上下文负责注册新部件(并为它们提供唯一的 ID)。您的应用程序中没有其他上下文可以创建部件。但是您的 Inspection 上下文每次看到“PartRegisteredEvent”时都可以存储对部件的引用。

实际上,SpareParts 和 Inspections 上下文都有一个具有相同 ID 的部件列表,但是:

  1. 只有 SpareParts 上下文可以注册和注销(或您的领域专家使用的任何更好的名称)

  2. 每个上下文中存储的与零件相关的信息会有所不同。例如,在 SpareParts 上下文中,您将拥有名称、翻译、图像等。在 Inspections 上下文中,您将拥有在检查中使用零件所需的任何信息。您最终可以拥有一个包含零件列表及其库存数量的库存上下文,以及另一个包含零件列表及其价格的上下文。

通常接下来的问题是:

  1. 如何在一个屏幕上向用户展示一个Part的所有信息?答案是视图或数据组合。要么用从相应上下文获取数据的“小部件”组成您的视图,要么让 API 从每个上下文获取数据并构建一个响应对象。

  2. 每个限界上下文如何收集它们需要的信息?有两种方法:a) 使用事件:PartRegistered、PartUnregistered 等 b) 第 1 点的反向方法:让不同的小部件与不同的限界上下文对话,或者分解 API 中的请求以发送数据到相应的限界上下文。

奖励方法:有一个捷径在单体应用中运行得相对较好,可以避免使用事件在每个有界上下文中维护部件列表。在您的场景中,当 API 收到将部分 X 添加到检查 Y 的请求时,而不是直接将请求发送到检查 BC,这要求检查知道部分 X 存在,您可以进行预检查在 SpareParts 中验证零件 X 存在的 API 级别(如果存在),然后将请求转发给 Inspections。如果 Inspections 不知道第 X 部分,它可以为它创建一个记录。通过这种方法,BC 可以始终相信他们收到的数据是有效的,因为它已经在 API 级别进行了验证。但请注意,如果您将这种方法转化为微服务,它会为每个请求引入至少一次到微服务的额外往返。

理想情况下,每个服务/模块都应该是自治的。换句话说,它应该具有完成其工作所需的所有信息和业务逻辑。

因此,您有 2 个相关上下文:“备件库存”和“检查”。

我认为您的备件库存将包含大量有关零件的可搜索信息。也许它包含打印目录供客户浏览所需的所有信息。

对于 Inspections 上下文,假设您正在纸上手动写出 Inspection Sheet。您需要在那个 sheet 上表示有关备件的哪些信息?

我假设它只是零件号、名称和数量。

在这种情况下,为了保持检查上下文的自主性,它应该只是该信息随时可用,而不是存储在清单中的整个 spart 部件对象数据。

如何同步?

一个选项是,在你的所有API中,客户端在创建备件、删除备件或更改备件名称时使用,然后在向备件发送命令后Inventory 上下文,然后它使用数据子集向 Inspections 上下文发送命令,以保持 Inspections 上下文中的数据同步。

一种更可持续的方式是,备件上下文在创建、删除或重命名零件时发布事件。

Inspections 上下文随后可以侦听这些事件并相应地更新其本地存储。您可以使用足够的信息发布事件以使事件的消费者满意(即零件号和名称),或者只发布 Id 并让 Inspections 上下文的基础结构回调到 Inventory API在本地 Inspections 域中执行更新之前获取相关详细信息。

在有界上下文之间使用事件可以防止领域知识泄漏到 API,但是,正如另一个答案中提到的,在谈论下一个上下文之前从一个上下文收集 API 中的信息是一条捷径。但是,如果您的解决方案变得越来越复杂,这可能会让您日后陷入困境。