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

Ben*_*ten 3 rest integration domain-driven-design

我正在阅读 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;
}
Run Code Online (Sandbox Code Playgroud)

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;
}
...

}
Run Code Online (Sandbox Code Playgroud)

从 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;
}
Run Code Online (Sandbox Code Playgroud)

这种对 REST API 的调用是否等同于直接在另一个有界上下文中调用应用程序服务方法?或者有什么不同?是否允许在其他有界上下文中直接调用应用程序服务然后翻译结果?是否有用于在有界上下文之间直接通信的 REST API 很常见?

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

Rom*_*usi 6

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

当然,几乎根据定义,有界上下文中的概念比外部事物更紧密耦合,这通常使得制作单独的服务成为可能,但我怀疑 DDD 坚持任何特定方式。有问题的书在“映射三个上下文”中提到例如开放主机服务模式等说:“我们通常将开放主机服务视为远程过程调用(RPC)API,但它可以使用消息交换来实现。”,这可以只是书的作者意见。

我认为,有时(并且在书中也提出),Anticorruption Layer(Collaboration Context 的)用于有效解耦,因为在书中示例中,Creator 是 Collaboration Context 概念,而 User 来自另一个服务,并且仅Collaboration 需要一些方面(书中详细描述,我不想重复)。

我看到的直接呼叫的唯一问题是,在进行直接呼叫时,使适配器“在稀薄的空气中”可能会让某些人感到“矫枉过正”,并且最终可能会使用用户。使用 REST,在心理上更容易将外部上下文的概念转化为相关上下文中所消耗的内容。

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

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

在同一作者的另一本书 - “Domain-Driven Design Distilled”,第 4 章“使用上下文映射的战略设计”中,您可以找到一些说明,引用:“您可能想知道将提供什么样的特定接口来允许您与给定的限界上下文集成。这取决于拥有限界上下文的团队提供的内容。它可以是通过 SOAP 的 RPC,或与资源的 RESTful 接口,也可以是使用队列或发布订阅的消息传递接口。至少有利于您可能被迫使用数据库或文件系统集成的情况,但我们希望这不会发生......”