最近一直在学习和研究DDD领域驱动设计(Domain Driven Design),DDD其实已经火了很多年了,只不过一直没有系统的去学习和应用到项目中,之前也是在网上和别人的演讲中零零散散的了解了一些设计理念,DDD给初学者的感觉就是太抽象,不实际,没办法应用到日常项目中,最近系统的看了DDD的两本巨著后对DDD也有一些自己的感悟,打算写几篇文章记录下。
先从自己理解的角度概括下DDD的核心理念,DDD我的理解其实就是从业务角度将系统进行可扩展的领域拆分。同一个实体在不同的业务领域中可能有不同的属性,但是现实中可能是同一个东西,例如一辆车在仓库中是一个库存车辆实体,但是这辆车如果放到了4S店就成了一辆待售车辆实体,不同领域进行实体交互的时候通过各个领域中的适配层将不同领域的实体进行映射转换。讲了这些可能还是有些抽象,其实个人觉得这个核心理念其实和开发中的传统分层概念很像只不过是从技术层面转移到了业务层面,例如传统技术分层会将系统分为展示层、服务层、数据操作层,每层之间通过调用上下游系统的接口进行操作,这样设计的目的无非也是为了避免各个层面如果有具体实现上的变动例如数据库换了,只要接口保持不变就不会影响到其他层次。DDD其实也是要达到一样的效果,只不过这里就不是为了避免技术层面的改动影响很多上下游层的改动,而是为了减少或避免某一个业务模块的改动,而影响到其他业务模块的改动,这就要求前期对业务能够有充分的理解,需要领域专家能够从业务角度充分拆解业务模块,做到每个业务模块是高内聚,模块之间是低耦合的。这个工作是非常考验对业务的理解的,并不是一个普通的技术人员就能够很好的拆解出来,技术人员更多的还是习惯于从数据模型驱动开发,想想平时我们开发的时候是不是先设计好数据表,然后根据数据表进行各个业务功能的开发。
这个系列的文章我计划是将自己学习过程中对DDD的知识点进行提炼和总结,希望能够帮助大家在以后遇到类似这个功能应该放在哪个系统去实现的问题时做到有章可循,在新系统设计的时候能够提前就分析好业务模块划分,避免以后出现一个小改动结果涉及到一堆系统配合改造。
第一篇文章先介绍下DDD中的一些核心概念的名词解释,让大家知道这些抽象名词都是什么意思。
界限上下文:代表一个系统、一个应用程序或者一种业务服务。限界上下文所包含的领域模型概念应该是高度相关的,这样可以保证在同一个上下文中所有的领域模型都是为了完成同一个业务功能而设计的,这样可以最大程度的避免不同界限上下文频繁交互访问,一旦发现一个界限上下文中频繁访问另一个界限上下文中的领域模型,那么就应该将这个领域模型放到你的界限上下文中了。
通用语言:在一个特定的限界上下文中只使用一套通用语言,并且保证它的清晰性,避免一个概念在同一个界限上下文中的二义性,也可以理解成一套业务字典,这套字典可以作为业务人员和技术人员之间的桥梁。
领域:从大了看,领域代表整个公司的运作一切。从小了看,是每个组织运作中的一切。所以领域的概念必然与公司的组织架构所承担的职责有一定的关系。
子域:一个领域内可以包含N个子域。理论上一个子域对应一个限界上下文是最优也是最理想的情况,但是有时又要考虑到业务关联度需要做出权衡。子域又分核心域、支撑子域、通用子域。
核心域:它是整个业务领域的一部分,也是业务成功的主要促成因素。从战略层面上讲,企业应该在核心域上胜人一筹。我们应该给予核心域最高的优先级、最资深的领域专家和最优秀的开发团队。在实施DDD的过程中将主要关注核心域。
支撑子域:对应着业务的某些重要方面,但却不是核心,那么它便是一个支撑子域。
通用子域:某个支撑子域的运用范围是整个系统,那么这个子域便是通用子域。
上下文映射图:由多个界限上下文和子域组成的表示当前单个领域或者多个领域之间的集成关系图。
上面介绍的是DDD中的核心概念名词,在实现层面同样也会涉及到一些关系名词:
合作关系(Partnership):如果2个限界上下文的团队存在高度依赖要么一起成功,要么一起失败,此时就是合作关系。应该为相互关联的软件功能制定好计划表,这样可以确保这些功能在同一个发布中完成。
共享内核(Shared Kernel):对模型和代码的共享将产生一种紧密的依赖性,对于设计来说,这种依赖性可好可坏。我们需要为共享的部分模型指定一个显式边界,并保持共享内核的小型化。共享内核具有特殊的状态,在没有与另一个团队协商的情况下,这种状态是不能改变的。
客户方—供应方(Customer-Supplier Development):当2个团队处于一种上游和下游关系时,上游团队可能独立于下游团队完成开发,此时下游团队的开发可能会受到很大的影响。因此,在上游团队的计划中,我们应该顾及到下游团队的需求,下游系统也可以先依赖挡板完成开发。
遵奉者(Conformist):在存在上下游关系的2个团队中,如果上游团队已经没有动力提供下游团队之需,下游团队便孤军无助了。处于利他主义,上游团队可能向下游团队做出种种承诺,但是有很大的可能是:这些承诺是无法实现的。下游团队只能盲目地使用上游团队模型。这个在日常工作中经常会遇到例如银行的核心系统是很强势的,下游系统只能作为遵奉者使用核心系统提供的接口,再烂也要用。。。
防腐层(Anticorruption Layer):在集成2个设计良好的限界上下文时,翻译层可能很简单,甚至可以很优雅的实现。但是,当共享内核,合作关系或客户方——供应方关系无法顺利实现时,此时的翻译将变得复杂。对于下游客户来说,你需要根据自己的领域模型创建一个单独的层,该层作为上游系统的委派向你的系统提供功能。防腐层通过已有的接口与其他系统交互,而其他系统只需要做很小的修改,甚至无需修改。在防腐层内部,它在你自己的模型和他方模型之间进行翻译转换。防腐层有点类似于设计模式中的Adapter模式,帮不同领域之间的模型进行适配,这样可以保证领域核心部分无需改动修改防腐层就能满足需求。
开放主机服务(Open Host Service):定义一种协议,让你的子系统通过该协议来访问你的服务。并且需要将协议公开。开放服务的方式有很多,可以是rest api可以是TCP定长报文也可以是pb这样的RPC协议格式。
发布语言(Published Language):在2个限界上下文之间翻译模型需要一种公用的语言。此时你应该使用一种发布出来的共享语言来完成集成交流。发布语言通常与开放主机服务一起使用。
大泥球(Big Ball of Mud):当我们检查已有系统时,经常会发现系统中存在混杂在一起的模型,它们之间的边界是非常模糊的。此时你应该为整个系统绘制一个边界,然后将其归纳在大泥球范围之列。在这个边界内,不要试图使用复杂的建模手段来化解问题。同时,这样的系统有可能会向其他系统蔓延,应该对此保持警觉。
本篇一股脑将DDD中常用的概念名词都简单解释了一遍,后面会随着我学习的深入再陆续产出一些个人对DDD理解的文章,希望能帮助架构师去学习DDD的设计理念。