当前位置:首页 > 燃气灶 > 文章正文

若何从0到1实践DDD

编辑:[db:作者] 时间:2024-08-25 04:29:42

随着业务的不断发展,我们创造自己的系统开始变得有点臃肿,为了减少繁芜性,我们考试测验借助DDD来改进我们的系统。
本文记录了自己对DDD的理解和实践过程,欢迎大家一起磋商。
见识所限,难免有理解不到位,希望途经的大佬不吝见教。

若何从0到1实践DDD

一、为什么须要DDD当朋友和你聊事情时,你能否一语中的,说清你在开拓中的业务内容及其代价?当产品和你聊需求时,你是否碰着过反复沟通之后才创造讲的不是同个东西的情形?当你在做需求评估时,你是否常常创造一个小的需求改动,总是牵一发动全身?当你在快乐写代码时,你是否常常以为有些类可有可无,有些接口望文不知义?

如果你有以上的一些疑问,那你可以试试领域驱动设计:

DDD(Domain-driven design,领域驱动设计)是一种架构设计方法论,通过边界划分,将繁芜业务领域大略化,帮助我们设计出清晰的领域和运用边界,担保业务模型与代码模型的同等性。

在细看这个定义之前,我们可以思考一下,为什么我们的业务系统会逐步变得繁芜?

常见的情形是,业务在发展过程中为了探寻发力点,须要不断地试错迭代,调度方向,而系统在设计之初,难以预期到后面的变化多端,为了搪塞业务,修修正改,久之,系统也变得繁芜起来。

可以怎么办呢?及时重构呗——不改变软件系统外部行为的条件下,改进它的内部构造。

然而重构是从技能层面上抽炼出来的模型,每每不具有实际的业务含义,其他同学可能难以自然地将业务问题映射到对应的设计模型。
其余,如果不能如实映射业务模型,随着业务方向调度,代码可能又开始腐败……有点像芝诺悖论中,阿基里斯永久追不上小乌龟。

那DDD怎么搞?

DDD是这么想的:”将业务架构映射到系统架构上,在相应业务变革调度业务架构时,也随之变革系统架构”。
可能大家平时有这样的想法,但是比较模糊,未形成体系,而DDD就供应了一套完全的方法论。
从业务角度去核阅我们的系统,从而实现高内聚低耦合的代码。

整体而言,领域驱动设计包括计策建模和战术建模: 计策设计侧重于高层次、宏不雅观上去划分和集成限界高下文,而战术设计则关注更详细利用建模工具来细化高下文。

二、 如何实现DDD之计策建模1. 基本观点

1)领域、子域

在谈论问题之前,我们须要先定义好问题。

领域即问题域,常日是根据一个组织所处的行业进行识别,它基于业务的愿景,定义了系统要办理的现实问题的目标和范围。
领域越大,业务的范围也越大,大的领域可以拆分成小的问题域,称之为子域。
根据子域主要性和功能属性划,可以将其分为三类。

核心域、支撑域和通用域:

核心域:决定产品核心竞争力的子域支撑域:实现核心域目标所需的,但主要程度不如核心域的子域,一样平常具备强烈的个性化需求通用域:具有通用功能,可被多个子域利用的的是通用域。
该子域所办理的问题一样平常是业界常见问题,有成熟的办理方案,可直接购买或大略修正来利用

这个几个观点实在很随意马虎理解,不过在划分的时候,把稳要从业务的视角,而不是技能功能模块来划分。

2)限界高下文

我们措辞博大精湛,同样的话在不同语境下就可演化出不同含义,这在沟通时总是带来不必要的麻烦。
为了准确地沟通,我们须要统一措辞的边界,在相同的措辞边界内沟通,才不随意马虎失足误。

一则阿凡提当理发师惩罚一个狡猾牧师的趣事:理发时,阿凡提刮脸时问牧师:“牧师,是否要眉毛?”牧师答:“这还用问,眉毛岂能不要?”.“好,你要我就给你!
”,说着就把牧师的眉毛刮下来递到他手里,牧师气得说不出话来,谁叫自己说要呢。
阿凡提又问:“牧师,胡子要吗?”.“不要,不要!
”牧师连忙说。
“好,你不要就不要。
” 嗖嗖几刀就把牧师的胡子刮下来。

在一个别系中,一个名词在不同语境可能有不同的含义,我们对它关注的属性和行为也有所不同。
例如,在电商系统中,对付产品Product, 在采购高下文,须要关注产品的进价、最小起订量与供货周期;在市场高下文中,则关心产品的品质、售价,以及用于匆匆销的精美图片和发卖类型;在仓储高下文中,仓库事情职员更关心产品放在仓库的哪个位置,产品的重量与体积,是否易碎品以及订购产品的数量。

限界高下文在《实现领域驱动设计》中,用了很大篇幅去讲,它有几个主要的意义:

限界高下文是领域观点的措辞边界与业务边界:在这个边界内,领域观点的内涵是清晰、无歧义的限界高下文是团队的事情边界:组织边界与限界高下文对齐限界高下文是技能方案的履行边界:在这个边界内,技能方案是独立自治的,业务逻辑不会落入不同技能边界的间隙

经由计策建模之后,我们可以得到以下的一个模型:

2. 业务实践

为了更好地理解,我们对手上的一个项目:“IoT设备增值产品管理系统”进行实践。
该项目中,我们供应给商户在IoT设备上管理增值运营产品的能力。
这里的IoT设备紧张是微信支付刷脸设备等。
商户可以在系统中创建我们业务中的增值运营产品,如电子海报、互动海报等,创建完之后,干系的增值产品会被投放到IoT设备上,进行展示、运作:

一开始我们从业务的用例出发,认为我们的系统紧张是商户在我们页面网站利用,以及IoT设备通过接口连接我们后台做事,认为这两个分属不同的子域,然后梳理了一些支撑的功能:

画完草图之后,觉得不是很确定,于是便去咨询部门的DDD专家王老师(十分感谢王立老师的辅导),得到了一些宝贵的建议:我们该当避免直接从表现层去看业务,表现层就像是冰山露在水面上的棱角,这些棱角看起来绝不相关,但是实际上底层是连成一块的,这些才是我们须要关注的。

就像这个项目,表面上商户和设备是分开的,实际上它们在操作都是我们的增值运营产品,该当算作我们的系统供应统一对外的做事,然后商户和设备来利用我们的做事。
UGC内容存储业务用例实在没有涉及到的,属于实现时候的东西。
一番建议让我们理清了思路,于是重新梳理,得到以下的计策建模图:

整体而言,我们将整体系统梳理为8个子域:

增值运营做事子域:核心域,是我们业务紧张竞争力。
从业务上来讲,我们的核心是通过供应业务中IoT设备上的增值运营做事增值运营产品子域:支撑域,这里紧张是我们供应增值运营产品,如电子海报、互动海报等生效场景子域:支撑域,业务中增值运营产品有不同生效场景,这里统一进行管理准入子域:支撑域,现紧张是业务中对利用者的一些限定规则权限管理子域:支撑域,基于角色来管理利用者的权限商户信息子域:支撑域,供应商户的信息IoT设备信息子域:支撑域,供应IoT设备的信息风险识别子域:通用域,识别业务中一些安全风险,如不合规的UGC素材等。
这部分是业界常见问题,可以利用通用方案来办理,实际上我们也是接入TEG的能力来实现

个中我们系统中的商户信息依赖了微信支付商户账号信息和IoT设备铺设做事信息,这里利用防腐层进行隔离,将外部的商户信息“翻译”为我们业务中的商户信息。
三、如何实现DDD之战术建模梳理清楚高下文之间的关系后,我们基本理解业务的概貌,接下来须要细化高下文,进一步完善我们的模型。
这里也须要用到DDD的一些基本观点。

3. 基本观点

1)实体、值工具

实体和值工具是组成领域模型的根本单元。
当一个工具由其标识(而不是属性)区分时,这种工具称为实体。
如在校园教务系统中,每个账户是对应着一个学生,根据学号来唯一标识,可以认为是一个实体。
传统的数据建模大多是根据数据库范式设计的,每一个数据库表对应一个实体,每一个实体的属性值用单独的一列来存储,一个实体主表会对应 N 个实体从表。

与其不同,DDD 是先构建领域模型,再将业务工具映射为持久化工具。
这可能导致DDD建立出来的实体,映射到详细数据库表时,可能是1对多,多对1的关系。

如一个账户实体,有它的基本信息和权限角色信息,可能就对应了2个持久化工具。
另一方面,有时候为了某些查询场景的方便,会把西席账户、学生账户等对应成一个持久化工具,就成了多对1。

通过工具属性值来识别的工具,则可以认为是一个值工具。
如地址信息{“省”: “广东省”,”市”:”深圳市”},我们是通过它的属性来区分出不同的地址。
值工具实际上是想把一些不变的属性组合起来,减少系统的繁芜性。
在设计值工具的时候,须要知足以下的特性:

值工具相等性:可以通过对其属性的比较,来区分不同的值工具不变性:须要担保值工具创建后就不能被修正,即不许可外部再修正其属性可更换性:值工具是一个整体,当其描述的工具有变革时,须要用一个新的值工具来更换对付值工具,由于其具有不变性,且是通过属性来判断相等的,在设计对应的数据库持久化工具时,可以将其以JSON形式存储在数据库表的某一字段中

2)聚合、聚合根

在 DDD 中,实体和值工具是根本的领域工具。
实体一样平常对应业务工具,它具有业务属性和业务行为;而值工具紧张是属性凑集,对实体的状态和特色进行描述。
但是我们的一个业务流程中,一样平常会同时涉及多个实体、值工具的操作,这里业务逻辑紧密的实体和值工具便组合成一个聚合。

从数据层面来看,同个聚合内的数据须要保持强同等性。

每一个聚合有一个聚合根实体,设置聚合根的紧张目的是为了避免由于繁芜数据模型短缺统一的业务规则掌握,而导致聚合、实体之间数据不一致性的问题。
聚合根可以算作是聚合的管理者,或是说handle。
对内其折衷实体和值工具完成业务逻辑。
对外则供应通过聚合ID供其他聚合关联引用,屏蔽外部对内部实体的直接访问和修正。

建议的聚合设计原则:

在同等性边界之内确保不变性:聚合用来封装真正的不变性,而不是大略地将工具组合在一起。
聚合内有一套不变的业务规则,各实体和值工具按照统一的业务规则运行,实现工具数据的同等性。
设计小聚合:如果聚合聚合包含过多的实体,会提高管理实体的繁芜性,高频操作下随意马虎并发冲突,降落了系统的性能。
在边界之外利用终极同等性:不同的聚合之间不哀求强同等性,担保终极同等性。
一次事务操作中,只修正一个聚合实例,如果须要修正多个实例,可以考虑通过异步的办法担保终极同等性。

3)领域做事

领域做事的定义:领域中的做事表示一个无状态的操作,它用于实现特定于某个领域的任务。
当某个操作不适宜放在聚合(实体)或值对像上时,最好的办法便是利用领域做事。

举个例子,在一个路线导航的项目中,“路线”可能是个中的一个实体,如果业务中有“推举路线上干系的美食”这样一个功能,那我们会想,这个功能该当归给哪个领域工具,给“路线”实体吗?有点不得当,该当路线本身关注的是起终点,韶光人物等。

此时可以将其这个功能归为领域做事,它是一个路线状态无关的做事,输入路线各个节点,来得到沿路的各种美食。
当然,要把稳不要过度地利用领域做事,由于这很可能导致你把实体的行为都放在里面了,实体本身都变成了一些只有getter和setter的“血虚模型”。

4)领域事宜

领域事宜是领域模型中非常主要的一部分,用来表示领域中发生的事宜。
一个领域事宜将导致进一步的业务操作,在实现业务解耦的同时,还有助于形成完全的业务闭环。

领域事宜含义很广泛,可以是业务流程的一个步骤,也可以是一个事宜发生后触发的后续动作,缴费完成之后,触发短信关照;上面在设计聚合的时候,我们提到一个原则:在边界之外利用终极同等性,一次事务最多只能变动一个聚合的状态。
如果一次业务操作涉及多个聚合状态的变动,应通过领域事宜,达到终极同等性。

实际上是通过事宜驱动的这种异步办法,对系统进行解耦。
当然,如果你以为某两个步骤,业务流程上不许可是不一致的,那就得重新考虑将其归在同个聚合中了。

4. 业务实践

我们以增值运营做事高下文为例,根据上面的理解,结合业务实际,得到以下模型:

个中增值产品是个中的一个聚合根,通过该聚合根进行各种领域操作。
海报缩略图是个中的一个领域做事,通过输入产品素材中的海报url,来得到一个海报的缩略图。

四、工程实践传统的三层架构和DDD的分层构造:

在《领域驱动设计——软件核心繁芜性的应对之道》一书中,Eric提出了这样的一种分层构造,将全体系统划分为四层:用户接口层、运用层、领域层和根本举动步伐层。

用户接口层:用户接口层卖力向用户显示信息和解释用户指令。

运用层:运用层相对来说是较“薄”的一层,紧张是支配了运用做事。
运用做事的实现中,它卖力编排和转发下一层的领域层的接口,将要实现的功能委托给一个或多个领域工具来实现,本身只卖力处理业务用例的实行顺序以及结果的拼装。

领域层:领域层是比较“厚”的一层,它包含聚合根、实体、值工具、领域做事等领域模型中的领域工具,实现了核心的业务逻辑。
领域层和运用层的职责看起来有点模糊。

个人以为,可以理解是运用层描述了一个详细操作从开始到结束的每一个环节,而领域层则是对其的细化,用来处理详细的某一个环节。

比如,比如线上购物中,购物车结算这一场景可算作是一个运用行为。
而这个行为又紧张包括金额打算、支付、天生订单,这些子环节就可以理解为一个领域层的做事了。

根本举动步伐层:可以看到上面三层都有箭头指向根本举动步伐层,它的浸染便是为其它各层供应通用的技能和根本做事,如数据持久化、中间件等DDD 分层架构中的要素与传统三层架构(用户界面层、业务逻辑层、数据访问层)还是挺相似的,一个紧张的变革是将业务逻辑层的做事拆分到了运用层和领域层。
运用层相应业务用例的变革,领域层关注不变的领域模型。

图片来自极客韶光

《DDD实战课》在实际的代码工程便是按照这样的目录来划分,最近部门在推的整洁Git,也是这样划分目录:

接下来,便是将领域工具映射到实际的类,实现对应的属性和行为。
当然,详细实现中有很多范式可参考和谈论,我们也在摸索中,待后续逐步补充……

五、总结

DDD首先不是关于技能的,而是关于谈论、聆听、理解、创造业务代价的。
——Vaughn Vernon《实现领域驱动设计》

如Vernon所说的,DDD首先是关注业务的代价的。
一开始我们对业务的边界、目标可能有个大概理解,但是见地还是不尽相同。

通过一起对业务的谈论与思考,我们理解了业务的概貌及核心,明确代价所在。
关注到了核心,自然可以帮助我们实现与业务契合的系统。
通过这次学习与实践,我们进一步打仗了DDD。

当然,这也还只是开始,更多的关联知识还隐蔽在冰山之下。
同时我们也明白,DDD也只是一种方法论上的参考,不是“银弹”,须要不断地去实践与思考,才能体会出它的代价。

参考:

Eric Evans.领域驱动设计.赵俐 盛海艳 刘霞等译.公民邮电出版社,2016.美团技能团队.领域驱动设计在互联网业务开拓中的实践:https://tech.meituan.com/2017/12/22/ddd-in-practice.html?spm=a2c4e.10696291.0.0.428119a4uu9Gpl极客韶光.DDD实战课:https://time.geekbang.org/column/article/152677

作者:bryanzhao,微信支付后台开拓工程师

本文由 @腾讯大讲堂 原创发布于大家都是产品经理,未经容许,禁止转载。

题图来自 Pixabay,基于CC0协议。

本站所发布的文字与图片素材为非商业目的改编或整理,版权归原作者所有,如侵权或涉及违法,请联系我们删除,如需转载请保留原文地址:http://www.baanla.com/rqz/120860.html

XML地图 | 自定链接

Copyright 2005-20203 www.baidu.com 版权所有 | 琼ICP备2023011765号-4 | 统计代码

声明:本站所有内容均只可用于学习参考,信息与图片素材来源于互联网,如内容侵权与违规,请与本站联系,将在三个工作日内处理,联系邮箱:123456789@qq.com