Domain driven design 有界上下文的实现与设计

Domain driven design 有界上下文的实现与设计,domain-driven-design,repository-pattern,aggregateroot,onion-architecture,bounded-contexts,Domain Driven Design,Repository Pattern,Aggregateroot,Onion Architecture,Bounded Contexts,假设我有两个有界上下文,发货上下文和计费上下文。每个上下文都需要了解客户 在数据级别,客户由数据库中的CustomerTbl表表示。此表由描述客户的所有必要列组成 CustomerTbl中的列(简化): Name 物理地址 PaymentMethod 配送上下文与名称和物理地址有关,而计费上下文与名称和付款方法有关 在发货上下文中,我对聚合的收件人进行了建模: Recipient现在拥有Name和physicaldaddress 在计费上下文中,我对聚合付款人进行了建模: Payer具

假设我有两个有界上下文,发货上下文和计费上下文。每个上下文都需要了解客户

在数据级别,客户由数据库中的
CustomerTbl
表表示。此表由描述客户的所有必要列组成

CustomerTbl
中的列(简化):

  • Name
  • 物理地址
  • PaymentMethod
配送上下文与
名称
物理地址
有关,而计费上下文与
名称
付款方法
有关

在发货上下文中,我对聚合的收件人进行了建模:

  • Recipient
    现在拥有
    Name
    physicaldaddress
在计费上下文中,我对聚合
付款人
进行了建模:

  • Payer
    具有
    Name
    PaymentMethod
收件人
付款人
聚合都由上下文边界完全分隔。他们也有自己的存储库

问题:
  • 使用同一个“数据库表”进行多个聚合(前提是它们位于单独的有界上下文中)是否可以接受

  • 客户数据可能在许多更为有限的环境中需要。这是否意味着每个有界上下文都有许多聚合、存储库和工厂实现?代码中会有一定程度的冗余。这不影响可维护性吗

  • 是否可以在集合中共享属性?例如customer
    Name
    属性。这也意味着冗余的验证代码


  • 答案:

    1.如果聚合及其存储库为只读,则为“是”。如果一个人单独更改模式或数据而不通知其他人,那么在有界上下文之间共享存储和模式可能会有问题,但我认为在这种情况下这不是一个大问题

    但如果收款人和付款人是可编辑的,则情况就不同了。有可能修改它们,这会在有限的上下文中产生影响。例如,客户可能需要更改特定发货订单的地址,但共享cutsomer表可能会在不通知的情况下更改客户发货订单的所有地址。所以最好为它们使用不同的存储空间

    2.不同的有界上下文需要客户的不同方面。我认为只依赖必要的数据是一种好的做法,因此聚合抽象可能会有所不同。潜在的可维护性问题可能发生在实现端(主要是因为代码重复)。因此,我们可以引入一个额外的组件来返回客户的所有方面,并在其上构建特定于上下文的有限适配器。

    Q&A 1) 使用同一个“数据库表”进行多个聚合(前提是它们位于单独的有界上下文中)是否可以接受

    • 只要您遵循管理共享状态的严格策略,我就可以接受
    • DDD可以接受,因为域被认为比数据更重要
    • 只要在不引入(太多)隐性成本的情况下完成工作,客户就可以接受
    2) 客户数据可能在许多更为有限的环境中需要。这是否意味着每个有界上下文都有许多聚合、存储库和工厂实现?代码中会有一定程度的冗余。这不影响可维护性吗

    不一定,看一看

    3) 是否可以在集合中共享属性?例如customer Name属性。这也意味着冗余的验证代码

    答案与问题1相同。关于冗余,一旦您有了一个共享内核,您就可以简单地将验证器类放在其中

    关于DRY和DDD之间的冲突: 优雅的代码不会不必要地使伟大的设计原则相互冲突。通常有一种方法可以满足这些原则。你只是还没有找到它,因为要么你对原理理解不够,要么你对问题剖析不够


    (如果这听起来很教条,那是因为软件工程实际上是一种宗教)

    您能解释一下问题3中的“共享属性”和什么是“冗余验证代码”吗?关于共享属性:在两种有界上下文实现中,客户实体上都存在的属性(
    收件人
    付款人
    )。即
    名称
    。关于冗余验证:由于模型应具有丰富的实现(自验证和不变安全),因此这两个实体中的
    名称
    属性都存在验证。