标识每个微服务的域模型边界

小窍门

此内容摘自电子书《适用于容器化 .NET 应用程序的 .NET 微服务体系结构》,可以在 .NET Docs 上获取,也可以下载免费的 PDF 以供离线阅读。

适用于容器化 .NET 应用程序的 .NET 微服务体系结构电子书封面缩略图。

在为每个微服务标识模型边界和大小时,虽然应尽可能倾向小型微服务,但目标并不是尽可能达到最细粒度分离。 相反,目标应该是实现由域知识引导的最有意义的分离。 重点不在于规模,而在于业务能力。 此外,如果基于大量依赖项的应用程序的某些区域需要明确的凝聚力,这也表示需要单个微服务。 凝聚力是确定如何分离或组合微服务的方法。 最终,虽然你对域有了更多了解,但应该以迭代方式调整微服务的大小。 查找正确的大小不是一次性过程。

Sam Newman 是公认的微服务推动者,也是《构建微服务》的作者,他强调应根据此前介绍的有限上下文(BC)模式(域驱动设计的一部分)来设计微服务。 有时,BC 可以由几个物理服务组成,但反之则不然。

具有特定域实体的域模型适用于具体的 BC 或微服务。 BC 限定了领域模型的适用范围,并为开发团队成员提供一个清晰且共享的理解,即哪些部分必须保持凝聚力以及哪些部分可以独立开发。 这些是微服务的相同目标。

另一个影响设计选择的工具是 康威定律,它指出应用程序将反映产生它的组织所具有的社会边界。 但有时相反的是,-the 公司的组织是由软件形成的。 可能需要方向吸取康威定律,按照想要公司进行组织的方式生成边界,倾向于业务流程咨询。

若要标识边界上下文,可以使用称为 上下文映射模式的 DDD 模式。 使用上下文映射,可以标识应用程序中的各种上下文及其边界。 例如,每个小型子系统都有不同的上下文和边界。 上下文映射是定义和明确域之间的边界的方法。 BC 是自治的,包括单个域的详细信息 -details(如域实体),并定义与其他 BC 的集成协定。 这类似于微服务的定义:它是自治的,它实现某些域功能,并且必须提供接口。 这就是为什么上下文映射和边界上下文模式是识别微服务的域模型边界的好方法。

设计大型应用程序时,你将看到其域模型如何分散——例如,目录域的专家在目录和库存域中会以不同方式命名实体,而运输域的专家则会有不同的命名方式。 或者,对于想要存储客户的每个细节的 CRM 专家,用户域实体的大小和属性数目可能与只需要部分客户数据的订购域专家要求不同。 很难消除与大型应用程序相关的所有域的所有域术语的歧义。 但最重要的是,你不应该试图统一术语。 相反,接受每个域提供的差异和丰富性。 如果尝试为整个应用程序创建一个统一的数据库,那么尝试统一词汇会很繁琐,而且对任何多个域专家来说都是不正确的。 因此,BC(作为微服务实现)将帮助阐明在哪里可以使用特定域术语,以及在哪里需要拆分系统,并使用不同的域创建其他 BC。

如果域模型之间的强关系很少,那么每个 BC 和域模型的边界和大小正确,并且在执行典型的应用程序操作时通常不需要合并来自多个域模型的信息。

对于每个微服务的域模型应该有多大的问题,也许最佳答案是:它应具备尽可能独立的自治边界上下文(BC),这样就可以让你专注工作,而无需不断切换到其他上下文(其他微服务的模型)。 在图 4-10 中,可以看到多个微服务(多个 BC)各自拥有自己的模型,并且其实体的定义方式依赖于应用程序中每个已识别域的具体要求。

示意图显示多个模型边界内的实体。

图 4-10. 标识实体和微服务模型边界

图 4-10 演示了与联机会议管理系统相关的示例方案。 相同的实体会在不同上下文中显示为“用户”、“购买者”、“付款者”和“顾客”。 已经根据域专家定义的域确定了几个可作为微服务实现的 BC。 如你所见,有些实体仅存在于一个特定的微服务模型中,例如支付微服务中的支付。 这些事情很容易实现。

但是,你可能还有一些结构不同的实体,这些实体在多个微服务的多个域模型中共享相同的标识。 例如,用户实体在会议管理微服务中被识别。 具有相同标识的同一用户是“订购”微服务中的“购买者”,或者是付款微服务中名为 Payer 的用户,甚至是客户服务微服务中名为“客户”的用户。 这是因为,根据每个领域专家所使用的 通用语言,即使拥有不同的属性,用户也可能会有不同的视角。 微服务模型中名为“会议管理”的用户实体可能具有其大部分个人数据属性。 因此,同一个用户在微服务支付中的“付款人”角色或在微服务客户服务中的“客户”角色,可能不需要使用相同的属性列表。

图 4-11 中说明了类似的方法。

显示如何将数据模型分解为多个域模型的关系图。

图 4-11. 将传统数据模型分解为多个域模型

在界限上下文之间分解传统数据模型时,可以有不同的实体共享同一标识(买家也是用户),在每个界限上下文中具有不同的属性。 可以看到用户是如何作为用户实体出现在会议管理微服务模型中的,并且在定价微服务中也以购买者实体的形式出现,当用户实际上是购买者时,具有备用属性或用户详细信息。 每个微服务或 BC 可能不需要与用户实体相关的所有数据(只是其中的一部分),具体取决于要解决的问题或上下文。 例如,在定价微服务模型中,不需要用户的地址或姓名,只需 ID(作为身份)和状态,这将在为每个买家定价座位时影响折扣。

Seat 实体在每个域模型中具有相同的名称,但属性不同。 然而,席位共享具有相同 ID 的标识,就像用户和购买者一样。

基本上,有多个服务(域)中存在一个用户的共享概念,这些服务(域)都共享该用户的标识。 但在每个域模型中,可能有有关用户实体的其他或不同的详细信息。 因此,需要有一种方法将用户实体从一个域(微服务)映射到另一个域。

不跨域共享具有相同数量的属性的同一用户实体有几个好处。 一个好处是减少重复,使微服务模型没有任何不需要的数据。 另一个好处是,主微服务拥有每个实体的特定类型的数据,以便更新和查询该类型的数据仅由该微服务驱动。