DDD:同步有界上下文导致不同的域行为/逻辑

时间:2017-03-10 14:18:44

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

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

  1. 上下文"帐户管理" :只允许工作人员在此工作。我们的想法是管理客户帐户(如地址,电话号码,联系人等)并验证客户的帐户(基本上检查客户提供的数据是否有效)。
  2. 上下文"网站" :我可以作为客户登录并编辑我的数据(例如更改我的地址)
  3. 问题在于:

    登录到帐户管理上下文的用户根据定义是员工。所以我可以假设这里做出的改变是值得信赖的#34;在"意义上的数据被验证"。 appservice的简化版本如下所示:

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

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

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

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

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

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

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

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

    我可以通过一种" Originator" 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兔子洞,但在这种情况下你的经验/最佳做法是什么?

1 个答案:

答案 0 :(得分:2)

最简单的答案可能是在您的模型中引入UnverifiedAddress作为一个概念,而不是试图处理"地址"作为一种普遍的想法,将验证作为事后的想法进行了抨击。