做为一个领域驱动设计的实践者,我切实感觉到了领域驱动为软件开发带来的好处,同时在实践领域驱动的过程当中也感觉到了困难,这种困难体如今工程实践的方方面面,例如什么是领域驱动的最佳设计?如何把书本上的设计灵活的应用在本身的项目上?如何跟团队成员就设计达成一致?数据库
本文尝试从领域驱动设计的目的出发,试图经过简单的描述来讲明领域驱动设计的思想。数据库设计
做为一个软件开发者,多数人觉得本身的职责就是编写代码,然而软件开发不是工厂流水线,若是全部的软件开发者不停的开发新功能而不关心设计,那么软件开发过程将会变得愈来愈复杂,关于这一点你们应该都有不一样程度的感觉。
软件开发工程师的工做是经过软件来解决问题,编写代码只是其中的一部分工做,设计和交流一样重要。而领域驱动设计就是一个让软件开发工程师交流和共享领域知识的途径。
微服务
做为一个问题的解决者,可否理解和认识问题的来龙去脉相当重要。很明显,若是你只看到了问题的表面,或者对事实有曲解,你显然不会找到一个有效的解决方案。对于开发者,若是你编写的代码只是你的理解,而不是领域专家的理解,你如何保证线上产品的质量?设计
那么如何保证开发者编写的代码就是领域专家的想法?最简单的办法就是让领域专家来编写代码,可是这种方案可遇不可求,还有没有别的办法呢?3d
若是领域专家,开发团队以及代码可以共享一个模型,这将有效减小不一样利益相关者的沟通及交流,而且会确保全部人都在解决同一个问题。对象
这个想法要求开发者可以把代码设计为一个反映业务的模型,而这正是领域驱动设计的核心思想。
blog
为了在领域专家和开发者之间创建一个共享模型,收集需求并理解业务是第一步。收集需求和理解业务的方式多种多样,而事件风暴常常被用来达到这一目的。业务逻辑能够看作是一系列状态的转换过程,而这些过程转换又被称为领域事件。好比“订单已提交”就是一个领域事件,若是把这个领域事件看作是订单业务的开始,经过梳理”订单已支付”以及”订单已出库”等后续的领域事件,就能够理解整个订单业务。此时对业务的理解被称为“问题域”。
事件
经过事件风暴,开发团队和领域专家已经对整个”问题域”有了理解,可是如今着手解决“问题域”还有点早。当咱们在面对一个大的问题时,天然而然会想到先将大的问题划分红若干个小问题,而后再考虑各个击破。接下来的一步就是把大的问题域划分为若干个小的问题域。咱们有一个网上商城的问题域,能不能把它分割为更小的问题域?开发
答案确定的,咱们把网上商城的问题分为:“订单”,“销售”,“市场”,“财务”,“采购”等若干个小问题域,再针对小的问题域分而治之。小的问题域在领域驱动设计中被称为“问题子域”。
博客
理解了问题域并划分为问题子域并不意味着你就能建立出一个好的方案,你没法针对问题子域的全部信息设计出一个解决方案,你的解决方案只会专一于那些有助于解决该问题子域的信息,对于不相关的信息则会人为的屏蔽掉。
在现实世界中,领域的边界很模糊,可是要设计一个好的解决方案,咱们须要对问题子域加上一个边界,将不重要的信息排除在边界外。让解决方案专心解决重点问题。
每一个上下文都表明着该解决方案的专业知识。在同一个上下文里,咱们共享统一的语言和一致的设计。
经过界限上下文人为将问题子域限制在有限的界限内,你才能够着手建立解决方案。
团队之间共享的术语和词汇被称为统一语言。统一语言用来定义业务领域的共享模型,固然能够用在项目的任何地方,包括需求分析和设计,最重要的是统一语言还须要出如今代码中。另外,统一语言在不一样的界限上下文中每每不可以通用,例如在“认证上下文”中提到“用户”,在“机票订单上下文”中叫作“乘客”。
有了界限上下文,让解决方案聚焦在最有用的信息里,你才能够着手创建共享模型。
如何才能创建一个不错的共享模型呢?
使用可视化的图示彷佛是一个不错的想法,但实际上画出一个可以表达全部领域知识的图示并非一个简单的工做;若是你有数据库开发相关的经验,你可能会想到经过表和主外键来表达领域知识,若是你有这样的想法那你就错了,在领域驱动设计中讲究经过领域逻辑来驱动设计和开发工做,而不是经过数据库模型来驱动开发。
在领域驱动设计中这一步叫作”领域建模“,你应该用代码创建一个反映领域知识的模型,这个模型跟领域专家口中的领域知识是一致的。领域模型是提供业务能力的核心部件,也是整个应用程序提供业务能力的核心。
对于开发者而言领域建模相当重要,也是最考验开发者功底的一个环节。一方面开发者须要抽象出一个跟领域专家口中一致的模型,另外一方面开发者还须要经过代码将这个模型表达出来。你须要恰如其分的使用一些面向对象的技巧把领域知识抽象到一个代码模型中,在这个过程当中你须要了解”值对象”,”实体“,”聚合根“等概念,在此再也不细说。
在领域建模以及以前的步骤中,咱们都没有说起数据库,由于领域驱动设计的核心是用代码创建一个共享模型,而数据库设计根本就不是领域驱动设计关心的内容。
可是终究咱们仍是要把领域模型的状态持久化到数据库中,有没有办法在不关心数据库表结构的状况下,将已经创建好的领域模型持久化?主流ORM的Code First刚好匹配咱们如今的处境,已经有一点为领域驱动设计而生的味道了。
可是即使是ORM的Code First也会对领域模型有侵入,你可能须要根据不一样的ORM为模型加上一些注解或者配置之类的代码,这跟领域驱动设计实际上是相互违背的,咱们但愿用代码建立一个纯净的领域模型,这个模型封装着领域专家的领域知识,除此以外的代码都跟领域模型是无关。
解决上面问题的思路是引入领域事件和事件溯源。领域模型在提供业务能力的过程,就是领域模型状态发生变化的过程。一旦领域模型的状态发生了变化,就会产生一个事件,这跟事件风暴中提到的业务事件是一致的,例如”用户已下单“。订单模型在提供”用户已下单“的业务能力后发生了状态变化。事件溯源的思路就是只持久化领域事件,而后经过还原事件的方式将领域模型还原在最新的状态。
经过采起事件溯源,就能够将领域模型持久化跟数据库彻底解耦。
咱们经过领域驱动设计的思路来分析和发现问题域,经过分解把问题域划分为问题子域,经过人为加限制的方式将问题子域转换为限界上下文。而这个过程就是咱们分解微服务的过程,通常来讲每个限界上下文均可以映射为一个微服务,但也不是绝对的,具体状况具体分析。
每个微服务专一于解决对应的限界上下文中的问题,并不表明微服务之间没有交流。单个微服务的领域模型在提供服务的过程当中会产生领域事件,领域事件为基于事件驱动(Event based)的微服务集成提供了基础,若是在微服务之间架设一条消息总线(不一样于ESB,ESB被认为是反模式)。不一样的微服务将本身产生的领域事件广播在消息总线上,微服务之间经过订阅本身感兴趣的事件就能完成微服务的集成。
迄今为止咱们已经创建了领域模型,建立了微服务,经过消息和领域事件完成了微服务的集成。还须要把微服务的能力经过REST API展示出来,微服务在对外提供能力的过程就是领域模型状态发生变化的过程,若是将领域模型理解为一个设计精良的状态机也一点不为过。若是设法将领域模型在某个状态下可以提供的能力经过REST API的的返回结果表达出来,这就是HATEOAS的核心思想。REST API不但能够提供某种能力,还能够告诉消费者此时领域模型可以提供的其余能力。
本文从需求分析到API设计,试图描述领域驱动设计的过程及思想。同时也能看的出领域驱动设计并非孤立存在的,它为解决开发团队和业务人员之间沟通而生,进而驱动微服务划分以及API的设计,领域驱动设计并非高不可攀的方法论,每个专业术语和思想都是为了解决基本的问题而定义,但愿本篇博客可以带你走入领域驱动设计。