战略设计部分:控制核心域的复杂性

       

目录

        不一致的模型

        什么是界限上下文?

        有界模型

       统一语言精练

       界限上下文的作用域

     界限上下文与子域的对比

      子域

      界限上下文

      子域和有界上下文之间的相互作用

      边界

       物理边界   

        所有权边界                    

      现实生活中的界限上下文

      语义域

      科学

      买一个冰箱

      总结


        正如您在前一章中看到的,为了确保项目的成功,开发一种统一(通用)语言是至关重要的,项目的所有涉众(从软件工程师到领域专家)都会用它来更高效的交流。该语言应该反映出领域专家对业务领域内部工作和基本原则的思维模式。

        因为我们的目标是使用通用语言来驱动软件设计决策,所以语言定义必须是清晰和一致的。它应该没有歧义、没有隐含的假设和无关的细节。然而,在公司组织结构上,不同组织领域专家的心智模型本身可能是不一致的。不同的领域专家可以使用同一业务领域的不同模型。让我们看一个例子。

        不一致的模型

        我们以电话营销公司为例。该公司的营销部门通过在线广告创造商机。它的销售部门负责招揽潜在客户购买它的产品或服务,这一过程如下图所示。

示例业务域:电话营销公司题

        对这些领域专家的语言含义进行研究可以发现一个特殊的现象。“线索”一词在市场和销售部门有不同的含义:

         市场营销部门:

        对于市场营销人员来说,线索表示有人对某一产品感兴趣。收到潜在客户的联系方式的事件被认为是一个线索。

        销售部门:

        在销售部门中,线索代表是潜在客户,潜在客户是一个更为复杂的实体。它代表了销售过程的整个生命周期。这不仅仅是一个事件,而是一个长期运行的过程。

        在这家电话营销公司的案例中,我们如何制定一种统一语言?

        一方面,我们知道统一语言必须是一致的——每个术语都应该有一个意思。另一方面,我们知道统一语言必须反映领域专家的心理模型。

        在这种情况下,市场营销部的领域专家和销售部门的领域专家对“线索”的理解就不一致了。在人与人之间的普通交流中,这种模糊性并不会带来太大的挑战。事实上,来自不同部门的人员之间的沟通可能更具挑战性,但人们很容易从交流的上下文推断出确切的含义。

        然而,在软件中表示这样一个业务领域的发散模型是比较困难的。源代码不能很好地处理模糊性。如果我们将销售部门的复杂模型引入到市场营销部门中,它将画蛇添足——会给营销人员增加更多他们不需要关注的细节和行为。但如果我们试图根据营销部门的理解简化销售部门的模型,它将无法满足销售子域的需求,因为它对于销售过程的管理和优化来说太简单了。在第一种情况下,我们会有一个设计过度的解决方案,而在第二种情况下,我们会有一个设计不足的解决方案。

        那我们如何解决这个两难的问题呢?

        这个问题的传统解决方案是设计一个单一的模型,可以用于各种各样的问题。这样的模型会出现跨越整个办公室墙壁的巨大实体关系图(erd)。类似下图:

企业范围的实体关系图

        俗话说:“样样通,样样不精”。这样的模型被认为适用于一切,但最终却毫无效果。无论您做什么,您总是要面对复杂性:过滤无关细节的复杂性、找到您真正需要的内容的复杂性,以及最重要的是保持数据处于一致状态的复杂性。

        另一种解决方案是在有问题的术语前面加上上下文的定义:“营销线索”和“销售线索”。这将会在代码中实现这两个模型。然而,这种方法有两个主要缺点。首先,它诱发了认知负荷。什么时候应该使用哪种模型?冲突模型的实现越接近,就越容易出错。其次,模型的实现不会与统一语言一致。没有人会在对话中使用前缀。人们不需要这些额外的信息,他们可以依赖场景上下文进行对话,也不会影响他们的理解。

        让我们转向处理此类场景的领域驱动设计模式:界限上下文模式。

        什么是界限上下文?

        领域驱动设计的解决方案很简单:将统一语言划分为多个更细粒度的语言,然后将每个语言分配到可以应用它的显式上下文:界限上下文。

        在前面的例子中,我们可以确定两个界限上下文:营销“marketing ”和销售“sales”。如下图所示,lead一词在两种界限上下文中都存在。只要它在每个界限上下文中具有单一的含义,每一种细粒度的通用语言都是一致的,并遵循领域专家的思维模型。

                

通过将统一语言划分到界限上下文中来解决不一致的问题

        在某种意义上,术语冲突和隐蔽性内容是任何规模可观的业务的少不了的问题。使用界限上下文模式,将上下文建模为业务领域的显式和不可分割的部分。

        有界模型

        正如我们在前一章所讨论的,模型不是真实世界的副本,而是帮助我们理解复杂系统的构造。它要解决的问题是模型固有的一部分——它的目标范围。模型不能没有边界而存在;它将扩展成为现实世界的复制品,这使得定义模型的边界-它的界限上下文,成为建模过程的固有部分。

        让我们回到地图作为模型的例子。我们看到每张地图都有其特定的上下文比如:航空、航海、地形、地铁等等。地图只有在其特定用途的范围内才正确、有用。就像地铁地图对航海导航毫无用处一样,一个界限上下文中的通用语言可能与另一个界限上下文中的作用域完全无关。界限上下文定义了统一语言及其所代表的模型的适用性。它们允许根据不同的问题域定义不同的模型。换句话说,界限上下文是统一语言的一致性边界。语言的术语、原则和业务规则只在其界限上下文中是一致的。

       统一语言精练

界限上下文允许我们完成对统一语言的定义。一种统一语言并不“通用”,因为它应该在整个组织中“通用”地使用和应用。一种统一语言并不是通用的。

        相反,一种统一语言只在其界限上下文的边界中是通用的。该语言只专注于描述界限上下文内所包含的模型。由于模型不可能在没有它应该解决的问题的情况下存在,在没有明确的适用性上下文的情况下,统一语言无法被定义或使用。

       界限上下文的作用域

        本章开头的示例演示了业务域的固有边界。不同的领域专家对同一企业实体持有相互矛盾的内心模型。要对业务领域建模,我们必须划分模型并为每个细粒度模型定义严格的适用性上下文--它的界限上下文。

        统一语言的一致性只有助于确定该语言的最宽边界。它不能再大了,因为那样就会有不一致的模型和术语。然而,我们仍然可以将模型进一步分解成更小的界限上下文,如下图所示

更细粒度的界限上下文

         定义统一语言的范围,它的界限上下文,是一项战略性的设计决策。边界可以是宽的,遵循业务领域的固有上下文;也可以是窄的,进一步将业务领域划分为更小的问题域。

        界限上下文的作用域并不是由它本身决定。模型不一定要大或小。模型必须是有用的。统一语言的边界越宽,就越难保持一致。将一种大的通用语言划分为更小的、更易于管理的问题域可能是有益的,但是追求小的界限上下文也会适得其反。它们越小,设计产生的集成开销就越大。

        因此,界限上下文的作用域应该取决于特定的问题域本身。有时,使用较宽的边界会更清晰,而在其他时候,进一步分解它会更有意义。

        从大的界限上下文中提取细粒度的界限上下文的原因,包括组成新的软件工程团队或解决系统的一些不应承担的问题功能和需求;例如,在原有的界限上下文中,有一部分组件需要在不同的开发周期中迭代实现时,需要进一步拆分成小的界限上下文,提取功能的另一个常见原因是能够独立于有界上下文,提供给其余功能扩展它。

        因此,保持您的模型有用,并使界限上下文的作用域与您的业务需求和组织结构保持一致。要注意的一件事是将一个连贯的功能拆分到多个界限上下文中,这样的拆分将阻碍每个上下文独立发展的能力。这时候还会起到另外一个反作用,同一个的业务需求的更改,将影响其他界限上下文,同时做出更改和发布。

        为了避免这种无效的分解,请使用我们在第一章讨论过的寻找子域的方法:识别出操作相同数据的用例集,并避免将它们分解为多个有界上下文。

     界限上下文与子域的对比

        我们已经知道业务域一般由多个子域组成。到目前为止,在本章中,我们探索了将业务域分解为一组细粒度问题域或界限上下文的概念。起初,分解业务域的两种方法可能看起来是多余的。然而,事实并非如此。让我们来看看为什么需要这两种边界划分。

      子域

        要理解一个公司的经营战略,我们必须分析它的业务领域。根据领域驱动的设计方法,分析阶段涉及识别不同的子领域(核心、支持和通用)。这就是公司机构如何运作和规划竞争战略的方式。

        正如您在第一章中学到的,子域类似于一组相互关联的用例集合。用例由业务域和系统需求定义。作为软件工程师,我们不定义需求,这是企业业务的责任。相反,我们正在分析业务域以识别子域。

      界限上下文

        另一方面,界限上下文是设计出来的。模型边界的选定是一个战略性的设计决策。我们决定如何将业务领域划分为较小的、可管理的问题领域。

      子域和有界上下文之间的相互作用

        从理论上讲,尽管不切实际,但一种模式可以跨越整个商业领域。这种策略适用于小型系统,如图所示。

        

整体界限上下文

 当冲突模型出现时,我们可以遵循领域专家的心智模型,将系统分解成界限上下文,如下图所示。

统一语言一致性驱动划分的界限上下文

         如果模型仍然很大并且很难维护,我们可以将它们分解成更小的界限上下文;例如,每个子域都有一个界限上下文,如下图所示。

与子域边界对其的界限上下文

         无论哪种方式,这都是一个设计决定。我们将这些边界设计为解决方案的一部分。在某些场景中,界限上下文和子域之间的一对一关系是完全合理的。然而,在其他情况下,不同的划分策略可能更适合。关键是要记住子域是被发现的,界限上下文是被设计的。子域由业务战略定义。然而,我们可以设计软件解决方案和它的界限上下文来处理特定项目的上下文和约束。

        最后,正如您在第一章中了解到的,模型旨在解决特定问题。在某些情况下,同时使用同一概念的多个模型来解决不同的问题可能是有益的。由于不同类型的地图提供了不同类型的关于我们星球的信息,使用同一子域的不同模型来解决不同的问题可能是合理的。将设计限制在界限上下文之间的一对一关系会抑制这种灵活性,并迫使我们在其界限上下文中使用子域的单一模型。

      边界

        正如Ruth Malan所说,架构设计本质上是关于边界的:

        架构设计就是系统设计。系统设计是一种情境设计,它本质上是关于边界(里面有什么,外面有什么,跨越了什么,什么在内外之间移动),以及关于权衡。它重塑了外在的东西,正如它塑造了内在的东西一样。

        界限上下文模式是用于定义物理边界和所有权边界的领域驱动设计工具。        

       物理边界   

        界限上下文不仅作为模型边界,而且作为实现它们的系统的物理边界。每个界限上下文都应该作为一个单独的服务/项目,这意味着它的实现、升级和版本控制独立于其他界限上下文。界限上下文之间清晰的物理边界允许我们使用最适合其需求的技术栈来实现每个界限上下文。

        正如我们前面所讨论的,界限上下文可以包含多个子域。在这种情况下,界限上下文是一个物理边界,而它的每个子域是一个逻辑边界。逻辑边界在不同的编程语言中具有不同的名称:命名空间(namespace)、模块(modules)或包(packages)。

        所有权边界                    

        研究表明,好的篱笆确实能造就好邻居。在软件项目中,我们可以利用模型边界:界限上下文,来实现团队的和平共处。团队之间的工作分工是可以使用界限上下文模式做出的另一个战略决策。界限上下文应该只由一个团队实现、升级和维护。没有两个团队可以在相同的界限上下文中工作。这种隔离消除了团队可能对彼此的模型做出的隐含假设。相反,他们必须定义通信协议,以显式地集成他们的模型和系统。

        需要注意的是,团队和界限上下文之间的关系是单向的:一个界限上下文应该只属于一个团队。然而,一个团队可以拥有多个界限上下文,如下图所示。

        

界限上下文和团队关系

      现实生活中的界限上下文

        确实,界限上下文不像业务域和子域那么明显,但它们确实存在,就像领域专家的心智模型一样。您只需要意识到领域专家如何思考不同的业务实体和流程。

        我想通过讨论一些例子来结束这一章,这些例子表明,当我们在软件中建模业务领域时,不仅有界限上下文,而且在不同的上下文中使用不同的模型的概念在生活中普遍存在。

      语义域

        可以说,领域驱动设计的界限上下文是基于语义域的词典编纂概念的。语义域被定义为一个意义区域和用来谈论它的词语。例如,这几个词“监视器”、“端口”和“处理器”在软件和硬件工程语义域中具有不同的含义。

        不同语义域的一个相当奇特的例子是“番茄”这个词的意思。

        根据植物学的定义,果实是植物传播种子的方式。果实应该从植物的花朵中生长出来,并且至少有一颗种子。另一方面,蔬菜是一个总称,包括植物的所有其他可食用部分:根、茎和叶。根据这个定义,西红柿是一种水果。

        然而,这个定义在烹饪界几乎没有什么用处。在这种情况下,水果和蔬菜是根据它们的味道来定义的。水果质地柔软,有酸有甜,可以生吃,而蔬菜质地较硬,味道较淡,通常需要烹调。根据这个定义,西红柿是一种蔬菜。

        因此,在植物学的限定语境中,番茄是一种水果,而在烹饪界的限定语境中,它是一种蔬菜。但这还不是全部。

        1883年,美国对进口蔬菜征收10%的税,但不包括水果。根据植物学对番茄的水果定义,向美国进口番茄无需缴纳进口税。为了填补这个漏洞,1893年美国最高法院决定将西红柿归类为蔬菜。因此,在有限的税收背景下,番茄又成了一种蔬菜。

      科学

         正如历史学家尤瓦尔·诺亚·哈拉里所说:“科学家们普遍认为,没有任何理论是百分之百正确的。因此,真正考验知识的不是真理,而是实用。”     。 换句话说,没有一种科学理论适用于所有情况。不同的理论适用于不同的环境。 

      买一个冰箱

        最后,让我们看一个现实生活中界限上下文的更实际的例子。你在下图中看到了什么?

        

纸板儿

         它只是一块硬纸板吗?不,这是个模型。这是西门子KG86NAI31L冰箱的一种型号。如果你查一下,你可能会说这块硬纸板看起来一点也不像那个冰箱。它没有门,甚至它的颜色也不一样。虽然这是事实,但这无关紧要。正如我们所讨论的,模型不应该复制真实世界的实体。相反,它应该有一个目的:一个它应该解决的问题。因此,关于纸板的正确问题是,这个模型解决了什么问题?

在我们的公寓里,我们没有一个标准的厨房入口。纸板被精确地切成冰箱宽度和深度的大小。它解决的问题是检查冰箱是否能通过厨房门。

        

厨房门口的纸板模型

         尽管纸板看起来一点也不像冰箱,但当我们不得不决定是买这个型号还是选择一个小一点的型号时,它被证明是非常有用的。再说一次,所有模型都是错误的,但有些模型是有用的。制作冰箱的3D模型绝对是一个有趣的项目。但它能比硬纸板更有效地解决问题吗?没有。如果纸板适合,3D模型也会适合,反之亦然。用软件工程的术语来说,建立一个冰箱的3D模型将是一个笼统的工程。

        但是冰箱的高度呢?如果底座合适,但太高了,无法塞进门口怎么办?这样就可以用胶水把冰箱的3D模型粘在一起了吗?不。用一个简单的卷尺来测量门道的高度,这个问题可以更快更容易地解决。在这种情况下,卷尺是什么?另一个简单的模型。

        所以,我们最终得到了两个相同型号的冰箱。用两个模型,每个模型都针对其特定的任务进行了优化,反映了DDD方法对业务域进行建模。每个模型都有其严格的限定环境:纸板证明冰箱底座可以通过厨房入口,皮尺证明它不会太高。模型应该省略与手头任务的无关信息。此外,如果有多个模型,就没有必要设计一个复杂的多面手模型,更简单的模型可以有效地单独解决每个问题。

      总结

        每当我们在领域专家的心智模型中遇到内在冲突时,我们必须将统一语言分解到多个界限上下文中。统一语言应该在其界限上下文的范围内保持一致。但是,跨越多个界限上下文时,相同的术语可能具有不同的含义。

        在发现子域的同时,界限上下文就被设计出来了。将领域划分为界限上下文是一项战略设计决策。

        一个界限上下文及统一语言可以由一个团队实现和维护。没有两个团队可以在同一个界限上下文中共享工作。然而,一个团队可以处理多个界限上下文。

        界限上下文可以将系统分解为物理拆分:服务、子系统等等。每个界限上下文的生命周期都与其他上下文解耦。每个界限上下文可以独立于系统的其余部分发展。然而,界限上下文必须一起工作以形成一个系统。有些更改将无意中影响另一个界限上下文。在下一章中,我们将讨论集成界限上下文的不同模式,这些模式可用于保护它们免受级联更新的影响。

        

                 

        

        

        

        

        

        

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值