张逸说

出口成张,逸派胡言

0%

验证限界上下文的原则

在获得了限界上下文之后,还应该遵循限界上下文的验证原则对边界的合理性进行验证。

正交原则

正交性要求:“如果两个或更多事物中的一个发生变化,不会影响其他事物,这些事物就是正交的。”变化的影响主要体现在变化的传递性,即一个事物的变化会传递到另一个事物引起它的变化,但这个变化影响并不包含彼此正交的点。例如,限界上下文之间存在调用关系,当被调用的限界上下文公开的接口发生变化,自然会影响调用方。这一影响是合理的,也是软件设计很难避免的依赖。故而限界上下文存在正交性,指的是各自边界封装的业务知识不存在变化的传递性。

要破除变化的传递性,就要保证每个限界上下文对外提供的业务能力不能出现雷同,这就需要保证为完成该业务能力需要的领域知识不能出现交叉;要让领域知识不能出现交叉,就要保证封装了领域知识的领域模型不能出现重叠。业务能力、领域知识、领域模型,三者之间存在层次的递进关系,无论是自顶向下去推演,还是自底向上来概括,都不允许同一层次之间存在非正交的事物,如图所示。

领域模型违背了正交性,意味着各自定义的领域模型对象代表的领域概念出现了重复。注意,限界上下文展现的领域概念具有知识语境,不能因为领域概念名称相同就认为领域概念出现了重复。判断领域模型的重复性,必须将限界上下文作为修饰,将二者组合起来共同评判。例如,在供应链系统中,商品限界上下文、运输限界上下文与库存限界上下文的领域模型都定义了Product类,但结合各自的知识语境,这一领域模型类实际代表了不同的领域概念;在保险系统,车险限界上下文、寿险限界上下文的领域模型都定义了Customer类,关注的客户属性也是近似的,属于相同的领域概念,导致领域模型的重复。

领域知识违背了正交性,代表了业务问题的解决方案出现了重复,通常包含了领域行为与业务规则,例如在电商系统中,运费计算的规则不能同时存在于多个限界上下文,如果在订单上下文和配送上下文都各自实现了运费计算的逻辑,就会使得这一重复蔓延到系统各处,一旦运费计算规则发生变化,就需要同时修改多个限界上下文,修改时,如果遗漏了某个重复的实现,还会引入潜在的缺陷。

业务能力违背了正交性,意味着业务服务出现的重复。例如,在一个物流系统中,地图上下文提供了地理位置定位的业务服务,结果在导航上下文又定义了这一服务。之所以出现这一结果,可能是因为各个领域特性团队沟通不畅。

单一抽象层次原则

单一抽象层次原则(Single Level of Abstraction Principle,SLAP)来自Kent Beck的编码实践,他在组合方法(Composed Method)模式中要求:“保证一个方法中的所有操作都在同一个抽象层次”。不过,这一原则却是由Gleann Vanderburg在理解了这一概念之后提炼出来的。识别限界上下文时,归纳业务知识的过程就是抽象的过程,限界上下文的名称代表一个抽象的概念,因此,我们可以引入该原则作为限界上下文的验证原则。
要理解单一抽象层次原则,需要先了解什么是概念的抽象层次。

抽象这个词的拉丁文为abstractio,原意为排除、抽出。中文对这个词语的翻译也很巧妙,顾名思义,可以理解为抽出具体形象的东西。例如,人是一个抽象的概念,一个具体的人有性别、年龄、身高、相貌、社会关系等具体特征,而抽象的人就是不包含这些具体特征的一个概念。抽象概念指代一类事物,因此,抽象实际上并非真正抽出这些具体特征,而是对一类具有共同特征的事物进行归纳,从而抹掉具体类型之间的差异。

抽象层次与概念的内涵有关,概念的内涵即事物的特征。内涵越小,意味着抽象的特征越少,抽象的层次就越高,外延也越大,反之亦然。例如,男人和女人有性别特征的具体值,人抽象了性别特征,使得该概念的内涵要少于男人或女人,而外延的范围却更大,抽象层次也就更高。同理,生物的概念层次要高于人,物质的概念层次又要高于生物。

违背了单一抽象层次原则的限界上下文会导致概念层次的混乱。一个高抽象层次的概念由于内涵更小,使得它的外延更大,就有可能包含低抽象层次的概念,使得位于不同抽象层次的限界上下文存在概念上的包含关系,这实际上也违背了正交原则。例如,在一个集装箱多式联运系统中,商务上下文与合同上下文就不在一个抽象层次上,因为商务的概念实际涵盖了合同、客户、项目等更低抽象层次的概念;运输、堆场、货站限界上下文则遵循了单一抽象层次原则,运输上下文是对运输计划和路线的抽象,堆场上下文是对铁路运输场区概念的抽象,货站上下文则是对公路运输站点工作区域相关概念的抽象,它们关注的业务维度可能并不相同,但不影响它们的抽象层次位于同一条水平线上。

抽象层次与重要程度无关,不能说提供支撑功能的限界上下文低于提供核心业务能力的限界上下文。仍然是在集装箱多式联运系统,运输、堆场以及货站等限界上下文都需要作业和作业指令,区别在于操作的作业内容不同。提炼出来的作业上下文为运输、堆场以及货站等限界上下文提供了业务功能的支撑,但它们属于同一抽象层次的限界上下文。

奥卡姆剃刀原理

限界上下文作为高层的抽象机制,体现了我们在软件构建过程中对领域思考的本质,它是架构映射阶段的核心模式。因此,限界上下文的识别直接影响了领域驱动设计的架构质量。通过分解、归类、归纳到最后的验证之后,如果对识别出来的限界上下文的准确性依然心存疑虑,比较务实的做法是保证限界上下文具备一定的粗粒度。

这正是奥卡姆剃刀原理的体现,即“切勿浪费较多东西去做用较少的东西同样可以做好的事情”,更文雅的说法就是“如无必要,勿增实体”。遵循该原则,意味着当我们没有寻找到必须切分限界上下文的必要证据时,就不要增加新的限界上下文。倘若觉得功能的边界不好把握分寸,可以考虑将这些模棱两可的功能放在同一个限界上下文中。待到该限界上下文变得越来越庞大,以至于一个领域特性团队无法完成交付目标;又或者违背了限界上下文的自治原则,或者质量属性要求它的边界需要再次切分时,再对该限界上下文进行分解,增加新的限界上下文。这才是设计的实证主义态度。


本文选择我的著作《解构领域驱动设计》