首页 > 解决方案 > EventSourcing, Aggregates – 使用不变量而不加倍它们

问题描述

我在我的应用程序中非常基本地使用事件溯源技术,但是我遇到了一个概念问题。让我们直接举个例子。

ProductAggregateRoot.php

public function changePrice(ChangeProductPrice $command): self
{
    if ($this->availability->equals(Availability::UNAVAILABLE())) {
        throw CannotChangePriceException::unavailableProduct();
    }

    if ($this->price->equals($command->newPrice)) {
        throw CannotChangePriceException::priceHasntChanged();
    }

    $this->recordThat(
        new ProductPriceChanged($this->price, $command->newPrice)
    );

    return $this;
}

现在,我想创建一些其他方法(甚至域服务,并不重要),这很简单:

  1. 从外部来源获取当前价格和可用性
  2. 尝试更新总价。
  3. 尝试更新总体可用性。

如您所见,在更新价格时,我正在检查一些业务不变性,例如如果产品不可用,您无法更改价格,如果其价值没有改变,您无法更改价格。如果任何不变量被破坏,则抛出异常。

现在,在我的域服务中,我想根据外部数据源更改价格和可用性。现在,我只是做了一些 try catch 块,如下所示:

try {
    $aggregate->changePrice(new ChangeProductPrice(
        $productId,
        $state->getPrice()
    ));
} catch (CannotChangePriceException $ex) {
}

一个用于价格的 try-catch 块,另一个用于可用性等。它有效,但我觉得它完全是错误的和hacky。我会对简单的 if 块和方法/规范(如CanChangePrice(). 但是,我需要双重使用它——无论是在服务中还是在具体方法本身,这听起来也不好。

问题是:你们如何处理这些事情?这似乎是一个非常微不足道的问题,但我仍然没有找到让我感觉良好的解决方案。

标签: phpdomain-driven-designevent-sourcing

解决方案


几个想法:

  • 为什么没有“更改价格和可用性”命令?这更好地捕捉了更新两者的意图,并允许不变检查具有更好的上下文知识(例如,如果我们将可用性更新为可用,那么当前可用性是没有意义的,因为它是先前时间的遗物)。

  • 我有点怀疑将价格更改为实际当前价格的尝试是错误的。在我看来,这个命令是表达一种将价格变成期望价格的愿望,所以如果这个愿望已经得到满足,为什么还要犯这个错误呢?返回$this(实际上是耸耸肩并说“确定”)似乎更好,并且不会强迫请求者知道当前价格(严格来说,他们不能知道当前价格)。


推荐阅读