上下文映射图的两种表示方式

方式一:画一个简单的框图来表示两个或多个限界上下文之间的映射关系。(优点:简单)

方式二:通过限界上下文集成的源代码实现来表示。(优点:详细)

上下文映射图的作用

首先,在绘制上下文映射图的过程中,可以促使你更好的分离限界上下文,并识别出语言边界。可以更清楚的识别出当前项目中的限界上下文和其依赖的限界上下文之间的关系

其次,通过上下文映射图,可以反映出与外部系统或者团队之间的集成关系,并且可以指明在哪些地方需要与其他团队进行交流。以上面的例子中,针对支付&结算上下文以及用户&会员上下文这两部分,我们其实可以引入第三方服务,这样借助它们已有的能力,也可以节约我们的研发成本。通过上下文映射图对其关系的展现,可以很直观的看到我们与外部团队之间的集成关系。

第三,如果我们依赖了其他团队的接口,但是该团队并不是与你合作的关系,而只是一种提供现有接口,让你去使用,使你被迫的成为了一种遵奉者的模式。那么,通过上下文映射图,可以迫使我们更清晰的认知到这种情况,并如何去处理与对方的关系,是协调?还是继续遵奉?还是自己开发?

如何绘制上下文映射图

上下文映射图表现的是项目当前的状态,暂时不比为将来的变化做考虑。那这个时候就有同学会疑问,为什么不考虑将来呢?只考虑现在是不是眼光太短浅了呢?其实不是这个样子的,我们绘制上下文映射图的目的其实就是要明确当前系统中上下文直接的关系和状况,帮助我们决定下一步该怎么走

绘制上下文映射图不用太正式,只要能清晰的表明上下文之间的关系就可以了。上下文映射图不是企业架构也不是系统拓扑图。它可以基于更高的维度发现系统中存在的系统架构问题(eg:哪些系统造成了系统集成的瓶颈)或有碍项目进展的管理问题。上下文映射图可以画在一个显著的位置,这样团队的每个成员都可以清晰便捷的看到。

组成上下文映射图的元素中,包括如下几部分:

  • 限界上下文
  • 限界上下文之间的关系,即:上游(U:Upstream)和下游(D:DownStream)
  • 负责相应限界上下文的团队
  • 上下文之间的集成关系,即:发布-订阅、遵奉者、合作关系、防腐层……
  • 必要的翻译 ... ...

上面的元素都是针对于上下文之间的,即:上下文映射图。那么针对于上下文内部,如果我们想要加入更多的细节,会涉及到如下几部分:

  • 聚合、实体、值对象
  • 模块
  • 团队的分布信息 ... ...

组织和集成关系

合作关系

看过《跑男》的同学们应该熟悉这个画面,当撕名牌的时候,面对大黑牛李晨,相对弱小的队员们就会采取组队结盟的方式,来共同“抗击”强者。在DDD中,也存在这种关系,对于一个产品的成功,需要两个技术团队协同合作,即:一损俱损,一荣俱荣。那么就会催化出合作关系,大家一同协调彼此的研发计划和团队管理工作,为同一个目标共同努力。在此模式下,两个团队在迭代开发上面的沟通会非常的频繁,因为只有同步了大家的研发计划,才可以保障能够在同一个迭代中发布新的功能或对旧的功能进行修复。

共享内核

在某些情况下,两个团队间有一部分共同的功能,那么针对这部分,就称之为共享内核。因为对于这部分是共同影响了两个团队,所以,对于共享内核的边界性就会要求很高。也就是说,每当团队彼此要跨入共享内核边界内的话,都是需要两个团队共同协商的,而不能仅仅由某一个团队只针对于自己功能进行对共享内核的修改。这种情况会比较特殊,一般来说,这种偏共享的部分会在后续的系统演变中被抽象化为平台服务,即:一种类型的支撑子域,并且由某一个指定的研发团队专门对这部分服务进行推进和维护。

对于共享内核来说,其产生的最主要原因还是在于对研发成本的节约对研发效率的提升,并且可以有效的防止多个团队之间去重复的“造轮子”。通过对相同业务或功能的代码维护,使其越来越平台化。其实在我们的生活中也不乏共享思维,从高层次的国家提出的“共享经济”,再到随处可见的共享单车、共享汽车、共享充电宝、共享雨伞、共享办公区等等。

客户方与供应方

假如我们是一家奶制品厂,无论是我们要生产奶油还是奶粉,都需要有饲养奶牛的牛场给我们提供足够的新鲜牛奶,这样我们才能够继续的生产奶制品。如果我们所依赖的上游牛场不在意我们对牛奶的需求量,就有可能会造成牛奶供给不足的情况,导致下游奶制品厂无法顺利投产。所以,当出现客户方与供应方关系的时候,对于上游的供应方,应该顾及到下游客户方的团队,以免对下游团队的开发迭代进度造成较大影响。

遵奉者

但是,在我们上面介绍的客户方与供应方关系下,有一种“不太好的坏味道”,就是遵奉者关系。为什么这是不太好的味道呢,就是因为在这个模式下,上游团队并不在意下游团队的需求,你想用我的东西,你就需要遵守且“侍奉”我。类似于我们去医院看病,一些比较有名气的那种大医院经常人满为患,大医院不会太在意你等待多么焦急,身体指标检查需要排多久的队,医院的休息座椅是否足够,医生开出来的检测项目是否需要好几天才能陆续的做完等等。再或是现在疫情期间,住院的病人和陪护的家人都会被严格控制在病房内,不能随意出入走动。那么,你要是想治病,就必须要“遵奉”医院的要求。

不过事情也都有两面性的。当上游供应方需要为大量客户方提供服务的时候,往往通过指定规则让客户方去遵守,才可以保障自己后续合理的发展,例如:支付宝、微信小程序开发平台等等。

防腐层(ACL)

防腐层就类似于我们设计模式中的适配器模式,当两个团队在上面提到的各种合作模式中,如果彼此开发差异较大,或者需要很多工作进行翻译适配,那么防腐层就有了它独特的作用。它负责两个团队接口之间的融合翻译工作。使得上游系统和下游系统都不需要太大的改动,因为改动都放在了防腐层中。

我们可以在防腐层中去定义相应的领域服务(Domain Service),也可以在防腐层中定义资源库接口

比如:下游系统要获得商城中的会员用户信息,上游接口的PL可能返回的是xml格式或者json格式,那么在防腐层中将其翻译转化为UserInfo对象,该对象是一个值对象,可以供下游系统直接使用。

开放主机服务&发布语言(OHS & PL)

开放主机服务与发布语言其实是搭配使用的,在实际项目中,上游系统提供api接口(其中包括RPC、HTTP等),并在通信过程中确定数据的格式化方式,使用xml还是json还是protobuff等等,或者是上游系统自己定义的一种序列化和反序列化格式协议。上游系统公开自己的服务协议后,任何想要接入的下游系统在遵循上游协议后,都可以快速的集成进来。

通常来讲,我们可以将开发主机服务看成是RPC的API。同时,它也可以通过消息机制实现。

根据不同的OHS,我们可以选择不同的PL:

  • 在使用RESE服务时,我们可以使用XMLJSONProtocol Buffer等。
  • 如果你打算发布Web用户界面,也可以使用HTML
  • 发布语言也可以用于事件驱动架构,其中领域事件(Domain-Event)会以消息的形式发送到订阅方。

我们可以在绘制上下文映射图时,将使用的某种组织和集成关系标注上去,下面以ACL、OHS和PL为例:

【解释】图中的字母U(上游:UpStream)和字母D(下游:DownStream)显式地指出了限界上下文之间的关系。有了这些字母标签,上下文在图中的位置关系就不那么重要了,但是,这些位置关系依然能给我们营造一种好的视觉效果。

另谋他路

从上面各种关系可以看到,两个团队无论采取何种关系去集成,其付出的代价都是不可避免的。那么,我们在集成之前,就应该好好的考虑一下,集成的必要性大不大。如果集成后带来的优势并不明显,那么我们就可以去思考其他解决办法去达到一定的目的。例如,我们的服务或系统需要获得某些权限判断,但是这种权限并不复杂,只是针对会员和非会员的权限验证,那么假设其他团队维护了一个比较复杂的权限系统,例如:根据不同的用户角色,控制不同的菜单展现或也没内容展现等等。在我们接入过程中,对方团队也无力配合我们,体现出了一种遵奉者模式关系,那么这种集成的必要性就不大了。因为我们的权限控制很简单,自己实现灵活度会更高,或者选择其他的更符合我们需求的权限控制服务等等。

大泥球

一般来说,如果我们负责的是一个全新开发的系统,那么它的边界和上下文一般都会比较清晰。而对于遗留系统,或者发展了好几年的老系统来说,它内部的边界一般来说都是比较模糊的,而面对这种大泥球系统,才是我们日常开发中经常会遇到的情况。那么,当我们遇到这种情况后,怎样去做呢?首先,不用试图去使用复杂的建模手段来化解问题,因为这样有可能会让原本轮乱的系统更复杂。其次,我们应该为整个系统绘制一个边界。这个边界是干什么用的呢?就是当我们判断一个系统或者功能属于这种“大泥球”时,就将其放到边界内,因为这样的系统有可能会向其他系统蔓延,我们应该通过这种边界来防止这种蔓延情况发生

上下文映射图在项目中的应用

高层面确定上下文映射图

比如在创建电子商城网站最初,我们考虑要有一个商品展示且可以售卖的功能,那么最初通常由于研发团队规模小,为了应对快速的开发迭代,代码都是在一个项目中进行开发维护的,如下所示:

但是,随着开发迭代的进行中,我们发现,如果再这么继续下去,就会变成我们上面提到的“大泥球”了,那么这种情况,是团队任何人员都不希望发生的。所以,团队小伙伴们坐在一起,研发同学和领域专家一起商量如何对子域进行划分,以及哪些是我们的核心域。通过讨论后,大家目前将其分为了订单上下文、商品上下文、库存上下文。在这些上下文中,库存上下文中除了对商品的采购和维护之外,还包含了采购策略,商品销售趋势预测等功能,而这部分能力的高低,会直接影响到商城上面的售卖,所以,库存上下文被认定为核心域,而订单上下文和商品上下文,被确定为支撑子域

这时有同学会问,怎么没有用户和会员上下文呢? 当然,随着商城的发展,用户&会员、权限、支付、结算、账户等等都会陆续的建立起来,但是由于目前我们的研发任务中只涉及了订单、商品和库存上下文,而对于上下文映射图只是反映当前系统情况的,对于未来的部分内容,当演变到那个阶段之后,再向上下文映射图中进行添加。

好了,既然确定好了这三部分子域,由于子域和上下文最好是一对一的,所以,就从之前一个“电子商城上下文”,拆分出了“库存上下文”、“商品上下文”和“订单上下文”这三个限界上下文了。具体如下所示:

确定了三个限界上下文之后,根据整体的业务流程,我们可以分析出商品上下文是订单和库存两个上下文的上游,因为都需要调用它所提供的接口去查询商品信息;而在库存上下文和订单上下文之间,很明显,只有当某个商品存在库存的时候,才会产生订单执行售卖行为,并且同时每当卖出去商品或者商品退货,都会对这个商品的库存进行影响。所以,库存上下文就作为了上游,而订单上下文就作为了下游。而在组织和集成关系部分中,我们介绍了9种关系,经过研发团队成员直接的沟通,决定上游采取开发主机服务+发布语言,即:OHS/PL,对于下游,则采取防腐层(ACL)的方式,进行PL与值对象之间的翻译工作。具体如下所示:

底层面分析内部细节

既然上面我们确定了库存上下文是核心域,那么我们库存上下文和以商品上下文为例,库存需要获取商品信息,那么对于上游商品上下文来说,需要提供商品相关接口。在系统集成中,可以选择RPC、REST、异步消息、领域事件等等,这个可以根据实际情况来选择。在本例中,商品上下文团队选择了基于REST的方式,而在PL上面,选择了JSON的方式对外提供数据格式。那么库存团队除了要对接商品上下文相关接口之外,还需要对获得的数据进行“转译”操作。比如,库存上下文需要获取一个商品的详细信息,那么商品上下文所返回JSON格式如下所示:

{"id": "1239838924892342","name": "AirPods Pro","color": "白色","introduction": "商品简介内容巴拉巴拉","detail": "商品详情巴拉巴拉",... ...
}

那么在防腐层中,会执行转译操作,即将JSON映射到本地模型中的值对象,如下所示:

public class Commodity {private Long id;private String name;private ColorEnum color;private String introduction;private String detail;... ...
}

细心的同学们可能发现了,这里记录颜色使用的是ColorEnum,为什么要使用枚举类型呢?用String不也一样嘛?是的。在技术实现上是这样的。但是,对于颜色,属于常量属性,那么我们通过状态模式(State Pattern)维护一套颜色常量,在这种设计中,会由ColorEnum定义的状态对象将对值对象Commodity起到保护作用

当然,这种转译过程其实不仅仅是将JSON中的值复制到Commodity值对象中,比如从JSON中获得属性A的值,然后在防腐层中,进行一些逻辑处理,可能就会变成值对象中属性B、C、D三个值。转译的含义会比较宽泛,希望大家不要误解为仅仅是对属性值的复制就好了。

作为库存上下文,如果想要更高的自治性,就需要控制对RPC使用的欲望,而尽量选择异步请求或者事件处理等方式。上游系统将下游需要的信息传输过来并通过防腐层进行翻译换成领域对象时,针对这个对象应该只保留最小状态集,因为此后会涉及到与远程模型的数据同步,如果承担了远程对象的过多特征属性,从而在不经意间会导致一种“杂交”状态。

对于数据同步,既可以采取状态数据回调,也可以采取消息队列,或者是通过服务总线BUS进行状态发布,具体采取哪种方式,大家可以根据实际情况进行选择。

如果要展示更细节的设计,可以以领域服务和接口的维度进行展示,如下所示:

在上面的介绍中,我们其实发现了一点,就是关于Commodity,它其实即存在于商品上下文中,也存在于库存上下文中。那么,有什么区别呢?其实只是名字相同而已,它们的类型和示例对象都是不同的,因此Commodity在两个上下文中的状态和行为也是不同的。在商品上下文中,Commodity是一个聚合,它管理一系列的Post;而在库存上下文中,Commodity只是一个值对象,它维护了对协作上下文中某个Commodity的引用。

今天的文章内容就这些了:

写作不易,笔者几个小时甚至数天完成的一篇文章,只愿换来您几秒钟的 点赞 & 分享 。

更多技术干货,欢迎大家关注公众号“爪哇缪斯” ~ \(^o^)/ ~ 「干货分享,每天更新」

(三)DDD上下文映射图——老师,我俩可是纯洁的男女关系!相关推荐

  1. DDD—上下文映射图

    一个项目的上下文映射图(Context Map)可以用两种方式表示, (1)比较容易的一种是画一个简单的框图来表示两个或多个限界上下文之间的映射关系.该框图表示了不同的限界上下文在解决方案空间中是如何 ...

  2. DDD 实战 (5):限界上下文映射和系统分层架构

    在完成了限界上下文的识别(也就是系统"最粗粒度"的模块划分)后,我们需要对这些上下文之间的协作关系进行分析--即"限界上下文关系映射".也只有在完成上下文关系映 ...

  3. DDD-上下文映射图

    上下文映射图-Context Map-包含项目的限界上下文和他们之间的集成关系. 两种基本的集成关系:上游upstream和下游downstream. 组织模式和集成模式的定义: 合作关系(partn ...

  4. ddd java 例子_【Java】DDD思维导图

    首页 专栏 java 文章详情 0 DDD思维导图 洪永佳发布于 今天 10:07 常见相关问题 DDD概念 DDD,全称Domain-Driven Design, 是一种处理复杂领域的设计思想,它试 ...

  5. MATLAB | 全网唯一,三元相映射图绘制(三元相分级统计地图)

    示例 对上期的补充 本期文章名叫三元相映射图绘制,但不单单讲这一点,同时会对上一篇多元映射地图做出补充https://slandarer.blog.csdn.net/article/details/1 ...

  6. 《OpenCV3编程入门》学习笔记7 图像变换(三 )重映射

    7.3 重映射 7.3.1 概念 1.重映射是把图像中某位置的像素放置到另一图片指定位置的过程,通过重映射表达像素位置:                    g(x,y)=f(h(x,y))     ...

  7. 【斯坦福大学公开课CS224W——图机器学习】三、节点和图嵌入

    [斯坦福大学公开课CS224W--图机器学习]三.节点和图嵌入 文章目录 [斯坦福大学公开课CS224W--图机器学习]三.节点和图嵌入 1. 节点嵌入 1.1 编码器与解码器 1.2 节点嵌入的游走 ...

  8. Origin: 气泡图+颜色映射图

    利用Origin绘制气泡图及其变体 一.气泡图(bubble chart)与颜色映射图简介 二.数据准备 三.气泡图 四.颜色映射图 五.气泡图+颜色映射图 六.气泡图+颜色映射图的细节修改 6.1 ...

  9. 思维导图培训三:思维导图的应用

    思维导图培训三:思维导图的应用 在这个商业社会,个人的价值的体现必须放在社会成功的天平上进行衡量! 这就给各类成功人士提供了一个用自己的成功经验赚钱的机会,他们出书或者办班,向听众大讲特讲许许多多成功 ...

最新文章

  1. [转帖]Docker里运行Docker docker in docker(dind)
  2. 计算机系统的组成doc,《计算机系统的组成》.doc
  3. java模拟一个军队作战_战区级联合作战仿真推演系统
  4. 「LibreOJ Round #6」花火
  5. (旧)子数涵数·Flash——遮罩动画
  6. python不支持_为什么 Python 不支持函数重载?而其他语言大都支持?
  7. linux查看某进程的连接,linux下查看指定进程的所有连接信息(转)
  8. oracle tochar fm,oracle的to_char中的fm-Oracle
  9. tar命令打包并删除原文件
  10. div两侧的boder断开 消失 奇怪
  11. 如何打开高清语音VOLTE
  12. SQLServer数据库密码已过期问题 处理
  13. 充电+拓展+投屏三合一的Type-C适配器拆解
  14. HTML 入门基础教程
  15. 【ROS程序】--- 1.基本时间操作和定时器
  16. 开源h5游戏 宠物_释放:宠物和动物的开源技术
  17. 一家 50 平米小店的老板,如何用社群打垮平台电商?
  18. Heavy Transportation(最短路)
  19. elementui下拉选择框
  20. 【信号处理】python按原理实现BPSK、QPSK、QAM信号调制

热门文章

  1. linux 相关快捷键
  2. Linux系统下操作的常用快捷键
  3. Kubernetes详解
  4. yum是干什么的_yum 安装是什么
  5. unity3d Android客户端与PC服务器实现Socket通信(wifi)
  6. GDI+ 中图片的绘制
  7. 第二课堂计算机记录,第二课堂计算机小结
  8. 交叉碳市场和 Web3 以实现再生变革
  9. 云队友丨新品牌的营销大战:砸进上百万,苦心博出圈
  10. dva的用法_dva基本用法