代码之家  ›  专栏  ›  技术社区  ›  DuskMcDusk

逻辑和性能中的聚合根冲突

  •  2
  • DuskMcDusk  · 技术社区  · 7 年前

    问题是: 我们有一个用户与任务交互的项目。但每个任务都是活动的一部分,每个活动都存在于一个帐户中。因此,在我看来,将帐户作为聚合根似乎是合乎逻辑的(因为没有战役,任务就不可能存在,没有帐户,战役也不可能存在)。

    帐户、活动和任务都有某种预算,用户必须能够执行任务。 所以我想了一下:

    class Account{
        Budget Budget;
        List<Campaign> Campaigns;
        // Account stuff
    }
    
    class Campaign{
        Budget Budget;
        List<Mission> Missions;
        // Campaign stuff
    }
    
    class Mission{
        Budget Budget;
        double Value;
        // Mission stuff
    }
    

    这对于域逻辑来说是有意义的,但我很难允许用户直接处理任务,因为他们不关心活动或帐户。还有多个帐户,我需要向用户提供他们可以执行的所有任务。加载所有这些实体变得繁重和复杂,因此我考虑恢复所有内容,并使任务如下:

    class Mission{
        Budget AccountBudget;
        Budget CampaignBudget
        Budget MissionBudget
        Double Value;
        // All mixed stuff that i need
    }
    

    所以我只需要一个任务存储库,它可以更容易地与所有任务和用户一起工作,但当任务执行时,我需要更新所有任务的帐户和活动预算。关于域逻辑,这种结构对我来说也没什么意义。 那么,如果我采用第一种解决方案,我如何避免性能问题,并让它为用户获得所有可用的任务而工作?如果我采用第二种解决方案,它有意义吗?

    1 回复  |  直到 7 年前
        1
  •  0
  •   VoiceOfUnreason    7 年前

    因此,在我看来,将帐户作为聚合根似乎是合乎逻辑的(因为没有战役,任务就不可能存在,没有帐户,战役也不可能存在)。

    在实践中,这似乎不是一个特别好的启发;将域划分为聚合更重要的是 行为 而不是结构。你需要知道帐户的详细信息才能更改任务吗?您需要知道更改帐户的任务的详细信息吗?

    我很难允许用户直接处理任务,因为他们不关心活动或帐户。

    这是一个很大的暗示,任务可能是一个单独的集合;如果您希望许多用户同时操作他们的任务,而不需要互相干涉,则情况尤其如此。

    执行任务时,我需要更新所有任务的帐户和战役预算。

    ,或者只是 很快 ?

    你可能应该复习一下格雷格·杨关于 warehouse systems . 基本思想是域模型没有试图阻止用户做事情;相反,它的重点是在模型怀疑可能存在问题时创建“异常报告”。

    在您的示例中,这可能看起来像是用户直接使用任务预算 分离骨料 那个 异步

    另一种观点是乌迪·达韩的文章 Race Conditions Don't Exist

    时间上的微秒差异不应该对核心业务行为产生影响。

    你有许多用户在更新任务预算;这意味着它们是 协作 与客户预算互动。因此,您应该考虑允许这种协作在没有用户争用的情况下发生的设计。

    我猜你最终会发现自己 Mission 结构类似

    class Mission{
        AccountId accountId;
        CampaignId campaignId;
        MissionId missionId;
    
        Budget Budget;
        // Mission stuff
    }
    

    对于允许用户在共享资源或某些资源上进行协作以进行查找的设计,您有什么建议吗?

    我觉得外面没有太多。你也许可以从格雷格·杨的演讲中得到一些想法 occasionally connected systems .

    有一种替代方法可以将来自外部世界的消息视为命令;你可以认为他们是 事件 UserDecided , UserSubmittedForm .... 所以外部世界就是记录,你的聚合就像一个下游事件处理器

    Alice said X
    Bob said !X (contradicting Alice)
    ... and therefore (other consequences)
    

    其他后果可能会升级到一个人身上,或者这两个决定相互抵消,或者。。。。

    您仍在更新您的记录簿,因此它仍然是CQS意义上的“命令” handle(Event) ,但您可以将“捕获事件”与“对事件进行操作”解耦