揭开 DDD 的秘密面纱

分享
计算机软件开发 2024-9-9 16:11:18 40 0 来自 中国
序言

范畴驱动筹划(Domain-Driven Design,DDD)提出距今已经有 20 年的汗青,固然前十多年的时间都不停处于不温不火的状态,但不停在坚强的生长。近来几年,微服务大行其道,DDD 也开始遍及了起来。我们完全可以断定,是微服务的热风让研发职员重新发现了 DDD 的代价,再加上灵敏软件开发和 DevOps 的发展为 DDD 的落地铺好了蹊径,DDD 终于咸鱼翻身,星火燎原。可以说,微服务就像是 DDD 的心上人,使得 DDD 真正焕发起了芳华。
微服务架构从提出以来不停没有很好的理论支持怎样合理地分别服务界限,研发职员经常为服务要分别多大而辩论不休,而 DDD 被发现恰好可以补充微服务的营养不良:

  • 服务最大不要大过一个限界上下文(Bounded Context),否则服务内大概会存在有歧义的范畴概念;
  • 服务最小不要小过一个聚合(Aggregate),否则会引入分布式事件的复杂度;
  • 服务间最好通过范畴事故(Domain Event)来举行交互,这样可以让服务保持松耦合。
微服务与 DDD 的团结,让微服务架构看起来似乎更加妥当了。
比年来,学习 DDD 的研发职员越来越多,很多学员反馈 DDD 很秘密,不容易把握。本文实验揭开 DDD 的秘密面纱,包罗下面七层:

  • DDD 发展了 OO;
  • DDD 发展了灵敏;
  • 统一语言;
  • 战略筹划;
  • 战术筹划;
  • 分层架构;
  • 两关联一循环。
面纱一:DDD 发展了 OO

在标准的 UML(Unified Modeling Language)过程中,软件研发被明确的分为面向对象分析(OOA),面向对象筹划(OOD)和面向对象编码(OOP)阶段:

  • 在 OOA 阶段,分析师(范畴专家或业务专家)以需求为输入,完全从业务视角出发,对需求中的范畴概念举行分析和提炼,并定义它们之间的关系,创建分析模子;
  • 在 OOD 阶段,筹划师(架构师)以分析模子为输入,从技术视角出发,增补被分析师忽略但却与软件开发服从息息相干的因素(软硬件平台、数据存储束缚、并发、编程框架...),进一步按照软件工程的要求(各种筹划原则和模式)重塑了分析师给出的分析模子,创建筹划模子;
  • 在 OOP 阶段,步调员(开发职员)根据筹划模子来编写代码,并根据代码的反馈来演进筹划模子。
分析师是业务职员(业务方),而筹划师和步调员都是技术职员(技术方)。OOA 方法固然在理论上是完备的,但在实践中却经常会有标题。由于业务职员在 OOA 阶段缺少技术视角思量,那么分析模子在转化为筹划模子的时间,大概会很难实现,须要通过复杂的转换才能顺应软件开发的要求,因此两种模子就有了比力大的 gap。
在之后的开发过程中,步调员每每只是聚焦于筹划模子,而将分析模子束之高阁。一方从任何研发活动中得到的知识都无法流畅的通报给另一方,导致分析模子与筹划模子之间的差别越来越大,分析模子变得天马行空天南地北,也就失去了存在的意义。
很多体系的真正复杂之处并不在于技术,而在于范畴本身和业务用户及实在行的业务活动。假如在软件筹划时没有得到对范畴的深刻明确,没有通过模子将复杂的范畴逻辑以模子概念和模子元素的情势清楚地表达出来,那么无论我们利用多么先辈、多么盛行的底子办法,都难以包管项目的真正乐成。
DDD 抛弃了将分析模子与筹划模子分离的做法,而是探求单个模子来满意两方面的要求,这就是范畴模子。范畴模子是业务视角和技术视角的交集,它反映了业务职员和技术职员的共识。对范畴模子的创建,必须由业务职员和技术职员告竣同等。随着范畴模子的演进及精粹,技术实现越来越迫近业务的本质,软件体系可以真实反映业务需求,且易于明确和维护。
面纱二:DDD 发展了灵敏

在灵敏软件开发中,团队更倾向于被定义为一个个独立的特性团队。在特性团队内部,业务专家、架构师、开发职员和测试职员要可以或许无停滞的沟通,并团体为特性的端到端交付负责。一种被广泛接受的观点是“软件源代码是唯一真正的筹划产物”,一些偏重技术实践的灵敏软件开发方法(如 XP)极大的推动了这方面的实践:技术职员优先将精力投入到代码上,连续保持代码的清楚和灵活性,通过重构代码来演进筹划模子,并通过主动化测试来确保筹划演进的精确性和安全性。

2.png 技术职员通过代码不停修改实际的业务模子,但这种厘革很难有效通报给业务职员,于是这种厘革就成为了“秘密的角落”。同时,也很难让业务职员以技术职员改变后的业务概念去思考标题。终极导致双方互看不爽,分歧越来越大。因此,看起来匪夷所思的情况,实际上不停都在发生。技术职员不停都在定义业务,只是没有合理的途径让业务职员相识并采取而已。
范畴模子从观念上改变了这一状态,它将各人从各自的领地,也就是业务与技术中,拉到了一个中心地带。范畴模子既不完全属于业务,也不完全属于技术,而是双方共有的部门。于是技术职员与业务职员就有了差不多的话语权,至少有了可以沟通和协同的空间。
一旦业务职员接受了范畴模子,实际上就是放弃了对业务 100% 的控制权,也意味着范畴模子可以或许赋予技术职员定义业务的权利。但范畴模子在给技术职员带来额外的权利同时,也隐含着额外的使命,即技术职员在范畴模子的实现过程中,要接受业务职员的监视与反馈。假如业务职员差别意技术职员对范畴模子的修改,那么技术职员须要尽快修复这种误差,就是说技术职员丧失了对代码 100% 的控制权,也意味着范畴模子可以或许赋予业务职员影响软件实现的权利。让业务职员与技术职员到场到对方的工作中,可以打破双方的知识壁垒,知识通报与沟通的服从就变得更高,反馈速率就变得更快,同时浪费也变得更少,以是说这是一种更好的协同方式。
DDD 发展了灵敏,它显式地把范畴和筹划放到了软件研发的核心,业务职员和技术职员被得到同样的器重,他们通过协同来构建并演进范畴模子,这让灵敏软件开发方法真正的在范畴知识复杂的行业内得以有效应用。
面纱三:统一语言

一样寻常情况下,业务职员嘴里满是业务,技术职员嘴里满是技术。业务职员对标题域的明确很深刻,但却不太关注办理方案域,而技术职员对办理方案域非常熟悉,但对标题域的明确却不充实。随着业务的发展和厘革,双方之间就徐徐形成了一道人为的鸿沟。
统一语言(Ubiquitous Language),也叫通用语言,是业务职员和技术职员共同创建的一套语言,必须在团队范围内告竣同等。团队全部成员利用统一语言举行交换,每个人都能听懂别人在说什么。显然,创建统一语言就是定义团队成员的“平凡话”,团队全部角色在脑海中对范畴知识天生的画面是高度同等的,如下图所示:

3.png 统一语言,将技术职员的思考出发点拉到了业务而不是技术上,也就是从标题出发,这就在肯定水平上填平了那道人为的鸿沟。
业务职员和技术职员怎样创建统一语言?最简朴的做法就是让业务职员和开发职员一起,找一块白板,把各种概念都写在上面,然后整理出范畴名词、范畴动词和范畴规则。这内里的重点是,让业务职员和开发职员在一起。假如只让一方出现,效果又会是原来的样子,由于你没法判断,这内里的语言对方是否听得懂。这种做法很简朴,但通常都不够体系,会存在各种遗漏。2013 年,一位叫 Alberto 的 DDD 专家提出了一种更正式的实践——事故风暴(Event Storming),这种方法简朴易学,充实体现了 DDD 中沟通协作和统一语言等要点,以是逐渐开始盛行起来。
事故风暴紧张分为三步:

  • 第一步是把辨认范畴事故。范畴事故表现的是业务流程中每个步调引发的效果。事故风暴的作者以为,从效果入手来梳理需求,比从利用入手,更容易把业务想清楚。事故风暴中的“事故”两个字就泉源于范畴事故。范畴事故的定名,假如套用英语的语法来说,一样寻常是完成时 + 被动语态。比如说,订单已提交,这个“已”字就是完成时,代表已经发生的事变。而订单已提交也可以说成订单已“被”提交,实际是被动语态,只不外一样寻常把被字给省掉了。除过辨认范畴事故以外,也要将发现的范畴规则写在便利贴上举行备忘,并贴在对应的范畴事故的下方。
  • 第二步是辨认下令。所谓下令就是引发范畴事故的利用,我们可以通太过析范畴事故得到,将下令贴到范畴事故的上方。除了辨认出下令本身以外,我们通常还要辨认出谁实行的下令,以及为了实行下令我们要查询出什么数据,将实行者和查询数据贴到下令的上方。对于实行者,可以是人(实在是人饰演的角色),也可以是其他体系,还可以是定时器。
  • 第三步是辨认聚合。先挪动上一步的便利贴,把围绕同一个范畴名词的下令、事故、实行者、查询数据摆在一起,分成好几“堆”,然后把范畴名词写在大一点的便利贴上,贴在每堆便利贴的中心,这就将围绕同一个范畴名词的全部元素聚集在一起,形成聚合。这里的聚合仅仅是范畴名词,差别于 DDD 中的聚合。范畴名词有大概只是 DDD 聚合充当的角色,大概是 DDD 聚合的属性,尚有些范畴名词须要颠末归并或拆解后,才是合理的 DDD 聚合,而这些须要比及范畴建模时才能真正搞清楚。
事故风暴不光能资助我们挖掘范畴需求,只管把遗漏的需求增补完全,而且还能以协作的方式包管业务职员和技术职员对需求明确同等。肯定要留意,“协作”才是事故风暴的英华,而详细效果怎样出现,反而是第二位的。
事故风暴竣事后,我们要将过程中创建的统一语言以表格的情势记载下来,包罗范畴名词、范畴动词和范畴规则。
范畴名词记载举例:
名词(英文/缩写)名词(中文)表明生命周期关系fund资金账户中以钱币表现的资产开始时创建,销户时注销归属于账户(1:1)范畴动词记载举例:
动词(英文/缩写)动词(中文)表明主语宾语transfer to转账将资金从一个账户转到另一个账户爸爸女儿范畴规则记载举例:
规则编号规则形貌举例影响的紧张功能R001单笔转账限额为 N 万元当 N 为 50万元时:a.假如爸爸给女儿单笔转账 60 万元,则转账失败,错误为高出单笔转账限额;  b.假如爸爸给女儿单笔转账 50 万元,则转账乐成转账有了统一语言后,我们就可以构建范畴模子了。范畴模子是统一语言的软件模子,须要通过范畴建模得到,在 DDD 中对应模子驱动筹划(Model-Driven Design),分为战略筹划和战术筹划两部门。
面纱四:战略筹划

战略筹划,这个名词看起来有点高大上,是模子驱动筹划的高层筹划,而战术筹划则是低层筹划。假如不以战略筹划开始,战术筹划将无法被有效实验。在展开详细实现细节之前,须要优先完成宏观层面的战略筹划,它夸大的是业务战略上的重点,怎样按紧张性分配工作,以及怎样举行最佳整合。
一提起战略筹划,很多人就会想起子域(Subdomain)、限界上下文(Bounded Context,BC)和上下文映射(Context Mapping)等模式,此中子域是为了将差别的业务区分开来,也就是要将辨认出来的业务概念做一个分别,而限界上下文和上下文映射是将分别出来的业务落实到真实的办理方案中。
范畴建模起首是一个定义标题的方法,其次才是办理标题的方法。就是说,一方面,我们要知道办理的标题是什么;另一方面,我们要知道怎么去办理标题。
我们要办理的标题就是范畴标题,在 DDD 中,通过子域模式先把标题从大面上举行分解。软件研发是办理标题,而办理标题要分而治之。所谓分而治之,就是要把标题分解了,对应到 DDD 中,就是要把一个大范畴分解成多少个小范畴,而这个分解出来的小范畴就是子域。
通过事故风暴,我们创建了统一语言,而统一语言对应着模子。在战略筹划中,我们要对这些统一语言做个分类,把它们分别到差别的子域中去。比如我们要做一个代码打靶服务,起首要把打靶和靶场管理这两件事分开,一个是打靶职员的打靶活动,另一个是代码专家的内容管理。同时,用户登岸和分权分域也是要思量的根本标题,那么身份管理也可以作为一个子域。雷同的,尚有数据服务和智能学习等子域。
对于一个真实项目而言,分别出来的子域大概会有很多,但并非每个子域都一样紧张。以是,我们还要把分别出来的子域再做一下区分,分成核心域(Core Domain)、支持域(Supporting Subdomain)和通用域(Generic Subdomain)。
核心域是整个体系最紧张的部门,是整个业务得以乐成的关键。关于核心域,Eric 曾提出过几个标题,帮我们辨认核心域:

  • 为什么这个体系值得写?
  • 为什么不直接买一个?
  • 为什么不外包?
假如你对这几个标题的复兴可以或许帮你找到这个服务或体系非写不可的来由,那它就是你的核心域。对于代码打靶服务来说,打靶子域和靶场管理子域是核心域。
有一些子域不是你的核心竞争力,但却是体系不得不做的东西,市场上也找不到一个现成的方案,这种子域就是支持域。对于代码打靶服务来说,打靶职员的本领画像、弱项分析和发展曲线等是和打靶效果密切相干的,同时要针对性的创建知识库,并举行智能保举,让打靶职员更好更快的提升 Code Review 本领和编码本领,这是对代码打靶服务核心本领扩展的紧张一步,以是智能学习子域就是一个支持域。
尚有一种子域叫通用域,就是行业里通常都是这么做,即便不本身做,也并不影响你的业务运行。对于代码打靶服务来说,数据服务提供度量看板,包罗组织看板和个人看板,行业里有现成的做法,以是数据服务子域就是一个通用域。
我们之以是要区分差别的子域,关键的缘故起因就在于,我们可以决定差别的投资计谋。核心域要积极投入,支持域次之,通用域乃至可以费钱买服务。
通过分别子域,区分核心域、支持域和通用域,我们把 DDD 在标题层面的概念已经说清楚了。接下来,就要进入到办理方案层面了。我们如今有了切分出来的子域,怎样去落实到代码上呢?起首要办理的就是这些子域怎样组织的标题,是写一个步调把全部子域都放在内里呢,照旧每个子域做一个独立的应用,抑或是有一些在一起,有一些分开。这就引出了范畴驱动筹划中的一个紧张的概念,限界上下文。
限界上下文,顾名思义,它形成了一个界限,一个限定了通用语言自由利用的界限,一旦出界,寄义便无法包管。关于限界上下文的分别,须要同时思量业务界限、工作界限和技术界限,笔者之前写了一篇文章《聊聊服务化架构的界限》,感兴趣的读者可以进一步阅读。


有了对限界上下文的明确,我们就可以把整个业务分解到差别的限界上下文中,但是,只管我们拆分了体系,它们终究照旧一个体系,免不了相互之间要有交互。以是,我们就要有一种形貌方式,将差别限界上下文之间交互的方式形貌出来,这就是上下文映射。DDD 给我们提供了一些形貌这种交互的方式,比如:

  • 相助关系(Partnership);
  • 共享内核(Shared Kernel);
  • 客户-供应商(Customer-Supplier);
  • 跟随者(Conformist);
  • 防腐层(Anticorruption Layer);
  • 开放主机服务(Open Host Service);
  • 发布语言(Published Language);
  • 各行其道(Separate Ways);
  • 大泥球(Big Ball of Mud)。
之以是有这么多差别的交互方式,紧张是为了让你在头脑中细致辨认一下,看看限界上下文之间到底在以怎样的方式举行交互。
在定义好差别的限界上下文,将它们之间的交互通过上下文映射出现出来之后,我们就得到了一张上下文映射图(Context Map)。上下文映射图是可以资助我们明确体系的各个部门之间,是怎样举行交互的,帮我们创建一个全局性的认知,而这每每是很多团队短缺的。
面纱五:战术筹划

对于战术筹划,就是要得到一个详细的模子,这个模子是关于统一语言的软件模子,称作范畴模子。颠末战略筹划,我们已经将统一语言拆分到差别的限界上下文中了,那么范畴模子就不是单一的、内聚的和全功能式的模子,而是存在于限界上下文这个显式的界限之内。
范畴模子通过范畴模子图表达,一样寻常用 UML 类图来画:

我们可以通过对象组合来表达更复杂的业务概念,同时通过对象泛化来表达更抽象的业务概念。创建范畴模子,紧张是辨认范畴对象,创建范畴对象之间的关系,以及确定范畴对象的关键属性,须要的时间还要将范畴对象组织成模块。
假如你想把 UML 学的更深入一点,可以读一读《UML 用户指南》和《UML 精粹》。
对于范畴对象,DDD 中紧张包罗实体(Entity)和值对象(Value Object)。实体指的是可以或许通过唯一标识符标识出来的对象,有生命周期管理,而值对象仅仅表现一个值。实体的属性是可以变的,只要标识符稳定,它就照旧谁人实体。但值对象的属性却不能变,一旦变了,它就不再是谁人对象,以是,我们会把值对象设置成一个稳定的对象。
在 DDD 中我们为什么要将范畴对象分为实体和值对象?实在紧张是为了分出值对象,也就是把变的对象和稳定的对象区分开。
我们通常会花很大的精力来区分实体和值对象,那么得到的值对象能带来什么长处呢?这就须要相识值对象有什么优点。关于值对象,优点紧张体如今内存和数据库结构的灵活性上。有了这种灵活性,就可以根据性能和编程方便性等因素,决定值对象的差别实现方式。其次,值对象的稳定性也会带来更高的步调质量。这些优点,都是实体不具备的。
接下来,我们将留意力转移到范畴对象的生命周期管理:

  • 利用工厂(Factory)模式来创建和销毁范畴对象;
  • 利用聚合(Aggregate)模式来封装范畴对象;
  • 利用仓储(Repository)来查找和长期化范畴对象。
工厂和仓储明确起来一点都不难,我们重点看一下聚合。
聚合就是多个实体或值对象的组合,它们共同构成了一个业务界限。聚合里可以包罗很多个对象,每个对象里还可以继续包罗别的的对象,就像一棵大树一层层展开。但重点是,这是一棵树,以是,它只能有一个树根,这个根就是聚合根(Aggregate Root)。聚合根必须是一个实体,是从外部访问这个聚合的出发点。可见,最简朴的聚合仅包罗一个实体。
有了聚合模式后,我们所说的范畴对象大多数情况下特指的是聚合,也偶尔指的是聚合内部的实体或值对象,这个可以通过所在的上下文来判断。
在 DDD 中,关于聚合筹划有四条根本规则:

  • 在聚合界限内掩护业务规则稳定性;
  • 聚合要筹划得小巧;
  • 只能通过标识符引用其他聚合;
  • 利用终极同等性更新其他聚合。
聚合最根本的作用,是为一组具有团体部门关系的范畴对象维护稳定规则。当我们把握了这种建模技术以后,还可以发现其他一些层面的作用:

  • 聚合不光是“被动地”实现稳定规则,它还为我们提供了一个新的视角,可以更过细地和业务职员讨论业务规则。
  • 技术职员已往一样寻常以为事件只是一个技术概念。如今我们可以看到,事件实在是泉源于业务规则的,本质上是个业务标题。也就是说,聚合在业务规则和事件之间创建了起接洽。
  • 我们在模子上可以为每个聚合建一个包,可以以为,聚合是一种特殊的模块。这样,模子的条理就变得更清楚了。同时,我们也可以把聚合看成一个粗粒度的概念单元举行思考,低落了认知负载。
假如限界上下文中聚合比力多,还可以再通过模块(Module)模式对聚合举行分组,进一步低落认知负载。
面纱六:分层架构

分层架构的一个紧张原则是每层只能与位于其下方的层发生耦合。分层架构可以简朴分为两种,即严酷分层架构和疏松分层架构。在严酷分层架构中,某层只能与位于其直接下方的层发生耦合,而在疏松分层架构中,则允许某层与它的恣意下方层发生耦合。
分层架构的长处是显而易见的:

  • 起首,由于层间疏松的耦合关系,使得我们可以专注于本层的筹划,而不必关心其他层的筹划,也不必担心本身的筹划会影响别的层,对进步软件质量大有裨益。
  • 其次,分层架构使得步调结构清楚,升级和维护都变得非常容易,更改某层的详细实当代码,只要本层的接口保持稳固,其他层可以不必修改。纵然本层的接口发生厘革,也只影响相邻的上层,修改工作量小且错误可以控制,不会带来不测的风险。
DDD 中夸大范畴模子对应的代码应该是被严酷隔离出来的,并保持与模子的高度同等性。在限界上下文中,保举利用分层架构大概解耦更纯粹的六边形架构,将范畴模子和别的支持代码(UI,DB,通讯等)举行解耦,可以凸显范畴模子,有效地管理业务复杂度和技术复杂度。
六边形每条差别的边代表了差别范例的端口,端口要么处理处罚输入,要么处理处罚输出。对于每种外界范例,都有一个适配器与之对应,外界通过应用层 API 与内部举行交互。上图中有 3 个客户哀求均抵达雷同的输入端口(适配器 A、B 和 C),另一个客户哀求利用了适配器 D 。假设前 3 个哀求利用了 HTTP 协议(浏览器、REST 和 SOAP 等),而后一个哀求利用了 AMQP 协议(比如 RabbitMQ)。端口并没有明确的定义,它是一个非常灵活的概念。无论采取哪种方式对端口举行分别,当客户哀求到达时,都应该有相应的适配器对输入举行转化,然后端口将调用应用步调的某个利用大概向应用步调发送一个事故,控制权由此交给内部地区。
应用步调通过公共 API 接收客户哀求,利用范畴模子来处理处罚哀求。我们可以将仓储的实现看作是长期化适配器,该适配器用于访问先前存储的聚合实例大概生存新的聚合实例。正如图中的适配器 E、F 和 G 所展示的,我们可以通过差别的方式实现资源库,比如关系型数据库、基于文档的存储、分布式缓存或内存存储等。假如应用步调向外界发送范畴事故消息,我们将利用适配器 H 举行处理处罚。该适配器处理处罚消息输出,而上面提到的处理处罚 AMQP 消息的适配器则是处理处罚消息输入的,因此应该利用差别的端口。
我们在实际的项目开发中,差别层的组件可以同时开发。当一个组件的功能明确后,就可以立刻启动开发。由于该组件的用户有多个,而且这些用户的偏重点差别,以是须要提供多个差别的接口。同时,这些用户的熟悉也是不停深入的,大概会多次重构相干的接口。于是,组件的多个用户经常会找组件的开发者讨论这些标题,无形中低落了组件的开发服从。
我们换一种方式,组件的开发者在明确了组件的功能后就专注于功能的开发,确保功能稳固和高效。组件的用户本身定义组件的接口(端口),然后基于接口写测试,并不停演进接口。在跨层集成测试时,由组件开发者或用户再开发一个适配器就可以了。
在 DDD 分层架构中,比力难区分的是范畴服务和应用服务,两者都是无状态的。
在面向对象的筹划中,有血虚模子和充血模子之分,简朴来说:

  • 对于血虚模子,对象中仅有数据没有活动,方向过程式编程范式;
  • 对于充血模子,对象中既有数据又有活动,方向面向对象编程范式。
假如利用血虚模子,则范畴对象的活动都会放到范畴服务中,这时范畴服务就比力多;假如利用充血模子,则范畴对象的活动都会封装在内部,这时范畴服务就比力少,仅仅包罗不得当放到范畴对象中的业务活动,比如转账业务活动涉及两个范畴对象,一个是源账户,一个是目的账户。
范畴层封装的逻辑通常是细粒度的,并不得当直接作为 API 袒露给外部。别的,尚有一些不属于范畴层的横切关注点,比如像事件控制,应该单独处理处罚。以是,我们每每要在范畴层表面再加一层,DDD 分层架构和六边形架构都将这一层称为应用层。 应用层本身并不包罗范畴逻辑,而是对范畴层中的逻辑举行封装和编排。
应用层作为范畴层的“门面”,把范畴层封装成更粗粒度的服务供外部利用,而且处理处罚事件和日记等横切关注点。应用层的应用服务是必须有的,对应一个详细的用户故事,具有业务代价。但范畴层的范畴服务可以没有,除非有跨范畴对象的业务活动封装。在应用服务中,可以直接调用聚合的接口举行范畴对象的创建、查询和长期化等,无需在中心再封装一层冗余的范畴服务。
面纱七:两关联一循环

DDD 研发过程如下图所示:

简朴分析一下:

  • 业务职员(业务方)梳理需求,并向技术职员(技术方)澄清;
  • 业务职员和技术职员一起通过事故风暴捕获活动需求,消化范畴知识,定义统一语言,同时实验用统一语言来形貌需求;
  • 业务职员和技术职员一起完成战略筹划和战术筹划,完满统一语言,更深刻的明确业务,同时确定分层架构规范;
  • 技术职员的代码实现要受到范畴模子和分层架构规范的束缚,分离业务和技术的关注点,凸显范畴模子,同时基于面向模子的实现模式来正确的表达范畴模子,让模子和代码逐一映射;
  • 范畴的业务需求“驱动”出了代码实现,同期间码实现又“交付”了范畴的业务需求,它们形成了一个正向反馈的循环,可以反复瓜代,迭代改进,使代码的实现复杂度徐徐迫近业务的本质复杂度。
我们可以进一步把 DDD 研发过程精简为两关联一循环:

  • 范畴模子与统一语言关联;
  • 范畴模子与代码实现关联;
  • 范畴模子的演进和精粹循环。
可见,DDD 的核心是范畴模子,修改模子就是修改代码,修改代码就是修改模子。
我们都知道,软件研发的核心难度在于处理处罚埋伏在业务知识中的复杂度,那么模子就是对这种复杂度的简化与精粹。以是从某种意义上说,Eric 提倡的 DDD 是一种模子驱动的筹划方法:通过范畴模子来捕获范畴知识,利用范畴模子构造更易维护的软件。
早先,不要太在意得到模子是否完满,是否在概念上充足抽象,是否利用了筹划模式等。反而,我们更应该关注该怎样围绕模子,创建有效的沟通与反馈机制,形成两关联一循环过程。理想的模子,须要是全部人都能懂的模子,而不是满是完满的模式和抽象的概念。
团队通过迭代改进法,不求一步到位,但求一次比一次好。通过两关联一循环,技术职员与业务职员在不停地交换与反馈中,徐徐完成对模子的演进和精粹。无论出发点多么低,只要可以或许连续改进,总有一天会有好效果的。而可以或许支持连续改进底子的,则是实现方式与模子方式的同等。以是比起模子的优劣(总是会改好的),关联模子与代码实现就变得更为紧张了。
由此我们可以更好地明确,DDD 并不是一种编码技术,或是一种特定的编码风格,而是软件研发的一种方法,贯穿软件生命周期的全过程,须要业务职员和技术职员的高效协同。
经常有 DDD 学员问笔者,技术职员怎样搞 DDD?笔者一样寻常都会告诉他,要搞 DDD,必须有业务职员到场,只有技术职员到场的 DDD 是伪 DDD。业务职员和技术职员围绕范畴模子,创建有效的沟通与反馈机制,形成两关联一循环过程,这才是真正的 DDD,也是 DDD 能真正发挥威力的缘故起因。
小结

本文实验揭开 DDD 的秘密面纱,统共七层:

  • DDD 发展了 OO,抛弃了将分析模子与筹划模子分离的做法,而是探求单个范畴模子来满意两方面的要求;
  • DDD 发展了灵敏,它显式的把范畴和筹划放到了软件研发的核心,业务职员和技术职员被得到同样的器重,他们通过协同来构建并演进范畴模子;
  • 统一语言是业务职员和技术职员利用事故风暴实践共同创建的一套语言,必须在团队范围内告竣同等,将技术职员的思考出发点拉到了业务上,填平了业务职员和技术职员之间那道人为的鸿沟;
  • 战略筹划属于高层筹划,目的是分离子域,拆分限界上下文,并确定上下文映射,须要优先完成;
  • 战术筹划属于低层筹划,目的是得到一个简朴自洽的范畴模子,既易于明确,又可以低资本相应需求的厘革;
  • 分层架构将范畴模子和别的支持代码举行解耦,可以凸显范畴模子,有效地管理业务复杂度和技术复杂度;
  • 两关联一循环是 DDD的内核,也是 DDD 能真正发挥威力的缘故起因。
盼望读者通过本文可以快速俯瞰 DDD 的全貌和内核,从而低落 DDD 的明确资本,进步 DDD 的实践收益。
您需要登录后才可以回帖 登录 | 立即注册

Powered by CangBaoKu v1.0 小黑屋藏宝库It社区( 冀ICP备14008649号 )

GMT+8, 2024-10-19 11:56, Processed in 0.182365 second(s), 35 queries.© 2003-2025 cbk Team.

快速回复 返回顶部 返回列表