DDD——在我梦里,我还能让你把我给欺负了?

在《夏洛特烦恼》中有这么的一段剧情:夏洛穿越到了他初中的班级里,当他发现自己在梦中的时候,看着一直讽刺挖苦他的老师说了句经典的台词:“在我梦里,我还能让你把我给欺负了?”。他能说出这么“男人”的话,就是因为这是他的梦,是他的“领域”,他是这个梦里面的“”。

那么在DDD中也有领域的概念,团队中的同学们也是所负责领域中的“王”。通过领域,我们会引出另外两个概念,即:子域限界上线文。那么,在今天的文章里,我们就好好的聊一聊他们的故事。

一、领域

既然DDD的含义是“领域驱动设计”,那么,什么是领域(Domain)?

从广义上讲,领域就是一个组织所做的事情以及其中所包含的一切。换句话说,就是一个公司或组织,它所涉及的业务范围以及在其中所进行的活动

上面的定义可能较为生涩,那么我们以非常火爆的《斗罗大陆》为例:唐三获得了杀神领域蓝银领域。那么,当施展出领域力量之后,在领域内的自己实力大增,而对手的实力却被大幅度削弱。

那么公司也是一样的,我们拿李宁和阿里为例,在运动服饰这个领域中,李宁就远远强于阿里;但是在电商互联网领域中,阿里就强于李宁。所以,用大白话来说解释领域这个词的概念,就是——你所经营的、活动的、擅长的那个圈子

“领域”这个词的含义是多样化的,它既可以表示整个业务系统,也可以表示其中的某个“核心域”或者“支撑子域”。

由于“领域模型”包含了“领域”这个词,我们可能会认为应该为整个业务系统创建一个单一的、完整的、内聚的、全功能式的模型,就像《圣斗士星矢》里面的圣衣一样,那么的完整、内聚、功能繁多且强大。

然后,其实正好相反,在DDD中,一个领域被分为若干个子域,领域模型在限界上下文中完成开发。事实上,在开发一个领域模型时,我们通常关注的只是这个业务系统的某个方面——某个子域。而无论软件系统本身的复杂度是大还是小,几乎所有软件的领域都包含多个子域。

二、子域

子域根据类型的不同,可分为:核心域支撑子域通用子域。以一个音乐网站或者app为例(排除掉版权问题,假设所有数字音乐各大音乐网站都可以平等播放),它一般包含很多的功能,我们暂且只关注音乐品味推荐、会员与权限、促销活动这3部分功能,那么如下就是针对这3部分子域类型的划分:

【解释】

  • 那么如果想要我们的音乐网站或者app脱颖而出并受到大众的喜爱,音乐品味推荐会是核心能力,我听了几首歌,后续不知道要听什么歌曲了,而网站给我推荐的歌曲都特别符合我对音乐的品味,那用户自然就更喜欢来这里听歌,那么“音乐品味推荐”就是核心域
  • 而网站的各个功能其实都会或多或少的使用会员与权限的能力,所以“会员与权限”就是通用子域
  • 而“促销活动”这部分也属于业务能力的一部分,但是并没有核心域那么重要,“促销活动”便是支撑子域

    2.1> 核心域

    它是整个业务领域的一部分,也是业务成功的主要促成因素。从战略层面上讲,企业应该在核心域上胜人一筹。我们应该给予核心域最高的优先级、最资深的领域专家和最优秀的开发团队。在实施DDD的过程中,你将主要关注于核心域。

    2.2> 支撑子域

    如果某个限界上下文对应着业务的某些重要方面,但却不是核心,那么它便是一个支撑子域。创建支撑子域的原因在于它们专注于业务的某个方面。

    2.3> 通用子域

    如果一个子域被用于整个业务系统,那么这个子域便是通用子域。

    三、限界上下文

    运用限界上下文(BoundedContext)的战略设计模式来分离领域模型。一个领域被分为若干个子域,领域模型在限界上下文中完成开发

    在实施DDD的时候,我们要保证每一个术语应该仅表示一种领域概念,即:将用到的每一个术语进行限界划分。这种基于语言层面上的上下文边界划分,也是实现DDD的关键。如下所示,同样的“售卖”一词在不同的上下文中含义都是不一样的:

    限界上下文是一个显式的边界,领域模型便存在于这个边界之内。领域模型把通用语言表达成软件模型。创建边界的原因在于,每个模型概念,包括它的属性和操作,在边界内都具有特殊的含义。

    上面我们介绍限界上下文的时候,一直再提边界的问题,边界真的这么重要?没有边界,不是一样不影响我们项目的开发迭代吗? 其实不然,在我们试图创建一个“大而全”的软件模型的时候,要使所有人都对某个概念的定义达成一致几乎不可能。因此,最好的方法是去正视这种不同,然后使用限界上下文对领域模型进行分离。可以举个例子,在广场上有一群人要商量去哪里,大家各抒己见,无法达成一致。

    那怎么办呢?大家谁都不让步。分析原因,广场上的这群人,彼此之间又都是陌生的,那么陌生人也不会轻易的迁就对方,那么我们以家庭进行分组(建立边界),由一家人(即:在同一限界上下文中)内部去商量要去哪里,确定一致性建议。

    由上面的例子我们可以看到,将不同的家庭分界开来,由于一家人是有血缘关系的,所以更容易达成一致。而在DDD中的这种“一家人”,就属于限界上下文,它把一个领域(类比:广场)划分为多个限界上下文,在限界上下文中进行领域建模,同时,这样更容易对某个概念的定义达成一致,建立专属这个限界上下文的领域语言

    四、战略设计的重要性

    DDD是分为两大部分内容的:宏观上的——战略设计微观上的——战术设计。而在上面我们介绍的“领域”、“子域”和“限界上下文”其实都属于战略设计。那么在实施DDD的过程中,我们也需要遵守先执行战略设计,再执行战术设计的方式。那么,战略设计为什么这么重要呢?

    其实一提到战略和战术,大部分同学的第一反应应该是在战场上高频出现的词汇,那么我们就以战场来做解释。下面是辽沈战役攻打锦州的作战部署图:

    从上面的图中我们可以看到,分为了“2C”、“7D”、“8D”、“8C”等作战部队,并且针对每个部队都标注着要攻打的位置和路线。在这张图里,并没有标注用什么枪、用什么炮、用什么手榴弹、多少医护人员……也就是说,不包含打仗的具体细节(战术模式),只在宏观上(战略模式)划分的队伍和攻打方向。如果没有这个宏观的作战图,那么部队将会一盘散沙,各自为战,没有任何配合可言了。这个跟我们DDD中的战略模式是类似的。如下是对应关系:

    • • 领域——>攻打锦城
    • • 子域——>部队
    • • 核心域——>主力部队,比如:8D
    • • 支撑域——>其他非主力部队
    • • 通用域——>通信部队,医疗部队,炊事班
    • • 限界上下文——>某部队负责攻打的区域

    通过上面针对战争的例子来看,战略的重要性远不亚于战术,就像人们常常说的那句话——“方向不对,努力白废!”,而战略设计就是DDD中的方向。

    五、问题空间&解决方案空间

    领域中还同时存在问题空间解决方案空间。它们的含义如下所示:

    软件开发过程,本质上可以看作是问题空间到解决方案空间的一个映射转化。

    5.1> 问题空间

    在实际项目中,我们可以针对如下问题,对问题空间进行评估

    • • 这个核心域的名字是什么?目标是什么?包含哪些概念?
    • • 支撑子域和通用子域是什么?
    • • 如何安排项目人员?能否组件一只合适的团队?

    5.2> 解决方案空间

    解决方案空间在很大程度上受到现有系统和技术的影响。在实际项目中,我们可以针对如下问题,对解决方案空间进行评估

    • • 有哪些软件资产是存在的?是否可以重用?是否需要创建?是否可以从别的地方获得到?
    • • 这些资产是如何集成起来的?需要如何集成?
    • • 假设资产都已经ok了,我们还需要做什么?
    • • 核心域和支撑项目的成功概率是多少?会不会由于其中一个的失败而导致全盘皆输?
    • • 在哪些地方我们使用了完全不同的术语?
    • • 限界上下文之间在哪些地方存在概念上的重叠?这些重叠的概念在不同的限界上下文之间是如何映射和翻译的?
    • • 哪些限界上下文包含了核心域中的概念,其中使用了哪些[Evans]中的战术模式?

    六、没有技术内容了,就是随便聊聊

    昨天我的一位关系很好的百度同事(化名:小A)结束北漂生涯回老家了,心里也挺不是滋味的。

    在百度我们有一个吃饭群,一到中午午餐时间,群里就开始“招呼”大家一起去吃饭。人最多的时候10多个人,食堂的大长桌子都不够坐,中午闲聊、扯淡、开玩笑很是热闹。

    不过随着大家“各奔东西”,群里的兄弟姐妹也越来越少。在去年的年中,群里也就剩下几个人还在百度,而晚上吃饭遛弯也只剩下我和小A了,当时就在公司7层遛弯,聊基金股票、聊新闻趣事、聊以后的人生怎么打算的……,一晃也有一年了,当时的一切历历在目。

    今年互联网的大形势确实很差,身边已经又几位朋友离开北京回老家了,这么一算,自己来北京也有十多年了,当时毕业赶上了金融危机,大环境也是像今年一样差劲,简历投递石沉大海,和同学聊天都说“不给钱,只要给工作机会也干”,现在想想,为了能成为“码农”也蛮拼的。当时一帮刚毕业的年轻人们,现在还在北京的也寥寥无几了。或许再过一段时间,自己也会离开这座城市吧。

    北京依然是那座城,依然会有一帮刚毕业的年轻人们,背着行李,满载梦想,把青春和激情洒满这片土地。

    行了,今天就这么多内容了,我们下篇文章再见啦!