第十四章 保持模型的完整性

本文探讨了领域驱动设计(DDD)中的核心模式,包括边界上下文、持续集成、上下文图等,解释了为何及如何应用这些模式解决大型系统开发中的模型分裂、集成难题,以及团队间沟通障碍。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、大型系统领域模型的完全统一既不可行,也不划算

why?
1、一次尝试对遗留系统做过多的替换

2、大项目可能会陷入困境,因为协调的开销太大,超出了这些项目的能力范围

3、具有特殊需求的应用程序可能不得不使用无法充分满足需求的模型,而只能将这些无法满足的行为放到其他地方

4、另一方面,试图用一个模型来满足所有人的需求可能会导致模型中过于复杂的选择,而难以使用。

 

二、模式:BOUNDED CONTEXT(边界上下文)

why?

任何大型项目中都会存在多个模型,而当基于不同模型的代码组合到一起后,软件就会出现bug,变得不可靠和难以理解。团队成员之间的沟通变得混乱。人们往往弄不清楚一个模型不应该在哪个上下文中使用。

将不同模型的元素组合到一起可能会引发两类问题:1)重复的概念,两个模型元素实际上表示同一个概念。每当这个概念的信息发生变化时,都必须更新两个地方。否则会出现同一个概念的两个版本,它们遵守不同的规则,甚至有不同的数据。2)假同源,使用相同术语的两个人认为它们在讨论同一件事情,但实际上并不是这样的。

how?

明确地定义模型所应用的上下文。根据团队的组织,软件系统的各个部分的用法以及物理表现(代码和数据库模式等)来设置模型的边界。在这些边界中严格保持模型的一致性,而不要受到边界之外问题的干扰和混淆。

 

三、模式:CONTINUOUS INTEGRATION(持续集成)

why?

当很多人在同一个BOUNDED CONTEXT中工作时,模型很容易发生分裂,团队越大问题越大,然而如果将系统分解为更小的CONTEXT,最终又难以保持集成度和一致性。

概念:持续集成是指把一个上下文中的所有工作足够频繁地合并到一起,并使它们保持一致,以便当模型发生分裂时,可以迅速发现并修改问题。分为两个级别的操作:1)模型概念的集成2)实现的集成。

how?

建立一个把所有代码和其它实现工件频繁合并到一起的过程,并通过自动化测试来快速排查模型分裂问题。严格坚持使用UBIQUTIOUS LANGUAGE,以便在不同人的头脑中演变出不同的概念时,使所有人对模型都能达成一个共识。

例如大多数敏捷开发每天会把开发人员所做的修改合并进来。极限编程。

 

四、模式:CONTEXT MAP(上下文图)

why?

BOUNDED CONTEXT之间的代码重用是很危险的,应该避免。功能和数据的集成必须通过转换去实现。通过定义不同上下文之间的关系,并在项目中创建一个所有模型上下文的全局视图,可以减少混乱。

how?

可以通过画草图来实现。不必拘泥于形式。

 

五、模式:SHARED KERNEL

why?

不同团队开发一些紧密相关应用时,如果团队之间不协调,尽管短时间内能够取得快速进展,但它们开发出的产品可能无法结合到一起。最终不得不耗费大量精力在转换层上。所以应该一开始就用持续集成。

how?

从领域模型中选出两个团队都同意共享的一个子集。除了这个模型子集外,还包括与该模型部分相关的代码子集,或者数据库设计的子集。这部分明确共享的内容具有特殊地位。一个团队在没与另一个团队商量的情况下不应该擅自改动它。

如果系统要经常集成,但集成的频率应该比团队中CI的频率要低。在进行这些集成的时候,两个团队都要运行测试。

概念:SHARED KERNEL通常是CORE DOMAIN。或是一组GENERIC SUBDOMAIN,也可能二者兼有,它可以是两个团队都需要的任何一部分模型。使用SK的目的是减少重复,并使两个子系统之间的集成变得相对容易一些。

example:之前项目中的parent项目。作为最底层的依赖,放置一些datetutils之类。

 

六、模式:CUSTUMER/SUPPLIER DEVELOPMENT TEAM

概念:一个子系统主要服务于另一个子系统;“下游”组件执行分析或其他功能,这些功能向“上游”组件反馈的信息很少,所有依赖都是单项的。两个子系统通常服务于不同的用户群,执行的任务也不同,这时上游和下游子系统自然分割到两个不同BOUNDED CONTEXT 之中。

why?

如果下游团队对变更具有否决权,或请求变更得程序太复杂,那么上游团队的开发自由度会受到限制。由于担心破坏下游系统,上游团队甚至会受到抑制。同时由于上游团队掌握优先权,下游团队有时也会无能为力。

how?

在两个团队之间建立一种明确的客户/供应商关系。在计划会议中,下游团队相当于上游团队的客户。根据下游团队的需求来协商需要执行的任务并未这些任务做预算,以便每个人都知道双方的约定和进度。

两个团队共同开发自动化验收测试,用于检验预期的接口。把这些测试添加到上游团队的测试套件中,以便作为其持续集成的一部分来运行。这些测试使使上游团队做出修改时不必担心对下游团队产生副作用。

 

七、模式:CONFORMIST(遵循)

why?

当两个开发团队具有上、下游关系时,如果上游团队没有动力来满足下游团队的需求,那么下游团队奖无能为力。处于利他主义考虑,上游开发团队可能会做出承诺,但可能不会履行承诺。下游团队出于良好的意愿会相信这些承诺,从而根据一些永远不会实现的特性来制定计划。下游项目只能搁置,直到团队最终学会利用现有条件自力更生为止。下游团队不会得到根据他们的需求而量身定做的接口。

how?

通过严格遵循上下游团队的模型,可以消除在BOUNDED CONTEXT之间进行转换的复杂性。尽管这些会限制下游设计人员的风格,而且可能不会得到理想的应用程序模型,但选择CONFORMIST模式可以极大地简化集成。此外,这样还可以与供应商团队贡献UBIQUITOUS LANGUAGE。供应商处于统治地位,因此最好使沟通变得容易。他们从利己主义的角度出发,会与你分享信息。

 

八、模式ANTICORRUPTION LAYER(隔离层),以下建成AL

why?

一个大型项目中,子系统通常必须与其它独立开发的子系统连接,这些子系统将从不同角度反映问题领域。当基于不同模型的系统被组合到一起时,为了使新系统符合另一个系统的语义,新系统自己的模型可能被破坏。

how?

创建一个隔离层,以便根据客户自己的领域模型来为客户提供相关功能。这个层通过另一个系统现有接口对话,而只需要将那个系统作出很少的修改,甚至无需修改。在内部,这个层在两个模型之间进行必要的双向转换。它是在不同的模型和协议之间转换概念对象和操作的机制。

AL的公共接口通常是一组SERVICE的形式出现,但偶尔也会采用ENTITY的形式。对AL设计进行组织的一种方式是把它实现为FACECADE、ADAPTER两种设计模式和转换器的组合,外加两个系统之间进行对话所需通信和传输机制。 

 

九、模式:SEPRATE WAY(各行其道)

why?

如果两个功能部分并不需要相互调用对方的功能,或者这两个部分的对象并不需要进行交互,或者他们操作期间不共享数据,那么继承可能是没有必要的。

how?

声明一个与其它上下文毫无关联的BOUNDED CONTEXT,使开发人员能够在这个小范围内找到简单、专用的解决方案。

 

十、模式:OPEN HOST SERVICE

why?

但一个子系统必须与大量其它系统集成时,为每个集成都定制一个转换层可能会减慢团队的工作速度。需要维护的东西会越来越多,而且进行修改的时候担心的事情也会越来越多。

how?
定义一个协议,把你的子系统作为一组SERVICE提供给其它系统访问。开放这个协议,以便所有需要与你子系统集成的人都可以使用它。当有新的集成需求时,就增强并扩展这个协议,以便使共享协议简单且内聚。

 

十一、模式:PUBLISHED LANGUAGE

两个BOUNDED CONTEXT之间的模型转换需要一种公共的语言。比如XML或者JSON或者CML(化学标记语言)

 

十二、选择你的上下文策略

why?
团队必须决定在哪里定义BOUNDED CONTEXT,以及它们之间的关系。这些决策必须由团对作出,或者至少传达给整个团队,并被团队里的每个人理解。

how?

置身上下文中,典型情况下,设计中的系统将被划分为一到两个BOUNDED CONTEXT,开发团队的主力将在这些上下文中工作,或许还有一到两个起支持作用的CONTEXT,除此之外就是这些CONTEXT与外部之间的关系。

转换边界。首先选较大的BOUNDED CONTEXT因素(1、但用一个模型来处理更多任务时,用户任务之间的流动跟顺畅;2、一个内聚模型比两个不同模型再加上他们之间的映射更加容易理解;3、两个模型之间的转换可能会很难有时甚至是不可能的;4、共享语言可以使团队沟通起来更清楚),首选较小的BOUNDED CONTEXT因素(1、开发人员之间的沟通开销减少了;2、由于团队和代码规模较小,CONTIUOUS INTEGRATION更容易了;3、不同的模型可以满足一些特殊的需求,或者是能够把一些特殊用户群的专用术语包括进来)。

与外部系统的关系,可以应用三种模式:各行其道,隔离层,遵循。

十三、合并CONTEXT

why?

翻译开销过高、重复显现明显。。。。

how?

1、评估状况,确定需要合并;2、建立合并过程,决定代码的共享方式和模块采用那种命名的约定;3、选择某个小的子领域作为开始;4、从两个团队的开发人员中选出2-4个开发人员组成一个小组,由他们为子领域开发一个共享的模型;5、来自两个团队的开发人员一起负责实现模型,确定细节并使模块开始工作;6、每个团队的开发人员都承担新的share kernel集成的任务;7、清除一些不必要的翻译。

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值