首页 > 其他分享 >浅析DDD

浅析DDD

时间:2022-11-08 18:36:04浏览次数:32  
标签:梳理 业务 模型 子域 领域 我们 浅析 DDD

浅析DDD_领域知识

什么是DDD

软件开发不是一蹴而就的事情,我们不可能在不了解产品(或行业领域)的前提下进行软件开发,在开发前,通常需要进行大量的业务知识梳理,而后到达软件设计的层面,最后才是开发。而在业务知识梳理的过程中,我们必然会形成某个领域知识,根据领域知识来一步步驱动软件设计,就是领域驱动设计的基本概念。

听起来这和传统意义的软件开发没啥区别,只是换了点新鲜的名词而已,其实不然。


软件开发 VS DDD

一般软件设计或者说软件开发分两种:​​瀑布式​​​,​​敏捷式​​。

前者一般是项目经理经过大量的业务分析后,会基于现有需求整理出一个基本模型,再将结果传递给开发人员,这就是开发人员的需求文档,他们只需要照此开发便是。这种模式下,是很难频繁的从用户那里得到反馈,因此在前期分析时就已经默认了这个业务模型是正确的,那么结果可想而之,数月甚至数年后交付的时候,必然和客户的预期差距较大。

后者在此基础上进行了改进,它也需要大量的分析,范围会设计到更精细的业务模块,它是小步迭代,周期性交付,那么获取客户的反馈也就比较频繁和及时。可敏捷也不能够将业务中的方方面面都考虑到,并且敏捷是拥抱变化的,大量的需求或者业务模型变更必将带来不小的维护成本,同时,对人(Developer)的要求也必然会更高。

DDD则不同:它像是更小粒度的迭代设计,它的最小单元是​​领域模型(Domain Model)​​​,所谓领域模型就是能够精确反映领域中某一知识元素的载体,这种知识的获取需要通过与​​领域专家(Domain Expert)​​​进行频繁的沟通才能将专业知识转化为领域模型。领域模型无关技术,具有高度的业务抽象性,它能够精确的描述领域中的知识体系;同时它也是独立的,我们还需要学会如何让它具有表达性,让模型彼此之间建立关系,形成完整的领域架构。通常我们可以用象形图或一种​​通用的语言(Ubiquitous Language)​​​去描述它们之间的关系。在此之上,我们就可以进行​​领域中的代码设计(Domain Code Design)​​。如果将软件设计比做是造一座房子,那么领域代码设计就好比是贴壁纸。前者已经将房子的蓝图框架规划好,而后者只是一个小部分的设计:如果墙纸贴错了,我们可以重来,可如果房子结构设计错了,那可就悲剧了。


建立领域知识(Build Domain Model)

说了这么多领域模型的概念,到底什么是领域模型呢?以飞机航行为例子:

现要为航空公司开发一款能够为飞机提供导航,保证无路线冲突监控软件。那我们应该从哪里开始下手呢?根据DDD的思路,我们第一步是​​建立领域知识​​:作为平时管理和维护机场飞行秩序的工作人员来说,他们自然就是这个领域的专家,我们第一个目标就是与他们沟通,也许我们并不能从中获取所有想要的知识,但至少可以筛选出主要的内容和元素。你可能会听到诸如起飞,着陆,飞行冲突,延误等领域名词,让们从一个简单的例子开始(就算是错误的也没关系):

  • 起点->飞机->终点

这个模型很直接,但有点过于简单,因为我们无法看出飞机在空中做了什么,也无法得知飞机怎么从起点到的终点,刚才我们似乎提到无路线冲突,那么如此似乎会好些:

  • 飞机->路线->起点/终点

既然点构成线,那何不:

  • 飞机->路线->points(含起点,终点)

这个过程,是我们不断建立领域知识的过程,其中的重点就是寻找领域专家频繁沟通,从中提炼必要领域元素。

尽管看起来还是很简单,但我们已经开始一步步的在建立领域对象和领域模型了。

通用语言(Ubiquitous Language)

上面的例子的确看起来简单,但过程并非容易:我们(开发人员)和领域专家在沟通的过程中是存在天然屏障的:我们满脑子都是类,方法,设计模式,算法,继承,封装,多态,如何面向对象等等;这些领域专家是不懂的,他们只知道飞机故障,经纬度,航班路线等专业术语。

所以,在建立领域知识的时候,我们(开发人员和领域专家)必须要交换知识,知识的范围范围涉及领域模型的各个元素,如果一方对模型的描述令对方感到困惑,那么应该立刻换一种描述方式,直到双方都能够接受并且理解为止。在这一过程中,就需要建立一种通用语言,作为开发人员和领域专家的沟通桥梁。

可如何形成这种通用语言呢?其实答案并不唯一,确切的说也没有什么标准答案。

a)UML
利用UML可以清晰的表现类,并且展示它们之间的关系。但是一旦聚合关系复杂,UML叶子节点将会变的十分庞大,可能就没有那么直观易懂了。最重要的是,它无法精确的描述类的行为。为了弥补这种缺陷,可以为具体的行为部分补充必要说明(可以是标签或者文档),但这往往又很耗时,而且更新维护起来十分不便。
b)伪代码
极限编程是推荐这么做的,这个办法对程序猿来说固然好,可立刻就要将现有模型映射到代码层面,这对人的要求也是不低,并不容易实现。

模型驱动设计(Domain Driven Design)

模型关系图(Model-Driven Design)

领域驱动设计中的模型关系图如下:

浅析DDD_值对象_02

层结构(Layered Architecture)

浅析DDD_值对象_03

  • User Interface

负责向用户展现信息,并且会解析用户行为,即常说的展现层。

  • Application Layer

应用层没有任何的业务逻辑代码,它很简单,它主要为程序提供任务处理。

  • Domain Layer

这一层包含有关领域的信息,是业务的核心,领域模型的状态都直接或间接(持久化至数据库)存储在这一层。

  • Infrastructure Layer

为其他层提供底层依赖操作。

层结构的划分是很有必要的,只有清晰的结构,那么最终的领域设计才宜用,比如用户要预定航班,向Application Layer的service发起请求,而后Domain Layler从Infrastructure Layer获取领域对象,校验通过后会更新用户状态,最后再次通过Infratructure Layer持久化到数据库中。


实体(Entity) & 值对象(Value Object)

​实体​​与面向对象中的概念类似,在这里再次提出是因为它是领域模型的基本元素。在领域模型中,实体应该具有唯一的标识符,从设计的一开始就应该考虑实体,决定是否建立一个实体也是十分重要的。

​值对象​​和我们说的编程中数值类型的变量是不同的,它仅仅是没有唯一标识符的实体,比如有两个收获地址的信息完全一样,那它就是值对象,并不是实体。值对象在领域模型中是可以被共享的,他们应该是“不可变的”(只读的),当有其他地方需要用到值对象时,可以将它的副本作为参数传递。

服务(Services)

当我们在分析某一领域时,一直在尝试如何将信息转化为领域模型,但并非所有的点我们都能用​​Model​​​来涵盖。对象应当有属性,状态和行为,但有时领域中有一些行为是无法映射到具体的对象中的,我们也不能强行将其放入在某一个模型对象中,而将其单独作为一个方法又没有地方,此时就需要​​服务​​.

服务是无状态的,对象是有状态的。所谓状态,就是对象的基本属性:高矮胖瘦,年轻漂亮。服务本身也是对象,但它却没有属性(只有行为),因此说是无状态的。

PS:这与我们常说的服务器的状态是两个概念,无状态的服务器是指,对服务器来说每次接收到的HTTP请求都像是客户端第一次发送的一样;而有状态的服务器就会存储客户端的状态,常见的就是Cookie&Session

服务存在的目的就是为领域提供简单的方法。为了提供大量便捷的方法,自然要关联许多领域模型,所以说,行为(Action)天生就应该存在于服务中。

服务具有以下特点:

a)服务中体现的行为一定是不属于任何实体和值对象的,但它属于领域模型的范围内
b)服务的行为一定设计其他多个对象
c)服务的操作是无状态的

PS:不要随意放置服务,如果该行为是属于应用层的,那就应该放在那;如果它为领域模型服务,那它就应该存储在领域层中,要避免业务的服务直接操作数据库,最好通过DAO。


概念总结

  1. 领域就是问题域,有边界,领域中有很多问题;
  2. 任何一个系统要解决的那个大问题都对应一个领域;
  3. 通过建立领域模型来解决领域中的核心问题,模型驱动的思想;
  4. 领域建模的目标针对我们在领域中所关心的问题,即只针对核心关注点,而不是整个领域中的所有问题;
  5. 领域模型在设计时应考虑一定的抽象性、通用性,以及复用价值;
  6. 通过领域模型驱动代码的实现,确保代码让领域模型落地,代码最终能解决问题;
  7. 领域模型是系统的核心,是领域内的业务的直接沉淀,具有非常大的业务价值;
  8. 技术架构设计或数据存储等是在领域模型的外围,帮助领域模型进行落地;


拆分领域

上面我们明白了,领域建模的基础是要先理解领域,让自己成为领域专家。如果做到了这点,我们就打好了坚实的基础了。但是,有时一个领域往往太复杂,涉及到的领域概念、业务规则、交互流程太多,导致我们没办法直接针对这个大的领域进行领域建模。所以,我们需要将领域进行拆分,本质上就是把大问题拆分为小问题,然后各个击破的思路。然后既然把一个大的领域划分为了多个小的领域(子域),那最关键的就是要理清每个子域的边界;然后要搞清楚哪些子域是核心子域,哪些是非核心子域,哪些是公共支撑子域;然后,还要思考子域之间的联系是什么。那么,我们该如何划分子域呢?我的个人看法是从业务相关性的角度去思考,也就是我们平时说的按业务功能为出发点进行划分。还是拿经典的电商系统来分析,通常一个电商系统都会包含好几个大块,比如:

  • 会员中心:负责用户账号登录、用户信息的管理;
  • 商品中心:负责商品的展示、导航、维护;
  • 订单中心:负责订单的生成和生命周期管理;
  • 交易中心:负责交易相关的业务;
  • 库存中心:负责维护商品的库存;
  • 促销中心:负责各种促销活动的支持;

上面这些中心看起来很自然,因为大家对电子商务的这个领域都已经非常熟悉了,所以都没什么疑问,好像很自然的样子。所以,领域划分是不是就是没什么挑战了呢?显然不是。之所以我们觉得子域划分很简单,是因为我们对整个大领域非常了解了。如果我们遇到一个冷门的领域,就没办法这么容易的去划分子域了。这就需要我们先去努力理解领域内的知识。所以,我个人从来不相信什么子域划分的技巧什么的东西,因为我觉得这个工作没有任何诀窍可以使用。当我们不了解一个东西的时候,如何去拆解它?当我们对整个领域有一定的熟悉了,了解了领域内的相关业务的本质和关系,我们就自然而然的能划分出合理的子域了。不过并不是所有的系统都需要划分子域的,有些系统只是解决一个小问题,这个问题不复杂,可能只有一两个核心概念。所以,这种系统完全不需要再划分子域。但不是绝对的,当一个领域,我们的关注点越来越多,每个关注点我们关注的信息越来越多的时候,我们会不由自主的去进一步的划分子域。比如,也许我们一开始将商品和商品的库存都放在商品中心里,但是后来由于库存的维护越来越复杂,导致揉在一起对我们的系统维护带来一定的困难时,我们就会考虑将两者进行拆分,这个就是所谓的业务垂直分割。

细分子域

通过上面的两步,我们了解了领域里的知识,也对领域进行了子域划分。但这样还不够,凭这些我们还无法进行后续的领域模型设计。我们还必须再进一步细化每个子域,进一步明确每个子域的核心关注点,即需求细化。我觉得我们需要细化的方面有以下几点:

  1. 梳理领域概念:梳理出领域内我们关注的概念、概念的关系,并统一交流词汇,形成统一语言;
  2. 梳理业务规则:梳理出领域内我们关注的各种业务规则,DDD中叫不变性(invariants),比如唯一性规则,余额不能小于零等;
  3. 梳理业务场景:梳理出领域内的核心业务场景,比如电商平台中的加入购物车、提交订单、发起付款等核心业务场景;
  4. 梳理业务流程:梳理出领域内的关键业务流程,比如订单处理流程,退款流程等;

从上面这4个方面,我们从领域概念、业务规则、交互场景、业务流程等维度梳理了我们到底要什么,整理了整个系统应该具备的功能。这个工作我觉得是一个非常具有创造性和有难度的工作。我们一方面会主观的定义我们想要什么;另一方面,我们还会思考我们要的东西的合理性。我认为这个就是产品经理的工作,产品经理必须要负起职责,把他的产品充分设计好,从各个方面去考虑,如何设计一个产品,才能更好的解决用户的核心诉求,即领域内的核心问题。如果对领域不够了解,如果想不清楚用户到底要什么,如果思考问题不够全面,谈何设计出一个合理的产品呢?

关于领域概念的梳理,我觉得可以采用四色原型分析法,这个分析法通过系统的方法,将概念划分为不同的种类,为不同种类的概念标注不同的颜色。然后将这些概念有机的组合起来,从而让我们可以清晰的分析出概念和概念之间的关系。

注意:上面我说的这四点,重点是梳理出我们要什么功能,而不是思考如何实现这些功能,如何实现是软件设计人员的职责。


关注公众号 soft张三丰 

浅析DDD_领域知识_04

标签:梳理,业务,模型,子域,领域,我们,浅析,DDD
From: https://blog.51cto.com/u_15501087/5834167

相关文章

  • 通用文档信息提取模型浅析
    文章目录​​1.前言与痛点​​​​2.通用信息提取模型技术分析​​​​1.技术介绍​​​​2.原理分析​​​​1.LayoutDetection(视觉检测模块):​​​​2.OCR(文字识别......
  • OpenStack Neutron浅析
    1.基础知识1.1防火墙(firewall)防火墙是依照特定的规则来控制进出它的网络流量的网络安全系统。一个典型的场景是在一个受信任的内网和不受信任的外网比如Internet之间......
  • Python yield 使用浅析
    之前了解了生成器的概念,带有yield的函数在Python中被称之为generator(生成器),那么应该什么时候使用呢?举个例子:简单输出斐波那契數列前N个数deffab(max):n,a,b=......
  • 浅析云边端协同与算力调度在AI视频检测场景中的应用意义
    人工智能在医疗卫生、能源动力、交通航天、语言图像识别等领域发挥着重要作用,在安防等领域也同样值得期待。人工智能、深度学习、视频结构化技术、物联网技术,大数据分析等变......
  • 浅析基于云-边-端协同架构的AI算力资源智能调度能力
    随着AI、云计算、边缘计算、大数据、物联网等技术的不断发展、数据的不断增加,基于云、边、端协同架构的部署需求也越来越多。TSINGSEE青犀视频的智能分析网关/云平台,不仅融......
  • 浅析无线测温技术在企业电力系统中的设计及应用
    陈盼安科瑞电气股份有限公司上海嘉定201801摘要: 电力系统是水泥企业生产和设备运转的重要组成部分,电力系统安全运行直接影响企业安全生产和效益。如何利用信息化技术......
  • 局域网与广域网浅析
    局域网有三种常见的拓扑结构,分别是:以太网:逻辑拓扑是总线型,物理拓扑是星型或拓展星型结构令牌环:逻辑拓扑是环形结构,物理拓扑是星型结构FDDI(光纤分布数字接口):逻辑拓扑是环形,物......
  • 数据库视图浅析
    关系型数据库中存在三种关系:基本关系(又叫“基本表”,或“基表”),查询表,视图表。在这儿我们就讲讲视图。视图是一张虚表,它并没有真正地保存数据,而是通过一些操作将多个表的数据......
  • 一文读懂NodeJs知识体系和原理浅析
    node.js初探Node.js是一个JS的服务端运行环境,简单的来说,它是在JS语言规范的基础上,封装了一些服务端的运行时对象,让我们能够简单实现非常多的业务功能。如果我们只......
  • #打卡不停更#【FFH】浅析Ability框架中Stage模型与FA模型的差异
    (#打卡不停更#【FFH】浅析Ability框架中Stage模型与FA模型的差异)Aility框架概述Ability是应用所具备能力的抽象,也是应用程序的基本组成单元。OpenHarmony与HarmonyOS的应......