前言

本文想再讨论一下关于领域、业务、业务模型、解决方案、BC、领域模型、微服务这些概念的含义和关系。初衷是我发现现在DDD领域建模以及解决方案落地过程中,常常对这些概念理解不清楚或者有歧义,导致我们不知道如何运用这些概念来落地我们的软件。先通过一个图来说明一下这些概念之间的关系,如下图所示

DDD战略设计相关核心概念的理解-LMLPHP

领域、业务、业务模型

  • 领域,即问题域、问题空间,领域是一种边界、范围。所以,一个领域代表了一个问题域的边界,也可以理解为是一个业务的边界。领域边界越大,业务范围就越大,反之则相反;通常我们大家交流都比较喜欢用业务这一词,比如这块业务,那块业务,业务的边界,我是一个业务开发人员(区分于我是一个中间件开发人员)。而领域一词,相对比较抽象,不是那么容易懂。
  • 领域既然是一个边界,所以可以划分领域的大小,即领域划分,划分出来的子领域简称子域,每个子域对应一个小的问题域和和小的业务;当然,不同的子域的重要性也是不同的,所以才有了核心子域、支撑子域的说法,这点显而易见。
  • 每个业务都有一个对应的业务模型(注意这个业务模型不是领域模型,而是一个业务概念的模型,领域模型下面会提到),这个业务模型设计的时候,完全不需要考虑任何软件设计的思想,比如对象的抽象、继承、存储、性能,等。我们是从业务本身出发,分析业务边界范围内的各种业务概念,以及业务概念之间的关系,通常我们可以使用一个业务模型的图来表达这些业务概念以及业务概念之间的关系。那么如何得到一个业务模型呢?最常见的有名词动词形容词分析法,还有比如四色原型分析法,都可以。找一个适合自己的就行;业务模型本身非常有价值,它提炼了领域内业务的核心概念及其关系,可以帮助我们更好的理解业务本身。

解决方案

  • 什么是解决方案?我们在进行DDD领域驱动设计的实践时,会进行需求分析、领域划分、领域建模等工作。而我们的系统要落地,则需要有一套解决方案。例如,我们要实现一个电商平台,需要一个复杂的系统解决方案,但是如果这个解决方案过大,各模块、组件都揉在一起,那么就不利于整个系统的维护、演进、伸缩,等。所以,我们需要把解决方案拆分为一个个独立的小的解决方案;所以,我们可以发现,领域和解决方案,是两个完全不同的概念,领域代表问题空间,解决方案代表解决方案空间。
  • 解决方案该如何拆分呢?简单的回答是:看情况,凭经验。说的具体点,就是我们需要使用软件设计的各种原则、最佳实践、设计模式、非功能特性的需求,以及团队成员的情况来指导我们进行解决方案的拆分或者直接不拆分,最终得出一个综合考虑后的拆分结果。所以,我们发现解决方案的拆分的维度可能有很多,没有一个单一的在任何情况下都合理的切分维度。有时我们可能从性能的角度来拆分,有时从不同架构分开演进(如CQRS架构)的角度,有时从分开伸缩的角度,有时从切合团队组织架构的维度。但是拆分的时候,多考虑一些各个因素,才能让我们更好的进行解决方案空间的拆分。

BC

  • BC,即Bounded Context,中文翻译为限界上下文。BC在DDD一书中首次出现,BC的理解分为两个层面:1)Bounded,表示边界的意思;2)Context,即上下文,我理解为是一个场景的上下文,这个场景不局限于普通的业务场景,而是各种上下文都涵盖在内,是一个时空感知的概念。比如我们两个人在公司交谈时的上下文是一个上下文,但是在路上交谈时,则切换到另一个上下文了,因为交谈的地点发生了变化;所以,BC合起来理解,就是一个上下文的边界。
  • BC有什么用呢?就是为了表达上面介绍的某个粒度的解决方案的上下文边界。那为何要强调这个边界呢?有了这个边界,我们才可以定义这个边界内的领域模型中所有对象概念的明确含义。如果没有这个上下文边界,对同一概念在不同上下文的理解,大家就会产生偏差。举个栗子:商品,在商品中心的解决方案BC中,商品中心负责管理电商平台的所有商品,所以商品在商品中心BC中,是一个聚合根;但是在订单中心解决方案BC中,虽然也叫商品,但是它只是一个值对象。我们知道订单中心的订单是一个聚合,订单内聚合了多条订单明细,每个明细是一个实体,每个订单明细对应了一个商品。虽然叫做商品,但是这个商品本质上只是商品中心的商品的一部分信息,如商品ID、标题、价格,且是只读的。甚至更为常见的,叫同一个名称的对象,在不同的BC中,是属性完全不一样的不同的对象。
  • 那为何解决方案的边界要叫做BC呢?对,我们可以不用叫做BC,比如你就叫做解决方案边界,也没问题。只是Eric在写作DDD这本书时,把他叫做BC,所以我们沿用了他的概念。我们主要的目的是为了用BC来表达解决方案空间的边界。
  • BC和子域的关系?没有关系。因为它们是不同的东西被划分后的产物,对解决方案空间进行划分产生了BC,对领域划分后产生了子域。而且它们划分的依据也不同,所以必定会出现BC与子域的关系是1对1,1对多,多对1的各种可能性。注意,我说的是被划分后的产物,所以这个产物叫什么其实不重要,我们真正要学会的是划分的原则、依据、经验,有了这些,我们才能合理地划分BC和子域。

领域模型

  • 什么是领域模型?这里讨论的领域模型是指DDD一书中提到的领域模型,领域模型是DDD软件设计方法论中的核心概念,它是业务分析、软件设计的综合结果,是一个系统设计模型。领域模型存在于某个粒度解决方案空间里。所以,任何一个领域模型,都是在特定的BC边界内才有意义;
  • 领域模型和业务模型的区别:我觉得领域模型有一个引起人们误会的地方,就是它的名称。很多人容易把领域模型理解为上面提到的业务模型,因为领域容易联系到业务,所以领域模型就是业务模型,比如非常著名的一本书《UML和模式应用》中,就认为领域模型是需求分析阶段的业务模型,是一种业务概念实体的模型。实际上两者是不同的,因为业务模型是对业务概念及其关系的表达,而领域模型在业务模型的基础上,用OOA/D的思想进行进一步精炼和抽象的对象关系模型,而且领域模型中有聚合、实体、值对象的区分。举亮个栗子:1)业务模型中,我们可能会有买家、卖家、读者、教师的业务概念,但是在领域模型中,我们已经把这些概念抽象为了账号这个模型。2)再比如一个读者持借书卡去图书馆借书这个场景,在业务模型中会存在一个借书卡的业务概念,而在领域模型中,我们很可能会去掉借书卡,因为它只是一个借书的工具,是借书系统用来识别读者的一个工具,系统真的的目的是为了知道哪个账号在借书,而不关心如何识别出这个账号。如果我们有一个网上借书系统,那就不需要借书卡了,而是要提供账号登录功能。在DDD一书中,作者一步到位直接根据需求设计出领域模型,在提炼需求分析需求的过程中直接应用软件设计思想和抽象思维一步到位产出领域模型,我个人觉得是有点快的,更好的做法应该是先分析出业务模型,再对业务模型进行精炼,得到领域模型;
  • 既然领域模型存在于某个粒度的解决方案空间中,而这个粒度的解决方案空间可能会对应多个子域。所以,这个领域模型则基于多个子域的业务模型结合起来推导出来的一个系统模型。同理,同一个子域内也可能有多个解决方案空间,既有多个BC,每个BC内有一个领域模型;
  • 那如何进行领域建模得到领域模型呢?这个就比较复杂了,不过经过前面的讨论,大致分为两个大的阶段:1)先得到业务模型;2)再对业务模型进行模型精炼;如何精炼?运用软件设计思想和原则,以及归纳演绎的抽象思维;所以,领域建模归根结底也是要“看情况,凭经验”,是不是很沮丧:)

微服务

最近几年,微服务开始流行起来,把DDD也带火了一把。那为何微服务的流行会让DDD也火起来呢?是因为微服务需要划分,而DDD中的BC的概念,大家发现正好可以和微服务的边界完全契合。比如都是对解决方案空间进行划分,都按照各种软件设计思想和原则进行划分,都提倡零共享。不过,DDD中实际上对BC的描述没有太多,尤其是如何得到BC这块没有展开。可能这块对大师来说是自然而然的事情,不需要过多介绍吧。

概念总结

  • 领域=问题域=问题空间=业务边界
  • 每个粒度的问题域都会推导出一个业务模型
  • 领域拆分、业务建模,是需求分析阶段该做的事情
  • 解决方案的边界即BC,解决方案可拆分
  • 每个粒度的解决方案都会推导出一个领域模型
  • 解决方案拆分、领域建模,是软件设计阶段该做的事情
  • BC边界即微服务边界,不同BC内的解决方案的架构可以是不同的,也即每个微服务的架构可以不同
05-16 13:23