点击下方“JavaEdge”,选择“设为星标”

第一时间关注技术干货!

免责声明~ 任何文章不要过度深思! 万事万物都经不起审视,因为世上没有同样的成长环境,也没有同样的认知水平,更「没有适用于所有人的解决方案」; 不要急着评判文章列出的观点,只需代入其中,适度审视一番自己即可,能「跳脱出来从外人的角度看看现在的自己处在什么样的阶段」才不为俗人。 怎么想、怎么做,全在乎自己「不断实践中寻找适合自己的大道」

1 简介 1.1 什么是上下文映射(Context Mapping)

指限界上下文之间的模型映射关系。描述团队之间的协作关系及上下文之间的集成关系。决定上下文之间如何集成及如何设置防腐层。

1.2 为何需要上下文映射?

尽管我们拆分了系统,它们终究还是一个系统,免不了交互。比如:

  • 一个用户下了订单,这是在订单上下文中完成的

  • 用户要去支付,这是在支付上下文中完成的

我们要通过某种途径让订单上下文的一些信息发送到支付上下文。所以,要有一种描述方式,描述不同限界上下文之间交互的方式-上下文映射图(Context Map)。

这么多交互方式,主要是为让你在头脑中仔细辨认,看看限界上下文之间到底在以怎样的方式交互。

知道不同限界上下文之间交互方式后,不同交互方式就可落地为不同协议。常用协议如:REST API、RPC 或是 MQ, 按需选型即可。

在我们定义好不同的限界上下文,将它们之间的交互呈现出来之后,就得到了一张上下文映射图。上下文映射图是可以帮助我们理解系统的各个部分之间,是怎样进行交互的,建立全局性认知。

日常开发很常见问题,由于限界上下文,当我们不同上下文之间需要交互时,如何将同一概念模型进行映射呢?就需要上下文映射。

2 上下文映射模式
打开网易新闻 查看精彩图片
2 上下文映射模式

DDD提供描述这种交互的方式,如:

2.1 开放主机服务(Open Host Service)

服务提供方为所有消费方提供一套公共API,如各种云服务组件,直接提供API。云服务商不会为你单独定制 API,所以这种只针对通用功能和模型。如支付上下文,我们都会引入通用的微信公共支付API。

打开网易新闻 查看精彩图片

会定义一套协议或接口,让限界上下文可被当作一组服务访问。

该协议是“开放的”,所有需要与限界上下文进行集成的客户端都能轻松使用它。通过API提供的服务都有详细文档,用着也舒服。

即使处在类似图中团队2的位置,也没有时间在这端的集成中创建隔离用的防腐层,和遗留系统相比,作为团队1模型的跟随者更容易被接受。开放主机服务的语言比其他类型的系统语言更易用。

打开网易新闻 查看精彩图片
2.2 跟随者/顺从者/尊奉者(Conformist)
打开网易新闻 查看精彩图片

存在于上游团队和下游团队间,上游团队无任何动机去满足下游团队具体需求。由于各种原因,下游团队也无法投入资源去翻译上游模型的通用语言来适应自己的特定需求,因此只能顺应上游模型,即允许它(上游)对你(下游)的侵入。

特点

  • 没有模型到模型转换

  • 一个上下文沿用另一个上下文的部分模型

案例

当一个团队需要与一个庞大复杂的模型集成,且该模型已很成熟,团队往往会成为其跟随者。如在作为亚马逊联盟的卖家进行集成时,就需要考虑遵循 Amazon.com 的模型。

或由外部公司和主体提供的中台服务功能,无法定制化,只能顺从。

2.3 大泥球(Big Ball of Mud)

要规避!

由混杂的模型构成的糟糕系统,模型不稳定且难于维扩。

在处理大泥球或者要和它进行集成时可能面临的严重问题。制造大泥球这种事应该人人避之唯恐不及:

打开网易新闻 查看精彩图片

假如这还不够让你警醒,下面描述的是如何一步一步把系统推向大泥球深渊:

  • 越来越多的聚合,因为不合理的关联和依赖而交叉污染

  • 对大泥球的一部分进行维护就会牵一发而动全身,解决问题就像在“打地鼠”

  • 只剩下“部落知识”和“个人英雄主义”,唯有同时“讲”出所有语言的极个别“超人”方能扶大厦之将倾

打开网易新闻 查看精彩图片

问题是,大泥球已经遍布于世界上的软件系统中,这个数量还铁定会逐月增长。即使通过 DDD 避免创建自己的大泥球,仍可能不得不与它们集成。

解决方案

若必须与一或多个这样的大泥球系统集成,请针对每个这样的遗留系统创建一个防腐层,保护自己模型免受污染,否则会陷入难以理解泥潭。

2.4 防腐层(Anticorruption Layer)

最具防御性的上下文映射关系,下游团队在其通用语言(模型)和位于它上游的通用语言(模型)之间创建个翻译层。防腐层隔离下游模型与上游模型,并完成二者间翻译。

但凡有可能,就该尝试在下游模型和上游集成模型之间创建防腐层, 才可以在你这端的集成中创造出特别适配业务需求的模型概念,并将外部概念完全隔离。

然而,就像为两个讲不同语言的团队雇佣翻译来解决沟通问题,有时各方面成本业水涨船高。

打开网易新闻 查看精彩图片

把上游上下文的模型转换成自己上下文的模型

  • 是下游上下文中访问外部模型的一个代理层

  • 打开网易新闻 查看精彩图片
    适用场景
    • 与遗留系统对接

    • 和大泥鳅系统对接

    • 对旧系统重构时

    2.5 共享内核(Shared Kernel)
    打开网易新闻 查看精彩图片

    两个(或更多)团队之间,共享一个小规模但却通用的模型。团队必须就要共享的模型元素达成一致。有可能它们当中只有一个团队会维护、构建及测试共享模型的代码。

    共享内核通常一开始很难理解,也难维护,因为团队之间沟通须完全开放,而且他们必须就共享模型的构成不断地达成一致。但只要所有参与者都认同共享内核比各行其道的方式更好,就有可能获得成功。

    方式

    常见方式就是将通用模块通过二进制依赖(如 JAR 包或链接库)共享给所有上下文使用。持续地就修改进行开放式沟通并达成一致很困难,效率也很低,但蓬勃发展的开源软件社区却给我们做出表率。大部分开源软件都以二进制库的形式发布,开发者们也很难有直接面对面的沟通机会,但它们的发展和演进一点也不慢。开源软件开发者们会使用各种约定和相应实践进行沟通协作,使用 GitHub 的拉取请求( Pull Request )来审查代码并接受贡献或使用长期支持版本( Long Term Support,LTS )保持固定发布节奏给下游预留升级时间,又或是使用语义化版本( Semantic Version )向下游宣告破坏性修改。因此,越来越多的企业向开源社区学习,搭建基础设施和平台,建立企业的内部开源社区来开鼓励开发团队更高效地进行跨团队的协作。

    Java 开发经常喜欢开发一些 core 服务,给到其他服务集成使用。

    两个上下文共享部分模型,包括但不限于代码、jar包、.so、数据库表等。慎用,仅当团队紧密合作且共享部分稳定。

    而对这种很紧密的团队关系,也称为:

    2.6 合作关系(Partnership)

    技术无关,是一种团队协作关系。两个团队之间可以随时互通有无,协同变更。

    关系存在于两个团队之间。每个团队各自负责一个限界上下文。两个团队通过互相依赖的一套目标联合起来形成合作关系。一损俱损,一荣俱荣。

    由于相互之间联系紧密,他们经常会面对同步日程安排和相互关联工作 ,他们还必须使用持续集成对保持 成工作协调一致。两个团队之间的一致步调使用粗的映射线段表示。粗线段表示两个团队彼此需高度承诺。

    保持长期的合作关系很有挑战性,因此许多进入合作关系的团队可能尽最大努力为这种关系设置一个期限。只有在能发挥彼此优势时才维持合作关系,而随承诺消失,这些优势不复存在,而这种合作关系应被重新映射成另外的一种关系。

    打开网易新闻 查看精彩图片

    描述的是两个限界上下文间和两个独立团队间的关系:

    • 供应商位于上游(图中的U )

    • 客户位于下游(图中的D)

    支配这种关系的是供应商,因为它必须提供客户需要的东西。客户需要与供应商共同制订规划来满足各种预期,但最终却是由供应商决定客户获得的是什么及何时获得。即便是来自于同一个组织的团队,只要企业文化不允许供应商完全自治或无视客户的实际需求,客户一供应商关系也是一种非常典型且现实的关系。

    • 下游上下文可以向上游上下文提需求

    • 一般用于核心域与非核心域之间的协作

    和共享内核的映射关系一样,保持客户和供应商之间持续开放的沟通也很重要,持续沟通才能保障供应商按照客户的预期提供集成所需的接口。存在这种集成关系的团队常常会采用一种被称为消费者驱动契约( Consumer Driven Contract, CDC )的实践,通过契约测试来保证上游(生产者或供应商 和下游 (消费者或客户〉之间的协作。而利用 些工具(如 Pact ,客户可以在进行测试时,将对供应商接口的期记录下来,并将其变成供应商的接口测试,作为供应商持续 成流水线的一部分持续地进行验证。这样供应商可随时了解自己提供的接口实现是否满足客户期望。

    和中台的协作关系是什么模式呢?中台应该是公司中姿态较低的,服务于业务方的,所以属于客户-供应商模式。中台的价值最终也只可能体现在业务上。由于中台需要服务多个业务方,自然就很可能成为大泥鳅,模型很难稳定下来,所以设计需要极强的经验。若中台能力实在太差,形同虚设,就可能出现如下模式:

    打开网易新闻 查看精彩图片

    也叫分道扬镳。

    意味着两个上下文之间根本没有关系,无需控制,也不需要承诺。在一个复杂的模型,存在着许多上下文,而大部分上下文之间应无直接依赖关系的。如账户子域(上下文)和物流子域(上下文)之间就没有直接联系。如果任何两个上下文之间都有直接联系,整个模型就要走向大泥球。两个上下文之间没有任何依赖,自由地独立演进,这应该是我们最希望的。因此,在可能情况下,我们应该把两个上下文分开,让它们各行其道。

    使用各种通用语言来与一个或多个限界上下文集成这样的方式不能产生显著回报。也许你所寻求的功能并不能由任何一种通用语言提供。此时,只能在限界上下文中创造属于自己的特殊解决方案,并放弃针对这种特殊情况的集成。

    特点

    • 两个上下文无协作,各自独立

    • 当两个上下文之间的集成成本过高

    适用场景
    • 新系统开发时,由于集成旧系统就很难了,就会放弃,完全自主研发,之后再完全下线老系统

      打开网易新闻 查看精彩图片
    2.9 公开语言(Published Language)
    打开网易新闻 查看精彩图片
    • 标准化与协议化的模型

    • 所有上下文都可以与公开语言中的模型进行转换

    • 对接了公开语言的上下文之间可以实现组件化对接

    案例
    • 蓝牙协议、tcp/ip

    • Java生态的jdbc、jvm标准等

    • SQL

    最终可设计得到我们的零售系统的上下文映射:

    3 总结
    打开网易新闻 查看精彩图片
    3 总结

    上下文、团队之间的关系,重叠模型的映射关系。清楚模式,才能清晰自己的定位。

    公众号:JavaEdge 专注分享软件开发全生态相关技术文章、视频教程资源、热点资讯等,如果喜欢我的分享,给 点一个赞 或者 ➕关注 都是对我最大的支持。

    欢迎长按图片加好友,我会第一时间和你分享软件行业趋势面试资源学习途径等等。

    添加好友备注【技术群交流】拉你进技术交流群

    关注公众号后,在后台私信:

    • 更多教程资源应有尽有,欢迎关注并加技术交流群,慢慢获取