在领域驱动设计中可以调用另一个限界上下文的应用程序服务吗?

In Domain Driven Design is it okay to call an application service of another bounded context?

我正在阅读 Vaughn Vernon 的《实施领域驱动设计》。在其中一个示例中,他展示了在协作限界上下文中创建的论坛。在它被创建之前,一个 Creator 值对象被实例化。 Creator 对象的信息来自不同的限界上下文。向 REST API 发出 HTTP 请求以从身份和访问限界上下文中检索用户。然后将其转换为 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;
}
...

}

JSON 从 REST 检索 API 用于实例化 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 接口后面,使用事件是否仍然更可取。直接调用其他限界上下文的应用程序方法总是不受欢迎,还是应该尽可能少地使用它?

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

当然,几乎根据定义,限界上下文中的概念比外部事物更紧密地耦合,这通常使得创建单独的服务成为可能,但我怀疑 DDD 是否坚持任何特定方式。有问题的书在 "Mapping Three Contexts" 中提到了 Open Host Service 模式等:"We generally think of Open Host Service as a remote procedure call (RPC) API, but it can be implemented using message exchange.",这可能只是本书作者的意见。

我觉得,有时候(书上也提到了),Anticorruption Layer (of Collaboration Context) 是用来进行有效解耦的,因为在书本例子中,Creator是Collaboration Context的概念,而User来自另一种服务,Collaboration只需要一些方面(书上有详细介绍,不想重复)。

我看到的直接调用的唯一问题是,在进行直接调用时,使适配器 "out if thin air" 对某些人来说可能感觉 "overkill",并且最终可能会使用用户。使用 REST,从心理上更容易将外部上下文的概念转化为相关上下文中使用的内容。

虽然不直接相关,但以下 question/answers 可能会为您提供更多见解: .

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

在同一作者的另一本书 - "Domain-Driven Design Distilled" 中,第 4 章。使用上下文映射进行战略设计,您可以找到一些说明,引用:"You may be wondering what specific kind of interface would be supplied to allow you to integrate with a given Bounded Context. That depends on what the team that owns the Bounded Context provides. It could be RPC via SOAP, or RESTful interfaces with resources, or it could be a messaging interface using queues or Publish-Subscribe. In the least favorable of situations you may be forced to use database or file system integration, but let’s hope that doesn’t happen..."