在Domain Driven Design中,可以调用另一个有界上下文的应用程序服务吗?

时间:2017-01-01 20:34:23

标签: rest domain-driven-design integration

我正在阅读Vaughn Vernon实施领域驱动设计。在其中一个示例中,他展示了在Collaboration有界上下文中创建的论坛。在创建之前,实例化Creator值对象。 Creator对象的信息来自不同的有界上下文。向REST API发出HTTP请求以从Identity and Access有界上下文中检索用户。然后将其转换为Creator对象。

private Forum startNewForum(
        Tenant aTenant,
        String aCreatorId,
        String aModeratorId,
        String aSubject,
        String aDescription,
        String anExclusiveOwner) {

    Creator creator =
            this.collaboratorService().creatorFrom(aTenant, aCreatorId);

    Moderator moderator =
            this.collaboratorService().moderatorFrom(aTenant, aModeratorId);

    Forum newForum =
        new Forum(
                aTenant,
                this.forumRepository().nextIdentity(),
                creator,
                moderator,
                aSubject,
                aDescription,
                anExclusiveOwner);

    this.forumRepository().save(newForum);

    return newForum;
}

UserInRoleAdapter在另一个有界上下文中调用REST API并将其转换为Creator对象。

public class TranslatingCollaboratorService implements CollaboratorService {

private UserInRoleAdapter userInRoleAdapter;

...

@Override
public Creator creatorFrom(Tenant aTenant, String anIdentity) {
    Creator creator =
            this.userInRoleAdapter()
                .toCollaborator(
                        aTenant,
                        anIdentity,
                        "Creator",
                        Creator.class);

    return creator;
}
...

}

从REST API检索的JSON用于实例化Creator对象。

private T extends <Collaborator> T newCollaborator(String aUsername,
        String aFirstName,
        String aLastName,
        String aEmailAddress,
        Class<T> aCollaboratorClass)
    throws Exception {

    Constructor<T> ctor =
        aCollaboratorClass.getConstructor(
                String.class, String.class, String.class);

    T collaborator =
        ctor.newInstance(
                aUsername,
                (aFirstName + " " + aLastName).trim(),
                aEmailAddress);

    return collaborator;
}

对REST API的调用是否等同于直接在其他有界上下文中调用应用程序服务方法?或者它有何不同?是否直接在其他有界上下文中调用应用程序服务,然后翻译允许的结果?是否有一个REST API用于直接在有界上下文之间进行通信?

编辑:我的问题类似于this,但我只想了解更多信息。在该问题中,据说最好使用事件并保持数据的本地副本而不是在另一个有界上下文中调用应用程序方法。如果将这些应用程序方法置于REST接口之后,是否仍然可以使用事件。是否总是不赞成直接调用其他有界上下文的应用方法,还是应该尽可能少地使用它?

1 个答案:

答案 0 :(得分:4)

有界上下文边界与消息传播方式无关。由架构师决定如何组织应用程序,是否将其分解为微服务等等。对接口进行明确和严格是非常重要的。你命名的REST或RPC或直接调用只是一种传输方式。

当然,几乎按照定义,有界上下文中的概念比外部事物更紧密耦合,这通常可以创建单独的服务,但我怀疑DDD坚持任何特定的方式。这本书提到了例如开放主机服务模式,其中包括&#34;映射三个上下文&#34;说:&#34;我们通常将开放主机服务视为远程过程调用(RPC)API,但它可以使用消息交换实现。&#34;,这可能只是本书的作者意见。< / p>

我认为,有时(并且它也在书中提到),反腐败层(协作上下文)用于有效解耦,因为在书中的例子中,Creator是Collaboration Context概念,而User来自另一个服务,协作只需要一些方面(本书详细描述了它,我不想重复)。

我看到的直接通话的唯一问题是,在进行直接呼叫时,制作适配器&#34;如果是空气稀薄&#34;可能觉得&#34;矫枉过正&#34;对某些人而言,用户最终可能会被使用。使用REST,它可以更容易地将外部环境的概念转换为相关环境中消耗的内容。

虽然不直接相关,但以下问题/答案可能会为您提供更多见解:Rest API and DDD

使用具体的消息传递技术与应用DDD方法是正交的。它更多地涉及特定情况和期望的系统特征,也可能是意见问题。例如,是否从另一个有界上下文保存(缓存?)信息取决于软件设计者。不是来自DDD书籍,但是您构建的分布式系统CAP theorem的解析取决于要求,没有通用的答案可以指导您。

在同一作者的另一本书 - &#34;领域驱动设计蒸馏&#34;,第4章战略设计与上下文映射中,你可以找到一些澄清,引用:&#34;你可能想知道将提供什么特定类型的接口,以允许您与给定的有界上下文集成。这取决于拥有Bounded Context的团队提供的内容。它可以是通过SOAP的RPC,也可以是带资源的RESTful接口,也可以是使用队列或Publish-Subscribe的消息传递接口。在最不利的情况下,您可能被迫使用数据库或文件系统集成,但我们希望不会发生......&#34;