ddd - 与远程 API 的同步应该去哪里?

问题描述 投票:0回答:1

为了使我的应用程序正常工作,我需要定期同步来自外部服务的数据(可以是 API,也可以是简单的文本文件,但目前它是 API)。

由于这需要一次创建/更新许多实体,因此我需要创建一个域服务。但是,我还需要创建一些包含远程 API 响应的 DTO,对吗?

这个逻辑应该去哪里呢?我应该有以下目录结构吗:

Domain -
    Model - // my set of entities and repository interfaces are here
        ....
    Synchronization -
        RunSynchronizationService.php // domain service
Application
    Synchronization - 
        SynchronizeData.php // application service
        SynchronizationDataSourceInterface.php // used by application service
        MySpecificRemoteApiDataSource.php // this implements the interface above
        SynchronizationDataSourceResponse.php // this would be returned by each call of  SynchronizationDataSourceInterface method, and would contain data normalized, but not validated.
Infrastructure -
    MyConcreteImplementationOfModelEntityRepository.php   

当我想要同步数据时,我只需调用Application\Synchronization\SynchronizeData的sync方法,该方法将采用SynchronizationDataSourceInterface的具体实现,调用其方法,并验证返回的SynchronizationDataSourceResponse对象,然后将它们传输到Domain\Model\Synchronization\运行同步服务?

或者我应该删除 RunSynchronizationService (域服务)并让应用程序服务 (SynchronizeData.php) 在同步过程的每个步骤创建/更新域实体?

php service domain-driven-design
1个回答
3
投票

通常,当遇到有关外部服务接口应该位于何处的问题时,我会尝试将其视为另一个存储库。 我在这里选择的抽象级别将在很大程度上取决于谁将使用该服务(只是该项目的域/应用程序层?其他项目?),是否存在不同版本/供应商的服务,以及如何使用哪个服务确定了。

对于您的示例,我假设该应用程序是唯一直接使用同步服务的应用程序。 共享服务需要进一步隔离公共端点(例如接口和输出对象),以避免将不必要的对象溢出到其他项目中。

但在这种情况下,为了将该服务视为另一个存储库,我将为其放置接口以及域期望并在域中使用的标准输出。

“验证”的含义在您的描述中有点模糊,所以我将尝试在这里攻击不同的观点。 一项或全部都可以申请。

如果验证要求您与域数据进行比较,它可能应该驻留在

RunSynchronizationService.php
模块中。 该模块似乎负责获取同步数据并将其应用到您的域。

如果验证是针对从同步服务调用返回的数据,并且不需要直接访问域对象图,我会将该验证放在接口的服务实现上,并在服务接口上公开该验证调用。 要处理同步服务的多个版本(例如 VersionA、VersionB 等)中的验证相同的情况,您可以使用继承和覆盖,或同步服务的通用辅助函数等。在下面的示例中,我使用了继承。

您可能需要进行这两种验证。 首先检查与域无关的同步数据问题(在已实现的类上),然后针对域中的业务规则进行检查(在

RunSynchronizationService
中)。 但是,当您在界面上公开同步数据验证调用时,这两个调用可能都会发生在
RunSynchronizationService
中。

应用程序层应负责创建服务实例 (

MySpecificRemoteApiDataSource
),并将其作为
RunSynchronizationService.php
传递到
SynchronizationDataSourceInterface
模块中。 如果有多个版本,应用程序层可能会负责选择哪个版本(也许是从配置中),并使用工厂。

但这又在很大程度上取决于该同步服务的范围。 如果您有依赖它的外部项目,您可能希望服务层本身的工厂部分,以便其他每个项目都使用相同的选择方法进行操作。

Domain -
    Model - // my set of entities and repository interfaces are here
        ....
    Synchronization -
        RunSynchronizationService.php // domain service
        SynchronizationDataSourceInterface.php // used to define the contract associated with a sync service
        SynchronizationDataSourceResponse.php // this would be returned by each call of  SynchronizationDataSourceInterface method, and would contain data normalized, but not validated.
Application -  
    Synchronization - 
        SynchronizeData.php // application service - Uses a factory or some means of determining which version to use and introduce the domain to the data point.

Infrastructure -
    MyConcreteImplementationOfModelEntityRepository.php  

Synchornization -
    VersionA -  
        MySpecificRemoteApiDataSource.php  // Implements SynchronizationDataSourceInterface.php, inherits from SyncApiDataSourceBase.php
    SyncApiDataSourceBase.php  // Common logic for sync goes here, such as validation.
© www.soinside.com 2019 - 2024. All rights reserved.