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
收件人
和付款人
聚合都由上下文边界完全分隔。他们也有自己的存储库
问题:
使用同一个“数据库表”进行多个聚合(前提是它们位于单独的有界上下文中)是否可以接受
客户数据可能在许多更为有限的环境中需要。这是否意味着每个有界上下文都有许多聚合、存储库和工厂实现?代码中会有一定程度的冗余。这不影响可维护性吗
是否可以在集合中共享属性?例如customerName
属性。这也意味着冗余的验证代码
答案:
1.如果聚合及其存储库为只读,则为“是”。如果一个人单独更改模式或数据而不通知其他人,那么在有界上下文之间共享存储和模式可能会有问题,但我认为在这种情况下这不是一个大问题
但如果收款人和付款人是可编辑的,则情况就不同了。有可能修改它们,这会在有限的上下文中产生影响。例如,客户可能需要更改特定发货订单的地址,但共享cutsomer表可能会在不通知的情况下更改客户发货订单的所有地址。所以最好为它们使用不同的存储空间
2.不同的有界上下文需要客户的不同方面。我认为只依赖必要的数据是一种好的做法,因此聚合抽象可能会有所不同。潜在的可维护性问题可能发生在实现端(主要是因为代码重复)。因此,我们可以引入一个额外的组件来返回客户的所有方面,并在其上构建特定于上下文的有限适配器。Q&A
1) 使用同一个“数据库表”进行多个聚合(前提是它们位于单独的有界上下文中)是否可以接受
- 只要您遵循管理共享状态的严格策略,我就可以接受李>
- DDD可以接受,因为域被认为比数据更重要李>
- 只要在不引入(太多)隐性成本的情况下完成工作,客户就可以接受李>
2) 客户数据可能在许多更为有限的环境中需要。这是否意味着每个有界上下文都有许多聚合、存储库和工厂实现?代码中会有一定程度的冗余。这不影响可维护性吗
不一定,看一看
3) 是否可以在集合中共享属性?例如customer Name属性。这也意味着冗余的验证代码
答案与问题1相同。关于冗余,一旦您有了一个共享内核,您就可以简单地将验证器类放在其中
关于DRY和DDD之间的冲突:
优雅的代码不会不必要地使伟大的设计原则相互冲突。通常有一种方法可以满足这些原则。你只是还没有找到它,因为要么你对原理理解不够,要么你对问题剖析不够
(如果这听起来很教条,那是因为软件工程实际上是一种宗教)您能解释一下问题3中的“共享属性”和什么是“冗余验证代码”吗?关于共享属性:在两种有界上下文实现中,客户实体上都存在的属性(收件人
和付款人
)。即名称
。关于冗余验证:由于模型应具有丰富的实现(自验证和不变安全),因此这两个实体中的名称
属性都存在验证。