域建模是困难的。教学和学习域建模更加困难。因此,我的目标是帮助您学习这个巨大的主题,让您对领域驱动的意义有一个坚实的基本理解。概念概念和挖掘示例是本系列的意义。人们经常直接潜入开发带有代码的业务线应用程序 (LoB),但在实施可能导致灾难之前不知道 DDD 真正代表什么。从历史上看,单体建筑一直是王道,微服务也慢慢被采用。

img

在我开始学习 DDD 之前的我的照片

互联网上有很多框架更倾向于在实施中使用 DDD 方法,但仅仅因为它听起来合适,就封装了大量原则,这还不够好。决定背后必须有一个明确的推理,我们将研究实施 DDD 的具体领域和好处,这样做是有意义的。到本系列结束时,您不仅会看到 DDD 不仅仅是一组模式,而且希望也能理解它背后的哲学。在我们破解它之前,有一些先决条件需要井然有序。在您成为 DDD 思维发展专业选手之前,揭开这些复杂先决条件的神秘面纱至关重要。

这个系列试图把超复杂的词汇和抽象这些部分到简单易于消化的图纸和小块的信息。希望所有的流行语对你更有意义,你觉得准备潜入DDD的世界。其次,本系列将作为软件工程概念新成员的起点,建议在选择学习路径之前从上到下遵循。

img

如何成为 DDD 中的专业人士的游戏计划

本系列将包括多个部分。介绍部分分为两部分(您现在正在阅读第 1 部分)。每个曲目将至少有一个部分(在编写时不确定数字)。这是前面提到的建议,在潜水头首先进入您的特定选择领域之前完成。您可以选择稍后了解有关业务轨道或开发人员跟踪的更多情况。通过保持对流程的合作,您应该在系列结束时拥有足够的知识,以便通过实际方法和实现继续您的 DDD 之旅。每个各自的轨道都有自己的焦点, 也许你甚至会完成他们所有?真棒, 现在我们开始吧!

免责声明:作为一名数据科学家,在过去的 4 到 5 年里,我本人作为一名软件工程师,没有随时了解软件集成中概念和设计原则中的最新趋势。因此,我总是乐于阅读本系列后产生的更正、修复、建议和其他有用的想法。该系列节目源于无数小时的阅读、与受过教育的人交谈、观看教程和 YouTube 视频。

让我们先列出我将从介绍段落中摘录的行话。

• 微服务

• 单体建筑

• LOB(业务线)应用程序

我相信,一旦我们继续解释这些概念,就会出现新的问号,我们将继续指出并解释这些概念。

微服务

img

微服务架构

微服务架构寻求将其组件(服务)打包成完全独立的单元。这是最简单的方法。一切都应该脱钩,以便每个微服务可以独立扩展。以前,软件项目往往是大单体怪物,高度耦合在一起,难以维护。您通常选择编程语言和过程,然后坚持使用它。但是,使用 Microservice,您可以自由选择每个特定工作的最佳工具。当开始一个项目时,你可以从一些更大的服务开始,并把它们雕刻成微服务,因为逻辑边界揭示了自己。但是,如果您正在努力阐明将更大服务拆分为微服务的推理,那么也许最好的前进方式是保持更大的服务原样。通过模块化工作,就像微服务允许您一样,如果一个微服务出现故障,您更有可能快速解决问题并避免严重的系统故障。您确切地知道管道的哪个部分会发生故障,因此您可以发布修复程序并重新部署该精确的微服务,而不必关闭软件项目的整个单体怪物。显然,在选择走这条路之前,你应该注意一些权衡,但我的工作是在行话上产生共鸣,而其他许多人则提出了利弊。

单体建筑

img

单体建筑

关于单体建筑的令人敬畏的是,他们已经证明了时间的考验。他们仍然工作和做他们的工作。许多企业架构仍然建立在这种方法之上,但其明显的缺陷是更新它们的复杂性。它们不仅可以建立在长期废弃的框架之上,使得它们难以保持相关性,而且人们继续前进,最初构建大黑匣子的开发团队不一定是继续进一步发展它的同一团队。因此,单体建筑的最大优势也可以被视为其最大的缺陷。相比之下,在微服务领域,一切都是脱钩的,各部分通过API的作品相互交流。野兽被分成小得多的块,这是更容易为开发人员消化。

业务线 (LoB) 应用程序

img

业务线 (LOB) 应用程序

业务应用线是一种应用,它比其他软件对业务更重要。例如,Word、PowerPoint 或电子邮件不是 LoB 应用程序,而是帮助您在工作日的工具。LoB 应用程序更直接地与为业务创造收入保持一致。换句话说,这些应用程序是业务的关键,甚至收入的创造者本身。许多公司开发定制软件以满足他们的需求,这些通常是需要工作的使命关键软件。对他们来说,这将是一个业务应用程序行。对于一个简单的概念,从字面意义转向 IT 流行语部分,解释非常简单。

高层管理人员做出技术选择时的问题

一个经常适用于现实世界场景的问题是,高层管理人员在没有合理推理的情况下做出技术选择。如果开发人员要应对这些选择,管理层必须传达做出决策的原因。如果没有,则可能会发生如下图示这样的场景。

img

使用正确的工具进行工作

我的观点是:使用有意义的技术。在别人眼里,替代方案可能更好,但您仍必须评估什么最适合特定场景或使用案例。批判 - 没有银弹!

通过继续这个系列,我不仅会帮助你了解IT行话的核心基础知识,已经找到了它在领域中的位置,但我也会给你的事实,提示和技巧。只要寻找灯泡插图!

img

如果您是开发人员,这些信息片段很方便,但如果您只是对扩展知识感兴趣,这些信息片段也很有用。我将链接您到一些惊人的资源存在,以便您可以深入潜水,并继续您的快速增长。该系列的下一部分的一些资源甚至是由 Raa 实验室团队创建的, 这有多酷?

往前走…

这是有趣的部分开始的地方, 但我们仍然在介绍阶段!所以,如果你迫不及待地想深入到你选择的轨道,我建议你保持紧一点,让你掌握所有的概念。这是介绍阶段的第一部分,但在分离到您选择的轨道之前,我们还需要一部分。

我们现在介绍了雕刻整体软件架构的最常见方法,并解释了一些基本术语。

我们现在将深入挖掘这个系列是什么:**掌握大野兽,领域驱动设计(DDD)。**现在需要解释更复杂的词语,并揭示令人生畏的原则。但别担心!我们将尽最大努力保持简单愚蠢(KISS)。

领域驱动设计

本节将讨论和思考下一个主题:

• 什么是领域驱动设计?

• 域名

• 模型

• 无处不在的语言

• 蒸馏 DDD 的问题空间

• 绑定上下文和子域

• 蒸馏 DDD 的解决方案空间

• 拆包战略 DDD 与战术 DDD

软件是为了解决问题而制作的,而以 DDD 思维模式编写的软件不会回避这一事实。然而,编写软件的人通常会直接潜入框架和代码中,而缺少针对特定问题的关键支持信息。记住你昨天写的代码实际上做什么, 有时也是一场斗争。如果你与它斗争, 你可以打赌一个新的开发人员也会!开发中的可维护性和编写不言自明的代码通常既困难又耗时。

围绕开发人员团队和其他利益相关者的人,往往回避开发过程,参与不够。这可能导致人们谈论自己的语言,而开发团队并不真正理解他们传达的内容。反之亦然…

这不是 DDD 的工作原理!调整昨天完成它, 这是 DDD 试图解决的实现。在直接进入此实现之前,您需要了解 DDD 的要点,并深入了解该概念在重述时实施的领域。而这正是DDD的重点,域。DDD 的口头禅是,试图将 “共性"和"协作"带入项目的主要重点。因此,不仅提高对非开发者领域的关注,而且提高开发人员的关注。DDD 拥有处理项目周围不一致的具体愿景和方法,有助于管理其对手头领域日益关注的问题。那么, 什么是真正的域, 为什么域名除了在名称中有单词 [域名] 之外对 DDD 如此重要?让我们来看看。

img

DDD 空间中的经典挑战

什么是领域驱动设计?

**但首先…**说实话, 我读了埃里克 · 埃文斯的书, 读起来相当多。超级全面,坦率地说,很难理解。因此,我没有放弃学习DDD,而是在别处找到了帮助。Infoq 有一个简短的总结版本, 基于 [蓝皮书] 称为 +领域驱动设计快速] 。我读了它, 我立刻就喜欢它了。另一个灵感来自斯科特·米利特与尼克·图恩合著的名为《领域驱动设计的模式、原则和实践》的书。我的灵感来自这两本书,这些书就是用这些书制作的。如果您有兴趣了解更多有关 DDD 的知识,我建议您阅读这些内容,以进一步扩大您对该主题的了解。请记住,这些书比我们本系列要涵盖的内容更深入。所以,如果你想保持高水平的话题,继续阅读!

img

埃里克·埃文斯领域驱动设计概述

看着上面的插图,你可能会觉得有点困惑。但不要担心,我的目标是打破障碍,阻止我们理解图片的真实说明。这个数字来自埃里克·埃文斯的书,并概述了领域驱动设计。为了理解这个主题,我们将不得不把数字分成小而易于理解的副题,并从那里开始工作。

让我们从了解什么是域开始。

领域

领域是应该通过设计软件来解决的问题空间。

img

转移焦点

领域通常是设置环境中的复杂变量集合,这些变量可以收缩、扩展和演变 - 具体取决于您如何定义边界。对于复杂的环境,你不能坐下来写代码,而不了解它的本质。

考虑船舶制造商的比喻。一艘船可以由数十万个部件组成,而从事船舶开发工作的工人由于其份额规模,对建造船舶的所有制造产品没有全面的概况。工人们把注意力集中在船舶的某一特定区域,并完成这一工作,而其他工人则同时在船舶的其他部分工作。换句话说,进展同时发生。在船尾工作的工人不需要确切地知道船前的进展情况,因为这已经不属于他的范围,不会影响他正在做的工作。

img

船舶制造商

然而,有些人的工作是从大局出发,了解船舶发展的确切状况。这些人对全面进展有更好的概述,但不需要知道确切的实施,因为需要特定的知识。只要工作完成,他可以看到整体的进展,他很高兴。现在,我们从致力于实施细节的人员,到对总体进度有概述的项目负责人。在这两个角色之间,还有很多。我们每个级别都上下起落,需要新的知识来理解正在完成的工作的界限以及如何去做。

软件类似于船舶制造商看到的复杂性。如果我们要为船舶制造制作软件,我们将不得不更多地了解船舶制造领域。船舶需要满足大量要求,如果不对该领域有充分的了解,就不可能编写出良好的船舶制造软件。在琐碎的情况下,你可以直接跳入代码,但在复杂的环境中,必须作出很多考虑。

那么,您如何了解域?通过让专家参与。域名专家。通过让那些真正了解我们为什么做决定的人参与其中。这些人将转移知识,最终将反映该领域的核心元素,以产生良好的船舶制造软件。要增强一个域,并在其中种植定制软件的根源,你必须了解它并建模它。

因此,现在我们了解什么是域,我们如何在代码中表达它?这是本系列后端轨道中的特定主题。为了更好地概述一般 DDD,我们还需要处理更多的主题,保持解释简短和简洁将有利于我们前进。我们还没有对域进行建模,而该域名对于正确实施域至关重要。那么,我们为域建模是什么意思呢?

DDD 的三点摘要取决于术语的定义:

• 关注核心域

• 探索领域从业者和软件从业者的创造性协作模式

• 在明确限制的上下文中说无处不在的语言

这些要点是直接从埃里克·埃文斯DDD参考小册子。我们已经详细阐述了第一个任期,并将探讨第二个任期。

简单地说,模型是目标域的表示或抽象。为了以简单易懂的方式绘制域,我们需要组织信息,系统化信息,并将其分成较小的块,因为我们的思维过程被合成到这个模型中。有时,您需要排除域的某些部分,因为它变得过于庞大和复杂。目前,这将是我们对模型的阐述。今后,我们将给出具体的例子,并可视化模型的外观,将域的关键元素提取到抽象中。

让我们稍后重温模型表示,目前保持速度,从三点摘要直接潜入第三个要点。议程上的下一个主题对于理解以向前迈进至关重要,并被视为 DDD 的核心组成部分之一。

无处不在的语言

DDD 的一大部分是保持所有通信的语言,对领域有意义,以便所有利益相关者充分了解对方,并能够高效工作。为了建模域,您需要以某种方式进行通信。那我们是什么意思呢?我们说的是英语还是法语?嗯,不是真的。其理念是定义开发人员可以实现到代码中的语言,以便从外部理解该语言。当然,您必须使用实际语言作为沟通的核心基础,但我们之前提到,开发人员需要将域实施为有形代码。这是开发人员在其代码中提出类名、变量等的地方。为了让开发人员想出合理且定义良好的变量和类名称,开发人员需要尽可能简单地编写它们,同时保持域名的特定性,以便如果新开发人员进入,他理论上应该理解和理解域名,同时了解代码的作用。这一切听起来很好, 但我确实故意在理论上写了 [100》,因为实际上, 这并不容易。

img

不同语境中令人困惑的单词

你可能想知道为什么这这么难。嗯,每个人都有自己的沟通风格,融入这种风格是想法和个人对主题的理解,对其他人来说可能不一样。如果你看看上面的云这个词,他们各自领域的专家有自己的沟通方式。在左边,你有一个船舶制造商,谈论液压和锻造等。另一方面,您让开发人员谈论他们的域名。当提出域模型时,您必须与域专家进行沟通。这些专家将使用他们的行话,而开发人员将调整自己的语言,以讨论在设计方面的领域。如果执行方与关键利益相关者之间存在理解障碍,域名实施将绝对受到此的影响。如果日常讨论与代码中嵌入的术语断开,则来自域专家的瞬态信息在实施中可能无法正确封装。因此,为沟通和实施提供无处不在的语言是项目最重要的部分之一,以便使其取得成功。

简言之,**学习域!**而这样做的过程,就是不要强加一种新的语言。而是拥抱这个领域,并理解它。认识到语言的更改是模型的更改。通过尝试反映替代模型的替代表达方式来消除困难。然后重构代码、重命名类、方法和模块以符合新模型。(埃里克·埃文斯,2014年6月)

罗伯特·斯莫尔希尔用一种简短而简洁的方式来描述无处不在的语言。在爱丁堡举行的欧元蛇会议上,他把这种无处不在的语言归结为以下几个关键要点:

• 上下文依赖

• 在适用性范围内有效

• 问题领域专家社区使用

• 共享含义

• 单一含义

• 在软件模型中表达

• 缩短问题和解决方案之间的距离

我认为罗伯特的接受几乎概括了无处不在的语言的意义。如果你想看他的演讲,我已经把它链接在本文底部的引用部分。

img

当开发人员被排除在外时,会出现混乱

领域讲故事

域讲故事是一种知识处理技术。参加域名讲故事研讨会的人将对该领域有新的见解。由此产生的域故事表达了他们共同的理解。其他建立域知识的方法包括场景(沃恩·弗农)和情景探索(埃里克·埃文斯)。域故事可帮助您提出场景并可视化它们。我建议阅读斯特凡·霍弗和海宁·施温特纳关于域讲故事的书。这本书涵盖了域讲故事的要点,并用易于理解的例子来说明它。他们的案例研究之一,说明了这个概念,是基于一个连锁电影院。想象一下,如果你被要求开发一个应用程序,允许他们的客户进行预订和购买电子门票。为了熟悉域,我们设立了一个域讲故事研讨会。经过反复讨论,您最终将得到一个说明票务系统的使用案例图。

img

影院应用使用案例图

从上面的图示中,您似乎已经涵盖了应根据从域故事会话演变而来的插图使用案例图应用于影院应用的所有功能。但是,您一直在讨论,事实证明,票务系统实际上有能力通过应用程序直接向客户发票。起初没有发现这种情况,但事实证明,票务系统可以发行基于QR的机票:用户将立即获得门票 - 使客户不必在到达时手动从收银员处领取门票要容易得多。这是新的信息!显然,这也应该说明,所以我们更新使用案例图,如下所示:

img

西纳梅应用程序的修订使用案例图

img

https://github.com/WPS/domain-story-modeler

通过这样的知识处理会话,您可以真正确保满足设置的所有要求。很容易被大而复杂的域混淆,但使用域讲故事等技术可以帮助您将问题分解成简单的部分,就像我们在上面的琐碎示例中所做的那样。

蒸馏 DDD 的问题空间

img

领域驱动设计的问题空间

上图是斯科特 · 米利特和尼克 · 图恩如何说明 DDD问题空间的蓝图副本。从外观上看,有几个新术语我们不熟悉。让我们在下一节中讨论这些内容,但首先概述一下我们正在研究的内容。

蓝图从了解问题领域和业务愿望开始。从那里,域名专家和开发团队坐在一起,了解域的语言 - 无处不在的语言。一旦语言被设置,每个人都在同一水平上,他们通过域知识嘎吱作响。此时,开发团队应准备好将蒸馏的域知识实现为代码。他们将代码拆分为具有适当模型的适当子域。希望开发团队已经理解了域名专家所设想的域名愿景。关注核心域至关重要,因为这是系统构建的主要原因。

绑定上下文和子域

有界限的上下文定义了无处不在的语言的适用性限制。由于域经常会变得非常复杂和庞大,因此将域提炼成更小且独立的模型是一种好方法。因此,您没有为域名提供一个大模型,而是有许多较小的模型,这些模型经过正确定义,并具有要封装的内容的具体边界。许多较大的域名将具有多个边界上下文。因此,具体词语的含义将根据其所属的界限上下文来确定。因此,我们可以说,一个词的意思很容易理解在上下文。边界上下文是对特定模型中存在的边界的描述。

让我举一个例子。请考虑以下数字:

img

单词有不同的含义,这取决于它们的上下文起源

正如你所看到的,这些单词清楚地指向不同的东西,这取决于上下文,即使他们拼写的方式相同。这些话很容易造成混乱,除非你知道你指的是哪个模型,以及我们正在谈论哪个边界上下文。保持不同边界上下文之间的强脱钩使大型系统更简单。

“服务"一词在餐厅环境中与网球相关语境完全不同。设置和浇注也是其他示例。

来自 developer.com的 Alireza以简单易懂的方式解释了子域的概念,以及它与边界上下文的区别。重要的是要知道,子域不同于有界限的上下文。

大问题域可以分解为子域来管理复杂性,并将重要部分与系统的其他部分分开。

img

不同类型的子域

我们根据它产生的竞争优势来区分三种子领域:

  • **核心域:**系统最重要的部分,成功的原因。这将给你竞争优势,所以专注于这一点,并使这尽可能好。
  • **通用域:**这不是核心,但核心取决于它。例如电子邮件发送服务、监控服务等。尝试重复使用现有部件,不要在这些系统上花费太多时间。
  • **支持域名:•**帮助支持核心但不提供任何竞争优势的额外 10 月域名。不建议大量投资,但仍需要在核心领域取得成功。甚至可能在这里外包?

从上面的要点中,您可以清楚地看到某些域类型比其他域类型更重要。在更大的领域;您通常将域划分为较小的域。在子域的上下文中,每个子域都可以存在一个独立模型。这一点很重要,因为不仅需要一个模型,而且每个域的模型也很多。与子域不同,有界限的上下文是一种具体的技术实现,在应用程序中强制执行模型之间的边界。

如何专注于核心域

将大问题视为一个大问题,往往会导致失败。常见做法是将大问题域划分为较小的子域,以管理复杂性并将重要部分与其他部分分开。在屠宰领域,猪被切成小得多的碎片,就像问题空间一样。如果了解子域,您可以轻松地分解问题空间。(斯科特 · 米利特和尼克 · 图恩)对子域有非常有效的观点。

子域是抽象概念:不要将子域与公司的组织结构混淆。子域代表功能领域、定义业务流程以及表示系统的功能。

通过以这种方式攻击问题空间,您应该能够更容易地征服它,并降低大问题的复杂性。

我强烈建议阅读他们的书,因为它清楚地说明了这些概念,在这个系列的许多数字是根据斯科特和尼克的原作重新创建。

img

一头标有切口的猪

以蒸馏问题域为例

让我们考虑在线拍卖网站的域名模型。正如我们所料,在线拍卖中有很多元素,其中很多对于域名和特定业务来说都是独一无二的。 起点:

img

现在,我们需要根据有意义的内容将域划分成较小的分区。拍卖网站内的会员负责注册过程。卖方是另一个分区,负责处理与卖方活动有关的所有行为。拍卖是管理拍卖时间和处理投标活动的问题领域。列表负责拍卖网站上的列表。最后,我们有处理成员和卖家之间所有争议的争议解决方法。拍卖网站没有这些部分,也许有些没有解决争议的制度,或者有些没有我没有列出的其他部分,这不是一成不变的。为了这个例子,让我们使用上述作为基础,因为我们将每个人的分离分类为亚域。

img

此时,您已经从领域专家中提炼出知识,并揭示了问题的不同部分。我们知道,有些部分是独一无二的,有些是相互依赖的。现在是时候将每个部分分类为称为子域的适当分区了。

img

**我们的拍卖网站成功的决定性因素是什么?**这些重要部分应归类为核心域。值得一提的是,你不仅需要有一个核心域,但可以有很多,如果它有意义。

拍卖网站的核心域名是卖方和拍卖。卖方域名包含卖方的评级和确定卖方费用所需的域逻辑。然而,拍卖核心领域包括处理投标和运行拍卖的机制。这些都很重要。会员域名和上市域名通过提供创建帐户和查找待售项目的可能性来支持核心域名。争议解决域是通用的,因为它可以与现成的软件一起服务。这方面的一个例子可能是票务系统。

主要的想法是知道在哪里投资,在哪里投入你的努力,你可以外包和从其他地方获得哪些部分。所有这些将域划分为子域的决策都是知识紧缩会议的结果,这些会议不仅是域专家的一部分,也是开发人员在协作中帮助他们掌握和理解域的结果。

这些子域将帮助您制定解决方案。

img

图示域分离

这个过程产生了两个系统。域名的一部分可以通过现成的包完成,而核心和支持域名是使用自定义 Web 应用程序构建的。

如果我没有核心域呢?

企业建立而不是购买软件的原因有很多。如果你能做到这一点更便宜,更快,或更聪明,那么它是一个很好的候选人的定制建设。

蒸馏 DDD 的解决方案空间

img

领域驱动设计的解决方案空间

解决方案空间涵盖可以塑造应用架构并使其更容易管理的模式。DDD 在建筑上是不可知论的,因为没有单一的建筑风格,你必须遵循实现它。

模型之间的不匹配

模型之间的不匹配是如何发生的?为什么纠正这一点如此重要?我提到,没有一个单一的建筑风格,你必须遵循,以实现DDD,因为它是建筑不可知论。然而,有些架构在历史上没有像其他架构那样与 DDD 思维一致。制作单体建筑的通常方法倾向于瀑布式方法,您可以提前规划整个系统。直接潜入整个解决方案的 UML 草图并不总是解决问题的最佳方式。域名专家和业务分析师创建分析模型并将其交给开发人员后,如果开发团队不参与域知识处理,分析和代码模型可能会相互背离。

当开发人员开始在代码中实施分析模型时,他们经常发现建筑师制作的高级文物与构建系统的现实不匹配。模型需要在明确的上下文中隔离和定义,以便保持纯洁和专注。但是,在这个阶段,开发人员通常没有反馈循环来与企业和架构师交谈,因此可以更新分析模型,并制定其输入。相反,开发人员偏离了分析模型,他们的实现往往忽略了重要和描述性的域术语和概念,这将提供更深入的洞察和理解的域(斯科特·米利特和尼克·图恩)。

img

当双方没有共同努力合作时,重要概念就会丢失和误解。适当的无处不在的语言将有助于两种模式保持一致。这是反馈循环的额外重要性发生的地方。

采用更统一的团队方法表明,在进行 DDD 时,协作工作比任何其他实践都重要得多。拥有恒定的反馈循环有助于发现不会被误解为无处不在的语言存在的重要概念。由于语言无处不在,这两种模式也将相互联系。代码的更改将而且应该反映分析模型的变化,因为这两者之间的协同作用的重要性。

那么,如何通过 DDD 实现来潜在地解决问题,以及如何构建架构呢?一个工具是通过事件风暴会话的工作想出一个上下文地图!我们将在一秒钟内了解更多有关事件风暴和上下文映射的信息。首先,我们需要解开DDD的战略要素。

拆包战略 DDD vs 战术 DDD

还记得之前所有我们不明白的盒子的大复杂图像吗?现在是将其分成两部分的时候了,分别分为战略和战术两部分。通过拆分它,我们可以定义某些边界并处理与该部分相关的元素。战略模式塑造了解决方案,而战术模式则用于实施丰富的域模型。

但是为什么把它拆散是有道理的呢?

阿内斯·哈西奇在一篇我强烈推荐阅读的中篇文章中很好地总结了这一点。我们还没有达到下面的帖子中提到的所有概念,但最终会达到这个点。

DDD、CQRS 和事件采购的十年对于那些还没有真正通过蓝皮书的人…medium.com

埃文斯早些时候曾表示,他后悔把战略模式放回书的结尾,这可能导致许多人更加重视战术模式,因为它们排在第一位,甚至更糟,他们陷入了复杂的战术模式实施细节,他们甚至没有得到这本书最重要的部分。

要消除的是,构建基块为您提供了实现 DDD 的工具,但您应该更加关注战略模式,更应该关注战略模式,因为战术模式/构建基块将继续演变,有些将过时,将添加新的模式(例如域事件)。

让我们先看看战略方面,然后再进入战术方面。

战略 DDD

img

领域驱动设计的战略方面

从图中看元素,我们已经涵盖了其中的一些元素。在我们结束战略篇章之前,诸如连续集成、泥球、上下文地图等元素值得多谈。

连续集成

连续集成 (CI) 是开发人员的一种实践,它的目标是共享代码存储库并高频推送。基于开发人员的这些承诺,更大的构建和释放管道触发应用程序的连续部署 (CD)。这是一个自动过程,可检查代码的完整性,并有助于检测在最新提交过程中可能引入的问题。DDD 非常强调这种做法,因此在战略 DDD 数字中引用了这一点。有些组织在这些做法上可能有困难,特别是如果他们的经验在很大程度上与不太灵活的发展模式有关,例如瀑布模型等。(安杜·鲍威尔-莫尔斯)

泥球大(BBOM)

img

一大团泥

泥球是一个杂乱无章的结构,蔓延,草率,管道胶带和捆扎线,意大利面码丛林。这些系统显示出无管制增长和重复、权宜之计的修复的明确迹象。信息在系统的遥远元素之间乱交共享,往往导致几乎所有重要信息变得全球化或重复。

*系统的整体结构可能从未明确定义过。-

*布赖恩 · 福特和约瑟夫 · 约德, 泥球大

如果你正在处理一个传统系统, 一个大球泥, 你会怎么做?您如何品尝 DDD(假设您仍然可以采用迭次开发方法,并能够访问域专家)?

嗯,仅仅因为传统系统,即"泥球"的存在,并不意味着你必须继续狭窄它与新功能,而是在这里使用你的上下文映射技术。画一条线围绕它,并说,“这是我的大球泥”,之后画一条线围绕您的新服务,并把它作为一个单独的边界上下文。

正如埃文斯所说,你的服务最终被泥球包围可能是不可避免的(因为它几乎可以吃任何东西),但至少你跑得不错。阿内斯·哈西奇)

上下文映射

TLDR;用图示的集成点定义的边界。

如何识别现有问题空间?然后,您如何将域划分为子域并创建有边界的上下文?通过事件风暴的工作!您将在下一个即将到来的主题中了解有关事件风暴的更多信息,但通过事件风暴的工作,您将获得一个结果的上下文地图,该地图基本上绘制了现有地形的地图。但是为什么这很重要呢?

在大型和复杂的应用中,上下文中的多个模型协作以满足系统的要求和行为。单个团队可能不拥有系统的所有子组件,有些将存在由不同团队负责的旧代码,其他组件将由第三方提供,这些第三方将不知道将消耗其功能的客户。团队对系统中的不同上下文及其彼此之间的关系没有很好的了解,在整合有限制的上下文时,可能会损害正在发挥作用的模型。如果团队没有明确绘制和理解上下文之间的关系,模型之间的界限可能会变得模糊,从而导致"泥球大战”。(斯科特 · 米利特和尼克 · 图恩)

您可以将上下文地图视为定义边界如何定义项目情况以及边界已划分为不同上下文的定义可视化。 上下文图**不是(!)**在某种企业架构工具中创建的高度详细的文档,它是一个高级的手绘图,传达了所扮演上下文的整体画面。上下文图应该足够简单,以便域专家和开发团队都能够理解。除了明确标记团队理解的上下文,该图还应显示系统中未被很好地理解的区域,以反映代码库的混乱且往往难以理解的现实。(斯科特 · 米利特和尼克 · 图恩)

这似乎有点混乱, 让我给你一个上下文地图的例子:

img

上下文地图示例

上图说明了上下文图。您可以看到,有一个反腐败层,保护人力资源背景免受招聘上下文的影响。这是因为招聘上下文是第三方,容易产生其他不应影响我们主要语境的力量。我们将进一步深入探讨 ACL(反腐败层)。

上下文地图反映现实,显示当前状态下的代码,而不是理想的未来状态,这一点极为重要。上下文地图不需要显示模型的细节;相反,它们必须演示边界上下文之间的集成点和数据流。除了连接点之外,我们还没有在上下文图上说明关系状态,因此了解更多关于我们如何说明关系流的案例是下一个主题。

上下游关系

DDD 上下文图中的一个非常重要的因素是两个上下文之间的关系方向。DDD 使用上游或下游术语:上游上下文将影响下游对应词,而相反的情况可能并非如此。这些通常分别缩短为字母 d 和您。这可能适用于代码(根据彼此的库),但也适用于技术因素较少,如计划或对外部请求的响应。在下面的示例中,您有一个上下文图,其中说明了个人理财管理应用程序,该应用程序通过 API 与网上银行服务对话。因此,在这种情况下,PFM应用程序是下游,网上银行服务是上游。我们将更深入地探讨进一步深化这种关系。

img

一个好的上下文地图会给你一张对你不利的赔率的图片。您可能知道组织是否有意识地工作 - 反对您的项目的成功,甚至在项目开始前。

InfoQ 有一个易于消化的示例,说明基于 Web 的个人财务管理应用程序 (PFM) 的上下文地图可能是什么样子。PFM 旨在跟踪预算、管理银行账户、股票等。在应用程序中,“帐户"一词可能有不同的含义。在银行方面,账户被视为"货币的容器”。但是,在另一种情况下,请采用 Web 应用程序上下文:帐户有不同的含义。在银行方面,您期望的属性,如余额,帐号,IBAN等。对于 Web 应用程序,您具有与身份验证和用户凭据相关的属性。换句话说,不是同一个概念。在这一点上,我们遇到了与"帐户"一词有关的模糊性问题。现在,我们开始看到无处不在的语言的含义。

img

因此,当我们有模棱两可的案例,我们需要一个工具,将域分到更小的更有形的边界上下文,以确保整个团队意识到存在不同的概念。这就是上下文地图闪耀的地方。如前所述,上下文地图不是超高保真度插图,而是更多的草图,表明上下文可能有点蓬松,难以定义,因此需要有一个"粗糙"的外观。

img

统一建模语言 (UML)

UML 是数据相关建模领域的行业标准。使用 UML 图,您可以轻松地勾勒出整个系统的高度细节。在编程和项目工程中,UML 广泛用于绘制显示属性、方法、参数等的类图。此图是开发人员要实施的类的"视觉表示”。因此,使用 UML 来展示基本概念将简化上下文地图、模型和代码之间的抽象。UML 是描述软件系统的一种语言。首先是软件。领域驱动设计侧重于了解域专家的实际概念。所以,这是人第一。但这些只是工具,选择一个不会间接地使另一个无效。

正如马丁·福勒所说:

“任何傻瓜都可以编写计算机可以理解的代码。优秀的程序员编写人类可以理解的代码。

如果程序员从人类对形势的现有理解开始,这种情况更有可能发生。因此,UML 可以用来以更有形和说明性的方式表达代码,而不仅仅是屏幕上的大量文本。

让我们为银行帐户绘制一个简单的类表示,并进一步深入探讨上下文地图的概念。

img

UML 示例

建模相同的概念

那么,当概念相同但以多种方式使用时会发生什么情况呢?请考虑上面所示的银行帐户类。一些 PFM 应用程序允许我们管理付款,通常保留支付方注册表。在这种情况下,收款人可能与一个或多个银行账户关联。但对于这种情况,我们不会知道任何关于收款人银行账户的内部,也不能做任何操作的银行帐户…将派伊账户与我们刚才定义的银行账户类一起建模有意义吗?

img

从现实情况中可以预见,我们的收款人账户可能与我们的银行账户在同一实体银行,但我们不应对收款人银行账户进行任何操作,也不应跟踪其上的任何操作。所以从概念上讲,这是没有意义的。这是同一应用程序中两种不同上下文的简单示例,其中单独建模是有意义的。我们只是用两种不同的方式模拟相同的域名概念,因为它们要求不同的用途。银行会计可能仍然是一个类,允许我们执行(或跟踪)特定操作(如存款或取款),而单独的类Payee帐户可能有一些共同的数据与银行会计(如帐户数),但一个更简单的模型和绝对不同的行为(我们不应该能够访问收款人余额, 例如)(信息)

img

这听起来可能很明显,但不是。当在类图或 UML 建模工具上工作时,您可能真的很容易开始为具有银行会计属性的 Payee 建模,并认为"我已经为此上过一堂课”。帕夫洛维安试图摆脱代码复制可能弊大于利,有时(信息Q)。

只要我们的域知识增加,上下文图就进化了!现在,我们只是将 PFM 应用程序拆分为两个单独的上下文;银行和费用跟踪。

img

在上下文图上详细阐述

由于对外部一方有依赖性,因此两种背景之间的关系可能会变得脆弱。要么,从我们的角度来看,外部党:可以选择倾听我们的需求并开发符合我们要求的软件,或者他们可以创建使用方(在这种情况下,我们)必须遵守的东西。由于 PFM 应用程序通过 API 与网上银行服务进行交互,我们需要某种保护,防止来自上游环境的变化。这将有助于我们维护银行环境的完整性。最常见的做法是实施所谓的反腐败层 (ACL)。这为流在接受我们的 PFM 上下文之前必须经历的上下文的顶端设置了障碍。在 ACL 中,在两个上下文之间的代码级别上正在进行明确的翻译。一个例子可能是将传入对象从旧模型转换为主要应用程序模型中的域对象。这可以管理两端模型之间的所有细微差异。微软在ACL上有一个相当明确的指南。我建议阅读, 如果你要实现这一点。也可能有一个想法,把一个ACL之间的主要上下文和潜在的大球泥。

img

在组织内部的大局中,还会有其他不是外部的上下文。这些背景可能由其他人维护,并受到不同力量的影响。我们可能需要与这些互动。如果银行和支出跟踪由不同的团队来维护,他们很可能处于伙伴关系关系中:它们都朝着一个共同目标发展(而且上下游没有多大意义,因为它们处于同一水平)。如果通过外部模块实现 Web 用户分析,我们可能会将其"按样"使用,这意味着我们是下游和合规者,用于 Web 用户分析。

img

假设现在我们的 PFM 应用程序变得更大,另一个团队(B 团队)已被分配与我们合作(我们显然是 A 团队)处理同一应用程序的新交易模块。B 团队可能位于不同的房间、建筑、城市、公司或国家/地区,并完全致力于交易区域。在下面的示例中,A 团队与 B 队共享一些代码,即使它们倾向于在代码基基的单独部分工作。最终,B 团队编写了一些类(下面图 12 中的 A),这些类实现了 B 队所需的功能,这些功能在 A 类(InfoQ) 中已经可用。

那是代码复制, 万恶之源!在一个定义明确、有界限的环境中,这绝对是真的。但出于某种原因,这种情况确实发生在几乎每一个非琐碎的项目。这通常是一个迹象,表明可能有不太良好的分离上下文在播放(信息Q)。

上下文地图反映了我们目前对整个系统的理解水平,只要我们学到更多东西或环境发生变化,就会更新。目前,我们不知道到底发生了什么,这是"我们目前的理解水平"。因此,由于我们对域名的交易部分没有 100% 的把握,我们可能需要设置一个说明这一点的标志。这被说明为与我们的PFM应用程序部分重叠的重叠圆元素,并在交叉点上有一个感叹号。

img

图示完整上下文地图示例

只要我们收集更多的信息,地图就会变得更加清晰。如前所述,只需确认我们的应用程序中存在不同的模型,并且模型完整性只能在定义明确的边界上下文中保存,就为我们的域名建模视角提供了许多价值。许多模型在成长时会失去完整性,上下文映射在这个意义上帮助很大(信息Q)。

事件风暴

TLDR;降落在视觉上的流程

img

事件风暴图示

活动作为一个实际便利的研讨会,有许多参与者,包括开发人员,领域专家和其他人。促进者的作用是保持团队的参与和一致,朝着同一个目标:建模领域。本会话中有很多来回,建议该组人员在执行前熟悉 DDD 的概念。事件风暴是 DDD 工具箱中的工具,应用作工具。对于如何进行事件风暴会话,有某些界限。阿贝托·白兰度尼已经写了一本关于这个主题的书,并推荐给那些想更多地了解你如何进行活动风暴会议的人。

菲利普·布高还创造了一个梦幻般的持续指南,如何进行事件风暴。它简短而简洁,并解释了它的核心概念。强烈推荐阅读,如果你不想潜水头先成吨的内容。

战术 DDD

img

领域驱动设计 (DDD) 的战术方面

DDD 图表的战术部分应为您提供构建基块,以帮助您成功实施。这些都是比我们在这个阶段所涵盖的更具技术性的大主题,但我们需要在系列的下一部分涵盖这些主题。

DDD 的两个部分是如何连接的?

通过无处不在的语言 - 代码和分析模型之间的绑定。

此时,您应该有足够的信息来掌握下面的 DDD 插图中正在发生的事情的概念。如果你不能对流程做出有根据的猜测,我建议您在进入系列的下一阶段之前向上滚动并再次阅读讨论的主题,因为我们将涵盖更多可能看起来令人困惑的概念。

img

领域驱动设计 (DDD) 的概念和概述

何时使用 DDD

您何时应该利用领域驱动设计的力量?这是一个很好的问题,很难给出一个答案,因为每个软件项目是不同的。甚至文学也意见不一。有人说,你可以将 DDD 原则应用于每个项目,而另一些人则倾向于在业务逻辑相当复杂和复杂的项目中使用 DDD。我对此采取的是,你必须权衡利弊,为您的特定项目。在某些情况下,DDD 非常合适,但在某些情况下则不适合,尤其是在应用程序具有边际域复杂性的情况下,但反过来则具有很大的技术复杂性。安德鲁·鲍威尔-莫尔斯对这个话题有很好的总结。由于 DDD 如此强调域专家需要(和重要性)生成适当的无处不在的语言,然后项目所基于的域模型,因此,对于域专家来说,一个技术极其复杂的项目可能难以把握,从而导致问题,也许当团队所有成员(Andrew Powell-Morse)都不完全理解技术要求或限制时。

我勾勒出这个简单的绘图,以表示我认为 DDD 可以使用的位置,尽管它不是一个要求:

img

何时使用领域驱动设计原则的矩阵

前进

哇, 太累人了!该系列的这一部分中有很多信息。我很高兴你仍然很坚强。让我们继续注意这一点,并跳进其他相关的副题,有意义地详细阐述。

  • 战术 DDD 构建基块
  • 事件采购
  • CQRS
  • DDD 框架

这些都是大话题。为了不冒险写一本关于这个主题的书,我认为我们应该结束介绍阶段的第一部分。我们将处理这些主题和更多的领领域驱动设计的下一部分像一个专业。在这一点上,你确实对DDD有相当的了解,但仍有一些主题需要反思,以便充分掌握DDD,并能够将其落实到自己的工作中。

敬请期待,以下评论部分将欣赏评论。我努力让你更容易掌握的概念,所以反馈是重要的,并高度赞赏🎉

我想结束在 Infoq 进行的一次采访中, 他们问埃里克 · 埃文斯在试图学习 DDD 时有什么陷阱。埃文斯回答说:

不要试图将 DDD 应用于所有内容。绘制上下文图,并决定您将在哪里推动 DDD 以及您不会在哪里。然后不要担心它超出这些边界。实验很多,期望犯很多错误。建模是一个创造性的过程。- 埃里克 · 埃文斯

特别感谢以下资源给了我灵感和弹药,使这个系列:

引用:

  1. 领域驱动设计:解决软件核心的复杂性(埃里克·埃文斯)
  2. 领域驱动设计参考:定义和模式摘要(埃里克·埃文斯)
  3. 领域驱动设计快速(阿贝尔阿夫拉姆, 弗洛伊德海军陆战队)
  4. 领域驱动设计的模式、原则和实践(斯科特·米利特,尼克·图恩))
  5. DDD、CQRS 和事件采购的十年阿内斯·哈西奇)
  6. 起草功能架构愿景与事件风暴和DDD(菲利普·布尔高)
  7. 领域讲故事 (斯特凡·霍费尔))
  8. 介绍事件风暴 (阿尔贝托·白兰度里尼))
  9. Python 的领域驱动设计模式 (罗伯特 · 斯莫尔郡))
  10. 领域驱动设计 - 它是什么,你如何使用它?(安德鲁·鲍威尔-莫尔斯))