限界上下文(简称BC)是一个很难讲的部分。我寻思着是不是再多找一找文章,看看其它人怎么讲的,但犹豫再三还是决定按自已的理解去聊,各种找材料就有点剽窃的行为了。至于说的是否正确,您务必也要做好判断,毕竟每个人都会有自己的理解。做为温故而知新的一部分,在此把前面总结的BC的特点再重复一下,也不是为了凑字儿,DDD这东西就得靠多多的啰嗦才能记得住,毕竟概念忒多。此外,为提升您的阅读体验,限界上下文分为两节分别讲解。

  BC的特点包括四个方面:1)是系统的物理划分;2)应根据子域的定义进行推导;3)限定了领域模型的边界,是对领域模型的一种划分和限定;4)BC内每个领域术语都有且只有一个明确的含义(即通用语言)。

  BC的设计一般是通过子域进行推导。假如将DDD的指导分成三部分:子域设计、BC设计和代码设计,BC属第二层,起到承上启下的作用,在将业务模型转换为技术的过程中提供宏观指导。BC定义的过程其实就是确认有几个子系统(或Java中的包、.NET中的名称空间),有哪些领域模型(此处的领域模型是一种业务术语不是指‘类’或‘接口’)以及子系统间如何交互。从上述概念上可以看出来,讨论BC时既有业务的部分也有技术的内容。

领域模型

1、领域模型的使用贯穿了“分析”、“设计”、“开发”的整个流程,各类人员都应该使用领域模进行沟通和交流,避免系统在实现过程中需求走样

2、领域模型只反映业务与技术无关,其不仅包括业务中的实体如“订单”、“客户”等还包含业务流程如“下订单”

3、领域模型是有边界的,我们只应该关注业务所关注的部份

  在进入BC的讨论之前,首先介绍一些基本概念避免后续我们用到的时候作为读者的您一脸的蒙圈,怪我不事先说事后卖关子。第一个介绍的词叫“建模”,第二个要介绍的词是“模型”。不论是作为软件开发老炮儿还是菜鸟,您可能在无数的场合听了无数次的这个词。遥想当前我初来乍到,但凡听谁说在做软件建模,给我的第一印象就是这人妥妥的大牛一个。那它到底是什么意思呢?咱换成人话就是:比如有这么一个事儿,我嘴笨和您说不明白,那就写一段儿或者画个图。反正不管用什么手段,只要您懂了我的意图咱这目的就达到了。这里所说的“一段文字”或“图”就是模型,干这个事情的过程就叫“建模”。所以您不管是做设计子域还是BC还是画流程图,都是建模,不知道为什么非得用“建模”,IT圈就是不喜欢说人话。

  题外话:中国IT圈对一些词的翻译我觉得真是前无古人:句柄、多态、建模、闭包……这翻译,不服来战。

  回到正题,在软件设计活动中(严谨的说是在UML建模过程中)包含三类模型:业务模型、分析模型和设计模型,具体解释如下列表。不过咱得多说一句,我们常见的类图啊、时序图啊,你可别认为这些模型仅用于实施前的设计阶段,在业务分析阶段也是可以用的,只是目的不一样。您可别回头一说类图就认为只在软件设计阶段专用,对外行说说就行了,内行咱得有内行的专业素养。

  • 业务模型:用于解释与说明业务逻辑的各类文档或图,与是否有电脑无关系,是对客观的业务的描述。子域设计即是业务模型设计。
  • 分析模型:用于说明哪些业务可在软件系统中实现(并非所有的业务都可被落实到软件中,这就是为什么常常见到开发与产品经理互撕),其上面连接了业务模型下面对应到设计模型。BC设计即分析模型设计。
  • 设计模型:用于说明软件在代码层次上的设计方式,常见的如类图、活动图、时序图等。DDD战术阶段所建模型如聚合、实体即为设计模型。

   我不仅说了三个模型还能套在DDD上,一是没跑题,二是显得专业。能这个事儿圆回来,我自己都佩服自己。另外着重说一点,所有的模型里,文档是最重要的,具体您自行体会。关于文档这个事情,也再多啰嗦几句。一般来说不建议花精力在代码设计阶段编写大量的文档,一是会很占用时间二是几乎没有多少公司能保证代码变化的同时文档也随之变化,在此情况下文档不仅不能说明问题还特别耽误事儿。But,业务模型文档是必需的,这东西变化率不是很高。您也别跟我抬扛,一个企业的业务模型天天变化,我劝您趁早离职,他自己都没找到方向。至于分析模型,属于过渡型文档,视具体情况而定。

  上一章中展示了个人微信的域图,为避免误会本节以一款“即使通讯软件”的后端架构为例展示限界上下文的设计图,由于并无实际的软件,您仍可以微信为对照。我得先避个嫌疑,回头腾讯公司找过了就虾米了……另外,实际的系统架构比案例复杂的多的多,划分得也会更加的详细。此处仅做为引子告诉您如何进行BC设计,您在日常工作中需要学会举一反三,这也是治学问的正确姿势。时间久了,你就能体会何为“众里寻他千百度,蓦然回首,那人却在,灯火阑珊处”。

 

   为能说明问题,本例中把“小程序管理子域”和“鉴权子域”去掉了,图不好画(其实主要是影响您的阅读体验)。此外,上一章针对“通讯录子域”和“聊天子域”的设计不够细致,需要进行细化。下图为两个子域的细化结果,注意:此处的设计仍为子域图,尚未到BC设计阶段。

 

      

   子域经过细化后我们建立了下面的BC图,需要注意的是BC设计图中应该以实线表示每一个限界上下文,因为BC具备物理特性已非概念上的模型, BC间的交互通过实线进行连接。

 

 

    BC的设计不仅需要子域设计为参考,还需要结合您的团队与公司的实际情况进行计。本案例的建设由同一部门的人数为200的成员所组成的团队,包括研发、测试、运维、产品经理、项目经理等基本角色,因资源充沛且岗位齐全,确定使用微服务架构作作为系统落地时的方案。我们来详细解释一下本方案的设计依据。

  1. 聊天子域:分为“通讯管理”和“历史消息管理”两个子系统,前者用于聊天场景比如发送各类文本、图片等;后者用于对历史消息进行存储以用于记录查询。这两个BC所关注的业务点有很大差异,边界较为明显,两个BC可使用不同的系统架构并可独立进化。
  2. 消息审计使用了第三方采购的实时审计系统用于对用户所发的朋友圈或消息进行审计以避免非法内容的存在。
  3. 通讯录子域分为两个BC:“联系人管理”和“好友关系管理”分别用于管理本账户的联系人和用于朋友推荐的推荐系统。

   一般来说BC和子域是可以一一对应的。当然,具体情况还要视您所在公司和团队的架构。假如说子域的设计是项目的开端,那BC的设计的好坏几乎可以决定系统的成败,应当是设计过程中投入精力最多的地方。其原因前面已然说过:子域划定了一个个小的物理系统,天然具备隔离效果,当您的系统具备良好的BC设计时,即便某个BC出现失败也不会导致整个系统的业务雪崩。后面我们谈到DDD的隔离机制时您就会发现为什么BC的隔离是最为核心和关键的。

  BC的设计粒度,往大了看其实可以是一个子系统本身,单体系统只有一个BC(此种情况下,单系统已经不能算是纯粹上的BC,应当以“包”或“名称空间”作为BC的基本单位);往小的方面看,最小的粒度为“聚合”,切记!真的不能再小了。无论其大小,关键的设计原则是“完整”即BC可以完整的支撑某项业务,换另外的说法就是每个BC应该是自治的且与其它BC有清晰的边界。实际上,当您在BC设计时会发现大部分情况下寻找BC边界是一个非常自然的过程,还是那句话:人是有灵性的。

注意!

系统的建设过程(开发阶段)中,请务必保证您的领域模型不能外泄到BC之外,这里的BC可以是一个项目也可以是一个包或名称空间。BC间的交互只能通过DTO或消息(其实消息也是一种DTO)

    实际上,BC的设计过程中还是有许多的原则可以遵守的,在此一一列举出来。

  1. BC的设计是系统的宏观架构设计,一经确认后就需要以此为依据进行实施
  2. 以业务维度为准进行BC设计。这一条会存在例外:前后端分离架构,是一种比较典型的以技术为参照的的BC设计方式。就前端是否属于BC一部分的问题目前还是有一定的争议的,比较权威的书上的回答也是“Yes”,为此还引入了微前端的技术。我个人建议您视自己的公司与团队情况而定,不必拘泥于理论。
  3. BC设计需要以您的组织结构包括团队技术层次、团队组织结构、是否跨部门、人力资源情况等为参考以免虽有设计方案但无法落地,陷入纸上谈兵的境界,造成前期工作浪费。
  4. BC也需要保持随时变更,尤其是在子域有变更的情况下
  5. DDD中最为重要的规律是“运动与适应”,一切事务皆在变化中,您需要随时根据变化做调整
  6. 现实中,有些带头大哥喜欢根据开发任务来设计BC,这种情况最好少用以减少甩锅的情况。另外,个人建议BC的开发工作只由一个人负责即由上面的service到最下面的dao,不要针对同一个聚合让过多的人参与,每个人都有自己的设计思路,非常容易出现重复性的内容;一个研发人员的连贯性思路也很容易被打断。如果BC较大,也请限制在一个团队内以减少沟通成本
  7. 限界上下文的识别实际上并没有标准可言,可以通过业务复杂度、管理复杂度和技术复杂度去分析和识别,迭代化的进行分析 。

  为了让您明白,我们再整一个例子。这里以一个电商购物系统为例,展示其BC的设计方式。本案例中,团队人员较少,由开发人员承担着运维的职责;系统客户对象以企业内部用户为主。为方便说明,我们仍只展示部分子域:核心域中的销售子域,如下图所示。

  依据上图所示的子域说明,推导出如下BC设计。

  不同于第一个案例,本例未使用微服务架构,而是使用了单体架构作为其落地方式。我知道有些人是强烈的微服务架构拥护者,但我仍然需要在此强调:系统的架构选择时,技术能力仅仅是一方面,而且还只是很小的一个方面。决策我们架构选择的因素有许多,比如团队的综合能力(注意:不能以团队中是否有一两个高手来决策团队综合能力)、团队结构、公司的总体结构(尤其您要做的系统是业务中台时)等。项目背景中已说明“开发兼职运维”,说明当前团队使用容器化部署、链路追踪、全栈监控等技术时会比较勉强,即使强加到系统中也会由于资源的不足造成您想要的结果与期望不匹配。

  最后需要说一句,我们都知道微服务架构有各种优势,也知道单体系统有各种不足。但任何事务都有其两面性,在您使用的时候需要首先综合评估自身所具备的条件。再说了,您做的系统不是一锤子买卖,随着后续资源的投入,您是可以进行架构优化的。