如何处理DDD故障?

时间:2012-06-25 12:20:38

标签: domain-driven-design

当我的域中“某些东西”发生变化时,我需要在本地驱动器上创建一个文件夹。因此,在DDD方式中,我需要引发一个事件,而不是让我的域创建文件夹。

我的问题是如果我的事件失败(即文件夹的创建失败)会怎样?

我是否必须重新提出另一个命令以撤消我认为称为补偿命令的第一个更改?

如果补偿命令失败怎么办?现在我有域名更改但该文件夹不存在。

2 个答案:

答案 0 :(得分:3)

您描述建议的解决方案的方式实际上不是DDD;更多的CQRS(即事件和补偿命令),我认为可能使情况复杂化。

您是否真的需要针对异步操作的场景采用CQRS方法?在那里,在一个单独的事务中创建的文件夹对被调用和持久化的业务逻辑有什么好处?在引发查询服务处理的事件时,这种方法有充分的理由,因为查询服务可能位于单独的物理机器上,因此需要RPC。此外,该事件可能需要更新许多非规范化表。因此,对于性能,此过程使用异步事件模型是有意义的。但是为了创建一个本地文件夹,我不确定它呢?

可能的方法

public class ApplicationService : IApplicationService
{
    private readonly IMyAggregateRepository _myAggregateRepository;
    private readonly IFolderCreationService _folderCreationService;

    public ApplicationService(IMyAggregateRepository myAggregateRepository, IFolderCreationService folderCreationService)
    {
        _myAggregateRepository = myAggregateRepository;
        _folderCreationService = folderCreationService;
    }

    public void SomeApplicationServiceMethod(Guid id)
    {
        using (IUnitOfWork unitOfWork = UnitOfWorkFactory.Create())
        {
            MyAggregate aggregate = _myAggregateRepository.GetById(id);

            aggregate.SomeMethod();

            _myAggregateRepository.Save(aggregate);

            _folderCreationService.CreateFolder();
        }
    }
}

此处,只有在工作单元的using语句中的所有代码完成且没有错误时,更改才会提交到数据库。

请注意,它不是域服务域实体,它们调用文件夹服务...它是应用程序服务。我更喜欢将域服务集中在纯域逻辑上。应用程序服务的工作是编排对域,数据库和任何其他基础架构服务(如此文件夹服务)的客户端调用。

如果您认为有充分理由使用事件模型,那么您所说的是正确的。如果在事件处理程序中创建文件夹失败,则必须发出补偿命令。您需要确保此处理程序不会因设计而失败(我的意思是所讨论的实体始终处于可以执行此补偿命令的状态;并且状态还原)。拥有涵盖所有场景的良好单元测试将有所帮助。如果设计中存在允许此补偿命令失败的缺陷,我猜您必须通过发送失败的电子邮件/通知来采取手动干预。

P.S。虽然不是问题的关键,但我真的建议不要创建物理文件夹,除非确实有充分的理由。根据我的经验,它只会导致部署/机器升级和事情的头疼。显然我不知道你这样做的原因,但我真的建议你使用文档存储/数据库代替你需要存储的东西。

答案 1 :(得分:0)

如果文件系统文件夹对您的域至关重要,我会将文件夹创建为域服务。这样,您可以让实体处理所有业务规则和逻辑,如果创建文件夹失败,您的域不会处于无效状态。

将服务作为参数传递给处理逻辑的方法(双重调度模式)。

文件夹服务示例。

IFolderService
{
    CreateFolder(string path);
}

实体示例。

class MyEntity
{
    public void DoWork(IFolderService folderService, ...)
    {
        folderService.CreateFolder(...);

        // do work.
    }
}

完成工作后,您可以引发域事件以通知子系统。