浅谈我对DDD领域驱动设计的理解

从遇到问题开始

当人们要作一个软件系统时,通常老是由于遇到了什么问题,而后但愿经过一个软件系统来解决。html

好比,我是一家企业,而后我以为我如今线下销售本身的产品还不够,我但愿可以在线上也能销售本身的产品。因此,天然而然就想到要作一个普通电商系统,用于实如今线销售本身企业产品的目的。数据库

再好比,我是一家互联网公司,公司有不少系统对外提供服务,面向不少客户端设备。可是最近因为各类缘由,致使服务常常出故障。因此,咱们但愿经过各类措施提升服务的质量和稳定性。其中的一个措施就是但愿能作一个灰度发布的平台,这个平台能够提供灰度发布的服务。而后,当某个业务系统作了一些修改并须要发布时,可使用咱们的灰度发布平台来很是方便的实现灰度发布的功能。好比在灰度发布平台上方便的定制容许哪些特定的客户端才会访问新服务,哪些客户端继续使用老服务。灰度发布平台能够提供各类灰度的策略。有了这样的灰度发布机制,那即使系统的新逻辑有什么问题,受影响的面也不会很大,在可控范围内。因此,若是公司里的全部对外提供服务的系统都接入了灰度平台,那这些系统的发布环节就能够更加有保障了。缓存

总之,咱们作任何一个软件系统,都是有缘由的,不然就不必作这个系统,而这个缘由就是咱们遇到的问题。因此,经过问题,咱们就知道了咱们须要一个什么样的系统,这个系统解决什么样的问题。最后,咱们就很天然的得出了一个目标,即知道了本身要什么。好比我要作一个论坛、一个博客系统、一个电商平台、一个灰度发布系统、一个IDE、一个分布式消息队列、一个通讯框架,等等。数据结构

DDD切入点1 - 理解概念

DDD的全称为Domain-driven Design,即领域驱动设计。下面我从领域、问题域、领域模型、设计、驱动这几个词语的含义和联系的角度去阐述DDD是如何融入到咱们平时的软件开发初期阶段的。要理解什么是领域驱动设计,首先要理解什么是领域,什么是设计,还有驱动是什么意思,什么驱动什么。架构

什么是领域(Domain)?

前面咱们已经清楚的知道咱们如今要作一个什么样的系统,这个系统须要解决什么问题。我认为任何一个系统都会属于某个特定的领域,好比论坛是一个领域,只要你想作一个论坛,那这个论坛的核心业务是肯定的,好比都有用户发帖、回帖等核心基本功能。好比电商平台、普通电商系统,这种都属于网上电商领域,只要是这个领域的系统,那都有商品浏览、购物车、下单、减库存、付款交易等核心环节。因此,同一个领域的系统都具备相同的核心业务,由于他们要解决的问题的本质是相似的。并发

所以,咱们能够推断出,一个领域本质上能够理解为就是一个问题域,只要是同一个领域,那问题域就相同。因此,只要咱们肯定了系统所属的领域,那这个系统的核心业务,即要解决的关键问题、问题的范围边界就基本肯定了。一般咱们说,要成为一个领域的专家,必需要在这个领域深刻研究不少年才行。由于只有你研究了不少年,你才会遇到很是多的该领域的问题,同时你解决这个领域中的问题的经验也很是丰富。不少时候,领域专家比技术专家更加吃香,好比金融领域的专家。框架

什么是设计(Design)?

DDD中的设计主要指领域模型的设计。为何是领域模型的设计而不是架构设计或其余的什么设计呢?由于DDD是一种基于模型驱动开发的软件开发思想,强调领域模型是整个系统的核心,领域模型也是整个系统的核心价值所在。每个领域,都有一个对应的领域模型,领域模型可以很好的帮咱们解决复杂的业务问题。dom

从领域和代码实现的角度来理解,领域模型绑定了领域和代码实现,确保了最终的代码实现就必定是解决了领域中的核心问题的。由于:1)领域驱动领域模型设计;2)领域模型驱动代码实现。咱们只要保证领域模型的设计是正确的,就能肯定领域模型能够解决领域中的核心问题;同理,咱们只要保证代码实现是严格按照领域模型的意图来落地的,那就能保证最后出来的代码可以解决领域的核心问题的。这个思路,和传统的分析、设计、编码这几个阶段被割裂(而且每一个阶段的产物也不一样)的软件开发方法学造成鲜明的对比。数据库设计

什么是驱动(Driven)?

上面其实已经提到了,就是:1)领域驱动领域模型设计;2)领域模型驱动代码实现。这个就和咱们传统的数据库驱动开发的思路造成对比了。DDD中,咱们老是以领域为边界,分析领域中的核心问题(核心关注点),而后设计对应的领域模型,再经过领域模型驱动代码实现。而像数据库设计、持久化技术等这些都不是DDD的核心,而是外围的东西。分布式

领域驱动设计(DDD)告诉咱们的最大价值我以为是:当咱们要开发一个系统时,应该尽可能先把领域模型想清楚,而后再开始动手编码,这样的系统后期才会很好维护。可是,不少项目(尤为是互联网项目,为了赶工)都是一开始模型没想清楚,一上来就开始建表写代码,代码写的很是冗余,彻底是过程是的思考方式,最后致使系统很是难以维护。并且更糟糕的是,出来混老是要还的,前期的领域模型设计的很差,不够抽象,若是你的系统会长期须要维护和适应业务变化,那后面你必定会遇到各类问题维护上的困难,好比数据结构设计不合理,代码处处冗余,改BUG处处引入新的BUG,新人对这种代码上手困难,等。而那时若是你再想重构模型,那要付出的代价会比一开始从新开发还要大,由于你还要考虑兼容历史的数据,数据迁移,如何平滑发布等各类头疼的问题。因此,就致使咱们最后每天加班。

虽然,咱们都知道这个道理,可是我也明白,人的习惯很难改变的,大部分人都很难从面向过程式的想到哪里写到哪里的思想转变为基于系统化的模型驱动的思惟。我想,这或许是DDD很难在中国或国外流行起来的缘由吧。可是,我想这不该该成为咱们放弃学习DDD的缘由,对吧!

概念总结:

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

DDD切入点2 - 理解领域、拆分领域、细化领域

理解领域知识是基础

上面咱们经过第一步,虽然咱们明确了要作一个什么样的系统,该系统主要解决什么问题,可是就这样咱们还没法开始进行实际的需求分析和模型设计,咱们还必须将咱们的问题进行拆分,需求进行细化。有些时候,需求方,即提出问题的人,极可能本身不清楚具体想要什么。他只知道一个概念,一个大的目标。好比他只知道要作一个股票交易系统,一个灰度发布系统,一个电商平台,一个开发工具,等。可是他不清楚这些系统应该具体作成什么样子。这个时候,我认为领域专家就很是重要了,DDD也很是强调领域专家的重要性。由于领域专家对这个领域很是了解,对领域内的各类业务场景和各类业务规则也很是清楚,总之,对这个领域内的一切业务相关的知识都很是了解。因此,他们天然就有能力表达出系统该作成什么样子。因此,要知道一个系统到底该作成什么样子,到底哪些是核心业务关注点,只能靠沉淀领域内的各类知识,别无他法。所以,假设你如今打算作一个电商平台,可是你对这个领域没什么了解,那你必定得先去了解下该领域内主流的电商平台,好比淘宝、天猫、京东、亚马逊等。这个了解的过程就是你沉淀领域知识的过程。若是你不了解,就算你领域建模的能力再强,各类技术架构能力再强也是使不上力。领域专家不是某个固定的角色,而是某一类人,这类人对这个领域很是了解。好比,一个开发人员也能够是一个领域专家。假设你在一个公司开发和维护一个系统已经好几年了,可是这个系统的产品经理(PD)可能已经换过好几任了,这种状况下,我相信这几任产品经理都没有比你更熟悉这个领域。

拆分领域

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

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

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

细化子域

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

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

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

关于领域概念的梳理,我以为能够采用四色原型分析法,这个分析法经过系统的方法,将概念划分为不一样的种类,为不一样种类的概念标注不一样的颜色。而后将这些概念有机的组合起来,从而让咱们能够清晰的分析出概念和概念之间的关系。有兴趣的同窗能够在网上搜索下四色原型

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

DDD切入点3 - 领域模型设计

这部份内容,我想学习DDD的人都很熟悉了。DDD原著中提出了不少实用的建模工具:聚合、实体、值对象、工厂、仓储、领域服务、领域事件。咱们可使用这些工具,来设计每个子域的领域模型。最终经过领域模型图将设计沉淀下来。要使用这些工具,首先就要理解每一个工具的含义和使用场景。不要觉得很简单哦,好比聚合的划分就是一个很是具备艺术的活。同一个系统,不一样的人设计出来的聚合是彻底不一样的。并且颇有可能高手之间的最后设计出来的差异反而更大,实际上我认为是世界观的相互碰撞,呵呵。因此,要领域建模,我以为每一个人都应该去学学哲学知识,这有助于咱们更好的认识世界,更好的理解事物的本质。

关于这些建模工具的概念和如何运用我就很少展开了,我博客里也有不少这方面的介绍。下面我再讲一下我认为比较重要的东西,好比到底该如何领域建模?步骤应该是怎么样的?

领域建模的方法

经过上面我介绍的细化子域的内容,如今再来谈该如何领域建模,我以为就方便不少了。个人主要方法是:

  1. 划分好边界上下文,一般每一个子域(sub domain)对应一个边界上下文(bounded context),同一个边界上下文中的概念是明确的,没有任何歧义;
  2. 在每一个边界上下文中设计领域模型,具体的领域模型设计方法有不少种,如以场景为出发点的四色原型分析法,或者我早期写的这篇文章;这个步骤最核心的就是找出聚合根,并找出每一个聚合根包含的信息;关于如何设计聚合,能够看一下我写的这篇文章
  3. 画出领域模型图,圈出每一个模型中的聚合边界;
  4. 设计领域模型时,要考虑该领域模型是否知足业务规则,同时还要综合考虑技术实现等问题,好比并发问题;领域模型不是概念模型,概念模型不关注技术实现,领域模型关心;因此领域模型才能直接指导编码实现;
  5. 思考领域模型是如何在业务场景中发挥做用的,以及是如何参与到业务流程的每一个环节的;
  6. 场景走查,确认领域模型是否能知足领域中的业务场景和业务流程;
  7. 模型持续重构、完善、精炼;

领域模型的核心做用:

  1. 抽象了领域内的核心概念,并创建概念之间的关系;
  2. 领域模型承担了领域内的状态的维护;
  3. 领域模型维护了领域内的数据之间的业务规则,数据一致性;

下图是我最近作个一个普通电商系统的商品中心的领域模型图,给你们参考:

领域模型设计只是软件设计中的一小部分

须要特别注意的是,领域模型设计只是整个软件设计中的很小一部分。除了领域模型设计以外,要落地一个系统,咱们还有很是多的其余设计要作,好比:

  • 容量规划
  • 架构设计
  • 数据库设计
  • 缓存设计
  • 框架选型
  • 发布方案
  • 数据迁移、同步方案
  • 分库分表方案
  • 回滚方案
  • 高并发解决方案
  • 一致性选型
  • 性能压测方案
  • 监控报警方案

等等。上面这些都须要咱们平时的大量学习和积累。做为一个合格的开发人员或架构师,我以为除了要会DDD领域驱动设计,还要会上面这么多的技术能力,确实是很是不容易的。因此,千万不要觉得会DDD了就觉得本身很牛逼,实际上你会的只是软件设计中的冰山一角而已。

总结

本文的重点是基于我我的对DDD的一些理解,但愿能整理出一些本身总结出来的一些感悟和经验,并分享给你们。我相信不少人已经看过太多DDD书上的东西,我老是感受书上的东西看似都太”正规“,不少时候咱们读了以后很难消化,就算理解了书里的内容,当咱们想要运用到实践中时,老是感受无从下手。本文但愿经过通俗易懂的文字,介绍了一部分我对DDD的学习感悟和实践心得,但愿能给你们一些启发和帮助。

相关文章
相关标签/搜索