领域驱动设计(DDD)- 请先搞清楚一些概念
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了领域驱动设计(DDD)- 请先搞清楚一些概念相关的知识,希望对你有一定的参考价值。
开发一个新系统
一般我们开始开发一个商业系统都需要做什么?读需求文档去查找功能点,拆解任务。多数情况下,拆解项目是为了评估工作,做评估、分配任务到个人、设计数据库结构,然后就开始了Coding。
所以,这种方式怎么样?我们是否已经做的很好了??
想想近几年通过这种方式做的项目是否都有下面一些问题呢?
- 你的项目在一些地方有着相同的实现
- 对同一个东西有着不止一个的对象
- 有些对象的属性并不是真实的属性
- 各个对象相互之间没有或者有很小的关联
- 看看你的项目是不是很难理解项目的真正意图
我肯定你经常遇到上面的问题,你知道为什么会出现这些问题么?原因是传统的方式指导我们自下而上的设计整个系统,而不是尝试着自上而下的设计系统。当你设计一个系统,你需要整个程序将要做什么,客户想要达到什么样的目标,那么从顶层目标开始设计会让你最终达到预定的目标。
但是当你从底层开始设计的时候,你会从细微处开始设计,你只有一点或者没有任何关于顶层怎么使用或者顶层的功能到底是怎样的。
你是否听说过有些开发者说他们对整个领域的知识并不清楚,那是必然的,因为整个程序的设计并不能体现整个领域,并且开发者只了解他们工作的那个部分,这是很悲催的事情。。。
那么,传统的方式-“数据库优先的开发方式”应该被遗弃么?并不是这个意思,但是当你面对一个复杂的系统,这种自下而上的设计并不能提供一个好的面向对象的处理方式。
那么,好的解决方案是什么?
解决方案就是 DDD(DOMAIN DRIVEN DESIGN)。
什么是DDD?
领域驱动设计(Domain-driven design 缩写DDD)不是一种技术或者方法,DDD提供了一种实践性的指导原则,用来解决和加速处理复杂领域的软件项目 -维基百科。
本文涉及的概念:
- 理解领域(Domain)
- 通用语言(Ubiquitous Language)
- 上下文和有界上下文(Contexts and Bounded Context)
- 实体和值对象(Entities and Value Objects)
- 聚合和聚合根(Aggregates and Aggregate Roots)
- 持久化透明(Persistence Ignorance)
- 仓储(Repository)
- 领域服务(Domain Service)
本文只是对这些感念进行理解,并不提供任何可用的代码。
理解领域
领域是一定范围内的知识、活动、影响。用户用程序去解决、处理的领域就是软件的领域。
领域就是一个概念,你能说出你现在做的程序的领域是什么?,你能说说优酷网站的领域是什么么?
本文就利用生活中真实的例子来让你体验怎么用领域来驱动你去分析你的项目。这个例子可能并不与开发有关,但它们对让你适应上而下的去思考是很有帮助的,同时也过一遍DDD的技术要点。
如果说你要盖一栋房子,那么你需要以下的东西
- 有一块地
- 楼共有6层
- 每层有4个套房
那么你的领域是什么呢?
领域是房子么?可能,但是你应该知道,如果你把房子作为你的领域,那么你可能会忽略很多的小的需求。你设计的房子必须设计那里是让人住的。那么,一般而言的“房子”可能会让我们忽略一些细节,所以,我们应该缩小我们的领域,那就是“民房”。
那么,当你和建筑工人或买房子的人说起你设计的房子时,你所说的“民房”就可以很容易的被人理解了。当承包商告诉你要设计一个6层每层4套房子的时候,在语言上你是否稍微修改了一下呢?现在如果你让建筑工人到一个地方建“房子”,他们可能并没有考虑到一些“民房”的一些特性。但是如果你说了“民房”呢,他们肯定会做出合理的分析。
这就是我们将要说到的“通用语言”
通用语言(Ubiquitous Language)
概念很简单,程序员和销售应该公用同一种两个人都理解的语言,更重要的是,应该使用商业术语而不是技术术语。
更多的“通用语言”的例子:
例1:
错误的语言:
小卧室的长宽比应该是4:3
正确的语言:
儿童卧室长度因该是20尺,宽度应该是15尺。
从这可以看到,对于房主来说“小卧室”,“长宽比”这些都属于技术术语,对他们来说儿童房、客厅、起居室等才是更易理解的词语。很明显尺寸对房主来说更为有意义。
例2:
来看看软件上的一些例子。
错误的语言:
在搜索功能上,我们应该考虑Sql Server的“词干分析器”和“同义词库”来让我们的搜索更合理,另外我们也应该添加排除词,让搜索更精确。
从这里可以看到,如果你的领域专家可能不是个技术型,那么他很有可能不理解“词干分析器”和“同义词库”等。
正确的语言:
在搜索功能上,我们应该考虑搜索词的同义词可以让结果有更多的相关数据,而且我们不应该区别对待数字的奇偶,大小写,分词等,我们应该忽略掉所有的没有意义的干扰字。
你能看到这些语言的不同之处么?一个正确的语言可以让圈内的所有人都以相同的方式理解这些观点。
我们再说说“民房”吧。如果你将设计民房的所有事情当作一个任务并放在一起处理的话,你认为这样明智么?很明显,如果你将这些作为一个工作单元的话,你可能会错过一些东西。设计一个房子有很多相关联的设计,例如,你需要考虑通风,多功能,停车空间,社区等。
正如你所看到的,不同的上下文就出现了,这就是“上下文”和“有界上下文”出现在领域驱动设计的原因了。
“上下文”和“有界上下文”
一个有界上下文可以是一个很小的程序,包括他自己的领域,自己的代码和自己的存储机制,在一个上下文里,他们应该在逻辑上一致,每个有界上下文应该独立于其他的有界上下文。
更多的有界上下文例子:
考虑一下电商系统,最初你可以认为他是一个商店上下文,但是你看的更细点,你会发现其他的上下文,例如:库存,物流,账户等。
合理的拆分一个大型的有界上下文可以让你的应用程序模块化,并且让你区分不同的关注点,而且让应用程序更易于管理和升级。每个有界上下文都有相应的责任和操作。合理的上下文划分可以让我们更容易的找到逻辑所在的位置,从而避免“大泥球”。
什么是“大泥球”(BBOM,Big ball of mud)
大泥球是一个不规则的、杂乱的、松散的泥巴,这类系统是典型的高度重复,快速修复,无意义增长的系统。混乱的消息传递,在一个地方几乎所有的重要信息都是全局的和重复的,所有的系统架构都可能没有被很好的定义。
我们的目标是避免所有的BBOM
我们还来说说“民房领域”吧,我们有几个有界上下文:
- 电力供应
- 停车位
- 套房
- 等等
详细说一下“套房”吧,套房是由不同的房间组成,每个房间又有不同的门窗。那么现在关于屋里面的窗户就有两个问题了:
问题1:你可以想象出来没有屋子的窗户么?
问题2:如果一个窗户没有了容纳他的屋子,那么它有没有唯一的标识?
回答上面的问题会揭示出DDD中下面的概念:
- 实体(Entity)
- 值对象(Value Object)
- 聚合和聚合根(Aggreates & Aggrate root)
实体
“这是我的实体,那里还有许多,但是这个是我的!”
定义实体的关键是实体是有“唯一标识”(Identity)的,唯一标识在系统中标识,无论两个实体是多么的相似,他们都是不同的实体。
例如:
- 你家的卧室
- 博客网的文章
- 博客网的用户
值对象
定义值对象的关键是值对象没有“唯一标识”,这样说可能有点简单,????
聚合和聚合根
上面给出的例子中:
- 房子、订单和问题是聚合根
- 窗户、订单备注和问题详情是聚合
当数据改变时,所有相关的对象被看作一个整体。
所有的外部数据访问都需要通过同一个根节点进入,这个根就是根节点
以上是关于领域驱动设计(DDD)- 请先搞清楚一些概念的主要内容,如果未能解决你的问题,请参考以下文章