你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn。
域驱动设计(DDD)反对为整个系统创建单一统一模型的想法。 相反,它鼓励将系统划分为边界上下文,每个上下文都有自己的模型。 在 DDD 的战略阶段,可以映射业务域并为域模型定义边界上下文。
在战术 DDD 阶段,需要更精确地定义领域模型。 战术模式在单个边界上下文中应用。 在微服务体系结构中,每个绑定上下文都是一个候选微服务,请注意实体和聚合模式。 应用这些模式有助于识别应用程序中服务的自然边界。 有关详细信息,请参阅 标识微服务边界。 作为一般原则,微服务不应小于聚合,且不大于边界上下文。
本文回顾了战术模式,然后将其应用于无人机交付应用程序中的发货边界上下文。
战术模式概述
本部分简要总结了战术 DDD 模式。 如果熟悉 DDD,可以选择跳过它。 这些模式在埃里克·埃文斯的书第 5 章和第 6 章中更详细地介绍,以及沃恩·弗农 的《实施 Domain-Driven 设计 》。
实体。 实体是一直保持唯一标识的对象。 例如,在银行应用程序中,客户和帐户就是实体。
实体在系统中有唯一的标识符,使用该标识符可以查找和检索该实体。 这并不意味着,该标识符始终直接向用户公开。 它可能是数据库中的 GUID 或主键。
标识可以跨越多个边界上下文,并且可能持续到应用程序的生存期之外。 例如,银行帐户号或政府颁发的 ID 不绑定到特定应用程序。
实体的属性可能会随时间而变化。 例如,人员的姓名或地址可能会更改,但它们保持不变。
值对象。 值对象没有标识。 它仅由其属性的值定义。 值对象是不可变的。 若要更新值对象,将创建一个新实例来替换旧实例。 值对象可以包括封装域逻辑的方法,但这些方法不得产生副作用或修改对象的状态。 值对象的常见示例包括颜色、日期和时间和货币值。
聚合。 聚合定义一个或多个实体的一致性边界。 一个聚合只包含一个根实体。 可以使用根实体的标识符执行查找。 聚合中的其他任何实体是根的子级,由从根开始的后续指针引用。
聚合的作用是为事务不变性建模。 现实世界中的事物具有复杂的关系。 客户创建订单,订单包含产品,产品有供应商,等等。 如果应用程序修改了多个相关对象,它如何保证一致性? 如何跟踪并实施不变性?
传统应用程序通常使用数据库事务来实施一致性。 但是,在分布式应用程序中,这种做法通常不可行。 单个业务事务可能跨越多个数据存储、长时间运行,或者涉及第三方服务。 最终由应用程序而不是数据层来实施域所需的不可变性。 这就是要为聚合建模的目的。
注意
聚合可以包含单个实体且不包含子实体。 聚合的定义由事务边界确定。
领域服务和应用服务。 在 DDD 术语中,服务是实现某种逻辑且不保存任何状态的对象。 Evans 对封装领域逻辑的领域服务,以及提供技术功能(例如用户身份验证或发送短信)的应用服务做了区分。 领域服务通常用于对跨多个实体的行为建模。
注意
软件开发中广泛使用了“服务”一词。 此处使用的定义与微服务不直接相关。
领域事件。 发生某些情况时,域事件可以通知系统的其他部分。 顾名思义,域事件应表示域中有意义的内容。 例如,“已插入表中的记录”不是域事件。 “已取消传递”是域事件。 域事件在微服务体系结构中尤为重要。 由于微服务是分布式的,并且不共享数据存储,因此域事件支持服务之间的协调。 有关异步消息传送的详细信息,请参阅 Interservice 通信。
此处未介绍一些其他 DDD 模式,包括工厂、存储库和模块。 实现微服务时,这些模式非常有用,但在设计微服务之间的边界时,它们不太相关。
无人机交付:应用模式
首先,我们探讨“交货”边界上下文必须处理的方案。
- 某个客户可以请求派遣无人机从已注册到无人机交付服务的公司取件。
- 寄件人生成了一个标记(条形码或 RFID)并粘贴在包裹上。
- 无人机将会收取包裹,然后将包裹从源位置交付到目标位置。
- 当客户安排交付时,系统将会根据路线信息、天气情况和历史数据提供 ETA。
- 当无人机起飞时,用户可以跟踪当前位置和最新的 ETA。
- 在无人机收取包裹之前,客户可以取消交付。
- 完成交付时,客户将收到通知。
- 寄件人可以请求客户提供签名或指纹形式的交付信息。
- 用户可以查找已完成交付的历史记录。
在这些方案中,开发团队确定了以下实体。
- 交付
- 包裹
- 无人机
- 帐户
- 确认
- 通知
- 标记
前四个项(“交付”、“包裹”、“无人机”和“帐户”)都是表示事务一致性边界的聚合。 “确认”和“通知”是“交付”的子实体,“标记”是“包裹”的子实体。
此设计中的值对象包括“位置”、“ETA”、“包裹重量”和“包裹大小”。
为便于演示,下面提供了“交付”聚合的 UML 关系图。 请注意,该聚合包含对其他聚合(包括“帐户”、“包裹”和“无人机”)的引用。
有两个领域事件:
当无人机起飞时,“无人机”实体将发送 DroneStatus 事件,用于描述无人机的位置和状态(飞行中、已着陆)。
每当交付阶段发生更改时,“交付”实体将发送 DeliveryTracking 事件。 DeliveryTracking 事件包括 DeliveryCreated、DeliveryRescheduled、DeliveryHeadedToDropoff 和 DeliveryCompleted。
请注意,这些事件描述领域模型中有意义的事物。 它们描述有关域的某些信息,但不与特定的编程语言构造相关。
开发团队还确定了另一个功能领域,但该功能领域并不与前面所述的任何实体紧密相关。 系统的某个部分必须协调有关安排或更新交付的所有步骤。 因此,开发团队向设计添加了两个 域服务 :协调步骤的计划 程序 ,以及监视每个步骤的状态的 监督程序 ,以检测任何步骤是否失败或超时。此方法是 计划程序代理监督程序模式的变体。
后续步骤
下一步是定义每个微服务的边界。