DDD 领域驱动设计学习(一)- 领域模型和统一语言_ddd领域语言-程序员宅基地

技术标签: DDD  

1. DDD是什么?解决什么问题?

1.1 软件开发的困境

“随着业务的扩展,软件开发投资越来越大” 团队的规模也开始变得越来越大,软件系统的投资和维护的成本变得越来越高。

“业务人员不懂架构,架构师不懂代码,开发人员不不懂业务模型” 当团队中的关键角色谁也不懂谁的时候,问题来了。。。

“重构是好的,但什么时候要重构?重构到什么样的架构就是够⽤的了?” 每个有追求的团队都在做重构,但管理者更关心,什么时间必须要重构?重构的目标在哪?

1.2 DDD的来源及简介

2004年Eric Evans 发表Domain-Driven Design –Tackling Complexity in the Heart of Software (领域驱动设计),简称DDD,DDD是一套综合软件系统分析和设计的面向对象建模方法。

Eric的著名书籍《领域驱动设计》的副标题是“软件核心复杂性的应对之道”,这个其实点出了DDD的来源和目标,很多因素会使软件的开发复杂化。软件是从现实世界到数字世界的一种建模和映射,软件复杂性的根本原因还是业务本身复杂性,软件开发者无法回避这种复杂性,所能做的是去控制这种复杂性。

怎样才能让软件和领域和谐相处呢?最佳方式是让软件成为领域的一个映射。软件需要包含领域里重要的核心概念和元素,并精确实现它们之间的关系。也就是说,软件需要对领域进行建模。

领域驱动设计分为两个阶段:以一种领域专家、设计人员、开发人员都能理解的通用语言作为相互交流的工具,在交流的过程中发现领域概念,然后将这些概念设计成一个领域模型;第二个阶段是由领域模型驱动软件设计,用代码来实现该领域模型。

从DDD提出到开始流行,感觉经过了10年左右的时间,巧的是XP和敏捷从提出到流行也差不多10年左右的时间。可见一套方法论从出现到成熟确实是有一定规律并需要成长时间的。

按Martin Fowler在PoEAA一书中给了一个图。说明当软件在开发初期,以数据驱动的架构方式非常容易上手,但是随着业务的增长和项目的推进,软件开发和维护难度急剧升高。领域驱动设计则在项目初期就处在一个比较难以上手的位置,但是随着业务的增长和项目的推进,软件开发和维护难度平滑上升。
   Adapted from Martin Fowler's PoEAA

2. 模型和建模

2.1 什么是模型

  1. 模型是对客观世界事物的一种抽象和简化。
  2. 它是从某个角度反映人对客观世界事物的一种认识。
  3. 它用于对事物的本质进行深入细致的研究。

2.2 模型的例子

2.2.1 地图的例子

地图就是一种典型的模型。现实世界的地理信息往往很复杂,一个地理位置上会包括非常多的信息,例如有位置信息,地形,气候等信息,也有城市,道路,绿化,管网,建筑等这些城市建设信息,还可能会有拥堵情况,商场,文化等各种附加于地理信息的各种信息在里面。如何表达一个地图信息其实并不容易,如何表达一个地图信息是一件非常复杂的事情。

我们常见的地图,一般都会缩小尺寸,忽略很多细节,分不同类型的地图,现在还有图层的方式来表达不同地理信息。地图其实就是一种模型,而且地图很多建模方式在软件设计中也能找到映射。

看两个地图例子,建模从古至今就存在,而且随着人们认知水平和建模能力还会不断的演进。

图一、 古代天下地图
图二、 百度地图例子
回到软件研发的话题,软件的研发也是一种建模的过程,传统的方法中,从问题空间到解决方案的空间,会经过需求采集和分析,概要设计,详细设计再到编码的过程。正如我们国家“系统分析师” 和“系统设计师” 两种职称考试一样,系统分析和系统设计是分离的,“系统分析师” -BA属于业务专家,“系统设计师”-SA是系统专家。随着信息不断传递的过程,信息也在不断的失真,导致可能到了最后交付阶段才发现很多功能不是客户想要的,或者客户需求变化太快,软件的变更也不能快速跟随需求变化。

再举一个常见的例子:一个函数写了几千行,里面的if-else写了一大堆,计算各种业务规则。另一个人接手之后,分析了好几个月,才把业务逻辑彻底理清楚。从表面来看,这是代码写的不规范,要重构,把一个几千行的函数拆成一个个小的函数。从根本上来讲,就是“重要逻辑”隐藏在代码里面,没有“显性”的表达出来。这里可以引用一个观点:建模的本质就是把“重要的东西进行显性化,并进而把这些显性化的构造块,互相串联起来,组成一个体系“。

DDD通过建立一个业务域到软件域的通用模型,把问题空间同解决方案空间联系在一起,真正把领域的知识挖掘出来,让领域专家可以去驱动软件的实现。

3. 统一语言(UBIQUITOUS LANGUAGE)

解决问题首先要从理解问题入手,很多事情的难点不在于解决问题,而在于认知问题。关于统一语言必要性,有一个经典的通天塔故事,人类想建一座通天塔,进度很快,上帝害怕了,于是上帝让建造者说不通的语言,这样通天塔就再也没有能建起来了。统一语言是一件事情能顺利开展的基础。

由于语言上存在鸿沟,领域专家们只能模糊地描述他们想要的东西,开发人员虽然努力去理解一个自己不熟悉的领域但也只能形成模糊的认识,结果就是各说各的话,或者都是一知半解,最后到上线前才会发现漏了这个漏了那个。

通用语言也并不是像UML,XML Schema或Java这样的语言,它是一种自然的但经过浓缩的领域语言,它是一种开发与用户共享的语言,用来描述问题和领域模型。通用语言不是把从用户那里听到的内容翻译为开发的语言,而是为了减少误解,让用户更容易理解的草图,从而可以真正的帮助纠正错误,帮助开发获取有关的领域新知识。

那么统一语言到底长什么样子?对DDD的UL没有标准的定义,可以是图,也可以是文字,UML的各种图依然是常见的表达方式,以DDD书中例子来说明下UL的一个应用。

示例:制定货运路线,比较两个图和两段沟通交流的方式

  • 场景1:最小化的领域抽象
    在这里插入图片描述

  • 场景2:用领域模型进行讨论
    image.png

两种沟通方式的比较

  最小化的领域抽象 用领域模型进行讨论
用户 那么,当更改清关(customs clearance)地点时①,需要重新制定整个路线计划啰。 那么,当更改清关地点时,需要重新制定整个路线计划啰。
开发人员 是的。我们将从货运表(shipment table)中删除所有与该货物id相关联的行,然后将出发地、目的地和新的清关地点传递给Routing Service,它会重新填充货运表。Cargo中必须设立一个布尔值,用于指示货运表中是否有数据。 是的。当更改Route Specification(路线说明)的任意属性时,都将删除原有的Itinerary(航线),并要求Routing Service(路线服务)基于新的Route Specification生成一个新的Itinerary。
用户 删除行?好,就按你说的做。但是,如果先前根本没有指定清关地点,也需要这么做吗? 如果先前根本没有指定清关地点,也需要这么做吗?
开发人员 是的,无论何时更改了出发地、目的地或清关地点(或是第一次输入),都将检查是否已经有货运数据,如果有,则删除它们,然后由Routing Service重新生成数据。 是的,无论何时更改了Route Spec的任何属性,都将重新生成Itinerary。这也包括第一次输入某些属性。
用户 当然,如果原有的清关数据碰巧是正确的,我们就不需要这样做了。 当然,如果原有的清关数据碰巧是正确的,我们就不需要这样做了。
开发人员 哦,没问题。但让Routing Service每次重新加载或卸载数据会更容易些。 哦,没问题。但让Routing Service每次重新生成一个Itinerary会更容易些。
用户 是的,但为新航线制定所有支持计划的工作量很大,因此,除非非改不可,我们一般不想更改航线。 是的,但为新航线制定所有支持计划的工作量很大,因此,除非非改不可,我们一般不想更改路线。
开发人员 哦,好的,当第一次输入清关地点时,我们需要查询表格,找到以前的清关地点,然后与新的清关地点进行比较,从而判断是否需要重做。 哦。那么需要在Route Specification添加一些功能。这样,当更改Route Specification中的属性时,查看Itinerary是否仍满足Specification。如果不满足,则需要由Routing Service重新生成Itinerary。
用户 这个处理不必考虑出发地和目的地,因为航线在此总要变更。 这一点不必考虑出发地和目的地,因为Itinerary在此总是要变更的。
开发人员 好的,我明白了。 好的,但每次只做比较就简单多了。只有当不满足Route Specification时,才重新生成Itinerary。

很明显,这两段对话有意使用了相似的结构,第一段对话显得更啰嗦,对话双方需要不断对应用程序的特性和表达不清的地方进行解释。第二段对话使用了基于领域模型的术语,因此讨论更简洁,表达了领域专家的更多意图。在这两段对话中,用户都使用了“itinerary”这个词,但在第二段中它是一个对象,这使得双方可以更准确、具体地进行讨论。他们明确讨论了“route specification”,而不是每次都通过属性和过程来描述它。

作者:njluz
链接:https://www.jianshu.com/p/39c557f5b87f
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/woshihyykk/article/details/108713296

智能推荐

在移动硬盘中安装win10和macos双系统-程序员宅基地

文章浏览阅读1.1k次,点赞22次,收藏23次。本文通过在SSD移动硬盘中安装win10和macos双系统,实现操作系统随身携带小慢哥的原创文章,欢迎转载目录 目标 准备工作 Step1. 清空分区,转换为GPT Step2. 安装win10 Step3. 压缩win10分区容量 Step4. 创建2个分区 Step5. 将bootcamp驱动放置到exFAT分区中 Step6. 将macos分区..._mac移动硬盘装双机系统

TransmittableThreadLocal解决线程池本地变量问题,原来我一直理解错了-程序员宅基地

文章浏览阅读14次。theme: cyanosishighlight: a11y-dark前言自从上次TransmittableThreadLocal框架作者评论我之后,我重新去看了下源码,终于在这个周天,我才把TransmittableThreadLocal解决线程池变量丢失的问题搞明白,而且发现我之前的认识有问题,久久孩子我之前是觉得,InheritableThreadLocal解决父子线...

Exchange 2016部署实施案例篇-03.Exchange部署篇(上)-程序员宅基地

文章浏览阅读366次。  距离上一篇《Exchange 2016部署实施案例篇-02.活动目录部署篇》博文更新已经过去快一周了,最近一直在忙项目上的事情和软考,整的真心有点身心俱疲啊,最近看了下上一篇博文不知道为什么访问量一直上不去,真心有点心寒啊。希望大家能多多提出宝贵意见,看看如何能让访问量上去。  废话就不多说了,开始今天的话题,Exchange的部署篇,我原定计划是把部署篇分上、下2个篇幅来写的,但最近发现好..._解决exchange2016部署先决条件

[译]使用MVI打造响应式APP(四):独立性UI组件-程序员宅基地

文章浏览阅读130次。原文:REACTIVE APPS WITH MODEL-VIEW-INTENT - PART4 - INDEPENDENT UI COMPONENTS作者:Hannes Dorfmann译者:却把清梅嗅这篇博客中,我们将针对如何 如何构建独立组件 进行探讨,我将阐述为什么在我看来 父子关系会导致坏味道的代码,以及为何这种关系是没有意义的。有这样一个问题时不时涌现在我的脑海中—— MVI...

tensorflow经过卷积及池化层后特征图的大小计算_池化层后特征图尺寸-程序员宅基地

文章浏览阅读662次。https://blog.csdn.net/qq_32466233/article/details/81075288_池化层后特征图尺寸

使用vue-echarts异步数据加载,不能重新渲染页面问题。_vue echart初始化渲染过后无法重新渲染-程序员宅基地

文章浏览阅读3.3k次。一、问题说明我是用的是官方示例中的这个饼状图。结果在应用到项目中后发现利用axios请求到的数据无法渲染到页面中去。并且其中value值已经改变。二、解决办法用$set改变value的值,并且重新绘制一遍表格。$set是全局 Vue.set 的别名。$set用法:向响应式对象中添加一个属性,并确保这个新属性同样是响应式的,且触发视图更新。它必须用于向响应式对象上添加新属性,因为..._vue echart初始化渲染过后无法重新渲染

随便推点

Dev-C++ “to_string is not a member of std” error- 已解决_devc++ [error] 'to_string' is not a member of 'std-程序员宅基地

文章浏览阅读3.7k次。今天在用Dev-C++ 的时候遇到一个错误“to_string is not a member of std” error解决方法:设置编译语言为ISO C++11 在菜单栏的Tool -> Compiler Option_devc++ [error] 'to_string' is not a member of 'std

python的10款最好的IDE_pydea兼容的-程序员宅基地

文章浏览阅读1.1k次。Python 非常易学,强大的编程语言。Python 包括高效高级的数据结构,提供简单且高效的面向对象编程。Python 的学习过程少不了 IDE 或者代码编辑器,或者集成的开发编辑器(IDE)。这些 Python 开发工具帮助开发者加快使用 Python 开发的速度,提高效率。高效的代码编辑器或者 IDE 应该会提供插件,工具等能帮助开发者高效开发的特性。这篇文章收集了一些对开发者非常有_pydea兼容的

python translate函数_Python:内置函数makestrans()、translate()-程序员宅基地

文章浏览阅读287次。一、makestrans()格式: str.maketrans(intab,outtab);功能:用于创建字符映射的转换表,对于接受两个参数的最简单的调用方式,第一个参数是字符串,表示需要转换的字符,第二个参数也是字符串表示转换的目标。注:两个字符串的长度必须相同,为一一对应的关系。注:Python3.6中已经没有string.maketrans()了,取而代之的是内建函数:bytearray...._python maketrance

Set集合详解-程序员宅基地

文章浏览阅读5.7k次,点赞9次,收藏14次。set集合的简介,它的特点和遍历方式。介绍了HashSet重复元素存储底层原理,LinkedHashSet,TreeSet排序方法,SortedSet获取集合值的方法_set集合

详解智慧城市排水管理系统整体方案_污水处理智慧管理系统案列-程序员宅基地

文章浏览阅读3.6k次,点赞3次,收藏29次。随着城市规模的不断扩大和现代化程度的日益提高,城市排水管网越来越复杂,一些城市相继发生大雨内涝、管线泄漏爆炸、路面塌陷等事件,严重影响了人民群众生命财产安全和城市运行秩序。因此,摸清排水管网设施资产家底、建立排水管网地理信息系统,用现代化的技术手段对排水系统进行科学管理显得迫在眉睫。以时空信息为基础,充分利用感知监测网、物联网、云计算、移动互联网、工业控制和水力模型等新一代信息技术,全方位感..._污水处理智慧管理系统案列

详解NTFS文件系统_ntfs文件系统中,磁盘上的所有数据包括源文件都是以什么的形式存储-程序员宅基地

文章浏览阅读5.7k次,点赞4次,收藏13次。上篇在详解FAT32文件系统中介绍了FAT32文件系统存储数据的原理,这篇就来介绍下NTFS文件系统。NTFS、用过Windows系统的人都知道,它是一个很强大的文件系统,支持的功能很多,存储的原理也很复杂。目前绝大多数Windows用户都是使用NTFS文件系统,它主要以安全性和稳定性而闻名,下面是它的一些主要特点。安全性高:NTFS支持基于文件或目录的ACL,并且支持加密文件系统(E_ntfs文件系统中,磁盘上的所有数据包括源文件都是以什么的形式存储

推荐文章

热门文章

相关标签