重读领域驱动设计——如何说好一门通用语言

Posted 心有千千绪

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了重读领域驱动设计——如何说好一门通用语言相关的知识,希望对你有一定的参考价值。

结论先行:在 DDD 中,通用语言并不是横跨了项目所处的领域的,而是每个限界上下文中都有一个通用语言。限界上下文提供了一个语义边界,来保持通用语言和领域概念的一一对应关系。这个约束解决了现实世界中同样的名词在不同场景、时机下对应不同的业务概念所带来的歧义问题,帮助团队在使用通用语言交流的时候可以无歧义沟通。

初尝“通用语言”

最初我对于如何构建通用语言的认识,来自于《领域驱动设计》第一章中的案例。这个案例生动的说明了开发人员如何在和领域专家的沟通过程中,建立了双方理解一致的通用语言,并且使用这个语言来进行双方的沟通。基于那个案例,我当时理解构建通用语言就是要:

  • 技术人员使用业务人员的用语作为开发词汇;

  • 划分好聚合,将这些词汇关联到聚合上;

  • 技术人员要将这些词汇映射到代码实现中;

  • 这些词汇会随着项目的发展而一点点扩展;

我带着这份理解,在曾经负责过的小型项目上做了一些实践,效果都很不错。在很长一段时间,团队的开发人员体会到了在和业务人员交流时候,心有灵犀,会心一笑的快感;也很少听到这个东西不是我要的,这类批评了。

“通用语言”遇到同名词汇时就变得不清不楚了

然而,当我来到思特沃克参与到一些几十号人的项目上的时候,我发现根据这个原则构建起来的通用语言,在遇到同名多义的词汇的时候,就无法保证团队内部的沟通是无歧义的。而这种歧义又会导致团队成员说着同样的话想着不同的事情的情况出现,例如:

  • 同名的业务词汇与实际业务关系不清

    “为什么不能给销售订单增加一个是否投诉的字段,界面上都是显示在销售订单上的”——销售订单到底是个什么东西,能干什么不能干什么怎么确定的?

  • 同名的业务词汇与不同的业务词汇关联

    “我在销售订单付款后改变了买家信息,为什么我看销售订单的预定里的买家也发生了改变”——这里说的买家信息有几个?

  • 同名的业务词汇之间的关系不清楚

通过添加约束消除歧义

下图,是 DDD 概念的一个元模型图。从图的左下角,我们可以看到在构建通用语言时,还有两个额外的约束条件:子域和限界上下文。


在 DDD 中,软件的核心是其为客户解决领域相关的问题的能力

这里的领域,就是指软件系统要解决的实际问题相关的东西的集合。例如:为一个电子商务公司开发一个电商系统,我们就需要了解这个电子商务公司的盈利模式,围绕这个盈利模式的运营方式、业务规则,比如如何进货,如何促销,如何物流等等,所有和业务相关的东西都属于领域。

领域中分为问题域和解决方案域两部分。

为了分解问题域的复杂度,问题域又会被拆解为多个子域,每个子域都要明确待解决的业务问题和业务流程,以及通过解决业务问题为企业带来了什么样的业务价值(这个是因,业务流程和要解决的业务问题是果)。

在清晰的定义子域后,我们就可以建立通用语言来提取该子域的领域知识,并基于通用语言为解决问题建立领域模型。

一个领域模型会存在于一个限界上下文中。限界上下文在 DDD 中用来定义模型的适用范围、模型的用途、以及在何处保持一致,限界上下文会让团队明确模型的职责边界是什么。同时,通用语言被限定在限界上下文中;限界上下文提供了一个语义边界,在每个限界上下文内通用语言的每个词汇必须和领域概念一一对应。

理想条件下,子域和限界上下文是一一对应。但是子域划分的粒度,遗留系统的现状,语言的歧义,团队结构等子域和限界上下文对应可能是1:N 或者 N:N 的。

通过限界上下文间的映射,上下文中的多个模型会协作以满足系统需求。我们也可以了解在不同上下文中的同名词汇是否存在关系,存在什么样的关系。

对通用语言而言,子域解释了通用语言和现实世界业务活动的关系;限界上下文提供了一个语义边界,来保持通用语言和领域概念的一一对应关系;上下文映射则提供了不同限界上下中的通用语言的转换关系。

来解决下前文的问题

前文所述的订单及订单的相关概念存在着歧义,我们来看下通过子域、限界上下文和上下文映射是怎么消除这些歧义的:

因为同名的业务词汇与实际业务关系不清,导致的疑惑

“为什么不能销售订单增加一个是否投诉的字段,界面上都是显示在销售订单上的”

假设,这里所说的销售订单存在于销售子域下,那么这个订单应该解决的是销售过程中的问题。订单的生命周期以销售开始到销售终止。一般而言投诉属于售后环节,在销售订单上声明是否投诉字段,意味着销售订单的职能突破了销售子域。UI 上的销售订单展示了聚合的信息,和同名的领域模型不一定保持一致。

因为同名的业务词汇与不同的业务词汇关联,导致的疑惑

“我在订单付款后改变了买家信息,为什么我看订单的预定里的买家也发生了改变”

在订单上有两种买家信息,可以通过在不同的上下文中隔离来区别这两个名字相同含义不同的词汇。在销售子域中建立两个上下文,分别为预定有界上下文和购买上下文,把订单领域模型拆分到这两个上下文中。在不同的上下文中,订单都由自己的买家信息,就解决了“在订单付款后改变了买家信息,为什么我看订单的预定里的买家也发生了改变”这个问题。

因为同名的业务词汇之间的关系不清楚,导致的疑惑

引用:

  1. 《领域驱动设计》

  2. 《实现领域驱动设计》

  3. 当Subdomain遇见Bounded Context

  4. DDD的终极大招——By Experience

  5. 《领域驱动设计学习:领域、子域、限界上下文》


以上是关于重读领域驱动设计——如何说好一门通用语言的主要内容,如果未能解决你的问题,请参考以下文章

解惑领域驱动设计的若干问题

领域驱动设计 DDD的一些基础概念

领域驱动设计--战术模式简介

DDD领域驱动设计基本理论知识总结

DDD领域驱动设计基本理论知识总结

[转]DDD领域驱动设计基本理论知识总结