【问题标题】:DDD: Syncing bounded contexts causing different domain behavior/logicDDD:同步有界上下文导致不同的域行为/逻辑
【发布时间】:2017-03-10 14:18:43
【问题描述】:

我目前正在开发一个由多个有界上下文组成的 DDD 系统。其中两个是:

  1. 上下文“帐户管理”:只允许工作人员在这里工作。这个想法是管理客户帐户(如地址、电话号码、联系人等)并验证客户的帐户(主要是检查客户提供的数据是否有效)。
  2. 上下文“网站”:我可以作为客户登录并编辑我的数据(例如更改我的地址)

问题来了:

根据定义,登录到帐户管理上下文的用户是员工。所以我可以假设这里所做的更改在“数据已验证”的意义上是“值得信赖的”。 appservice 的简化变体如下所示:

class AccountAppService
{
    public function changeAddress(string $accountId, string $address) : void
    {
        $account = $this->accountRepository->ofId(new Guid($accountId));
        $account->changeAddress(new Address($address));
    }
{

这是我在员工更改地址时调用的应用服务。请注意,我没有注入/使用 IdentityService 来了解员工是谁,因为这在这里并不有趣。在成功调用其 changeAddress() 方法后,Account 实体将发出一个 AccountAddressChanged 事件

class Account implements Entity
{
    public function changeAddress(Address $address) : void
    {
        $this->address = $address;
        DomainEventSubscriber::instance()->publish(new AccountAddressChanged($this));
    }
}

但我还需要在客户编辑网站上的数据时立即反映更改。我计划通过“AccountAddressChangedViaWebsite”事件来异步执行此操作。帐户管理上下文将订阅并处理该事件,将相应的帐户再次设置为“未验证”。因此,帐户管理上下文的简化订阅者可能如下所示:

class AccountAddressChangedViaWebsiteSubscriber
{
    public function handle(AccountAddressChangedViaWebsite $event) : void
    {
        $accountId = $event->accountId();
        $address = $event->getAddress();
        $this->accountService->changeAddress($accountId, $address);
    }
}

现在的问题是:员工直接调用应用服务,客户则通过订阅者。如果我们说“我们必须在客户更新其数据后重新验证帐户”,这听起来像是一个域概念。 领域概念适合实体或领域服务,但不适合我所知道的应用程序服务或订阅者。这对我来说意味着应该避免以下情况(注意最后一行调用 unverifyAccount()):

class AccountAddressChangedViaWebsiteSubscriber
{
    public function handle(AccountAddressChangedViaWebsite $event) : void
    {
        $accountId = $event->accountId();
        $address = $event->getAddress();
        $this->accountService->changeAddress($accountId, $address);
        $this->accountService->unverifyAccount($accountId);
    }
}

这是在某种程度上隐藏在订阅者中的域逻辑,这看起来很奇怪。我有直觉认为这应该是域服务的责任,但是域服务如何知道它是由外部事件(通过订阅者)或命令调用的?

我可以传递一种“发起者”ValueObject,告诉我导致此问题的用户是员工还是外部系统。示例:

class OriginatorService
{
    public function changeAddress(Originator $originator, Account $account, Address $address) : void
    {
        $account->changeAddress($address);
        if(($originator instanceof Employee) === false) {
            $account->unverify();
        }
    }
}

在这里,我将要做的事情委托给域服务。但是,将 OriginatorService 双重分派到 Account 实体中可能是一个好的解决方案吗?这样,实体可以通过询问传入的 originatorService 来检查是谁导致了更改,并且可以取消验证自己。

我想我在这里陷入了 DDD 兔子洞,但是在这种情况下,您的经验/最佳实践是什么?

【问题讨论】:

    标签: domain-driven-design bounded-contexts domain-events


    【解决方案1】:

    最简单的答案可能是在您的模型中引入 UnverifiedAddress 作为一个概念,而不是试图将“地址”视为一个普遍的想法,然后再添加验证。

    【讨论】:

    • 谢谢!有道理,因为帐户永远不会只是整体验证,而是部分验证。但是,主要问题仍然存在,因为应用程序仅从外部获取“原始”数据类型,因此永远“不知道”您是否为其提供了经过验证的地址。我想我会保持简单,并始终为域层提供未经验证的地址,并且用户 activley 必须在使用附加请求对其进行更新后对其进行验证。对于大多数用例来说,这应该足够了。
    猜你喜欢
    • 1970-01-01
    • 2010-10-24
    • 1970-01-01
    • 2017-10-12
    • 1970-01-01
    • 1970-01-01
    • 2013-09-16
    • 1970-01-01
    • 2013-11-27
    相关资源
    最近更新 更多