高内聚低耦合的集中决策设计

假设,我们正在构建另一个电子商务平台。其关键业务流程之一当然是处理订单。付款成功后,订单模块(域)必须异步调用仓库,准备购买的货物。然而,这些货物可能并不在那里。通常情况下,这不是什么大问题,因为我们可以从供应商那里获得。但是,如果有任何物品已经没有了怎么办?订单已经下了!钱已经转手了。我们的客户已经在等待交货了。我们别无选择,只能取消订单。

假设仓库必须让订单知道这件事。抛开部署策略和通信媒介不谈,我们应该如何在应用程序接口层面为这样的操作命名呢?

应该是 cancelOrder 还是 handleItemUnavailable?

有人会说这只是一个偏好问题,但我不同意这种说法。事实上,问题并不在于这两个名称,而在于由谁来做决定。令人惊讶的是,我们的选择会对整体设计和长期可维护性造成严重后果。

为了实现高度内聚和松散耦合,我们需要集中决策。

这就意味着,每个模块(领域)都应该是其职责范围内的唯一决策者。同时,这些模块只应了解彼此间绝对必要的信息。

选择cancelOrder作为名称会让仓库决定何时取消订单?
事实上,仓库可能根本不需要订单概念!从它的角度来看,所请求的项目永久不可用,仅此而已。避免导入外来概念支持松散耦合。

订单应该是唯一关心......订单的概念。整个订单生命周期的管理都应封装在这里。封装可以提高内聚性,这是我们所希望的。

选择 handleItemUnavailable 意味着下一步应由 Orders 来完成。

集中决策可以提高长期可维护性。为了改善客户体验,我们可以避免在这种情况下立即取消订单。相反,我们可以以更低的价格提供类似的产品。以 cancelOrder 为名,我们至少需要触及两个模块(域)才能引入这样的变化。选择 handleItemUnavailable 则可以使更改对仓库透明。

在事件驱动的世界中,我们甚至可以将此调用转化为更通用的 WarehouseItemUnavailable 事件。这样不仅可以消除点对点通信,还可以在以后插入更多消费者。一旦物品不再可用,我们可能需要更新目录以防止进一步购买,或通知销售部门......

所述方法可以在不同的部署策略中很好地扩展。订单和仓库可以是同一个应用程序的两个不同文件或模块,也可以是不同的服务。根据具体情况,操作名称可能会略有不同。但其背后的原因是相同的。我们希望集中决策。