最近几年,领域驱动设计(Domain-Driven Design,DDD)这个术语越来越多地出现在软件工程师的视野里。对DDD不熟悉的人可能会觉得它是软件领域里的一个新的概念,但是实际上,Eric Evans在十几年前就已经提出了这个概念。这个“古老”的概念在之所以能够重焕新生,很大程度上是因为遇上了“微服务”这个浪潮。如果把DDD里面的理念拿去和微服务架构做对比,你会发现它们有着高度的相似性——DDD里的限界上下文不正是微服务架构中的微服务吗?于是,各大公司纷纷运用DDD的方法论来构建自己的产品架构。有些团队成功地将DDD结合到了产品架构中,产生了许多优秀的实践;也有些团队反映DDD太过复杂,很难落地。那么DDD究竟是个什么样的理念?为什么大家都争先恐后地使用它,彷佛不加点DDD都不好意思说自己是微服务架构?然而又为什么那么多团队说DDD难以落地?本文将会结合简单的代码实现来谈谈笔者对DDD的理解。

什么是领域驱动设计?

软件的核心是其为用户解决领域相关的问题的能力。

软件就是为了解决某一领域相关问题而存在的,比如一个普通的计算器软件,就是为了满足我们进行简单的加减乘除运算而存在。对于计算器这种小而简单的软件,一个普通的软件工程师可能花上几天就能过设计开发出来,而且基本不会出现Bug。但是对于一些大型而且复杂的系统,一个团队都得花上很长的时间去设计整个架构,然后经过n轮迭代才能开发出可用的版本,而且后面还有各种Bug要去处理。比如证券交易系统,里面就包括了用户系统、账户系统、订单系统、撮合系统等一系列的子系统,而且其中的调用关系和业务都非常复杂。像这样一个庞大的系统,怎样才能把它设计好呢?这正是DDD要回答的问题。

领域驱动设计(DDD)是一种软件开发的方法论,旨在帮助我们设计出高质量的软件模型

在软件领域,解决复杂问题的方法不外乎是“分治”和“抽象”,DDD也是基于这两个理念建立起一套方法论。其中将一个系统划分成多个限界上下文,限界上下文中划分出多个子域,这是分治;然后在分别对各个子域进行领域建模,这是抽象。当你在设计一个业务复杂的系统却无从下手时,尝试一下DDD,说不定困难就会迎刃而解了。DDD中最核心的理念就是领域建模,可以说它提供的各种方法都是为了帮助我们设计出更能准确传达业务规则的领域模型。一个好的领域模型可以让一个系统更加健壮,可以让一个框架易用性更加好,可以让一段代码更加好维护。那么,什么样的模型才是好的领域模型?下面,我们通过一个例子来简单说明下。

什么是领域模型?
领域模型是关于某个特定业务领域的软件模型。通常,领域模型通过对象模型来实现,这些对象同事包含了数据和行为,并且表达了准确的业务含义。

日期和时间领域模型

如何设计一个日期和时间API?

首先需要对日期和时间的概念进行建模,从直觉上,我们可以将日期和时间抽象成一个对象Date。另外,时间和日期经常都需要进行格式化输出,因此我们还需要一个用于表示时间格式的对象DateFormat。为了更好地表示年月周日等概念,再抽象出一个表示日历的Calendar对象,以及表示时区的TimeZone对象。

相信到这里大家都已经知道,这正是JDK 1.1版本的日期时间API,下面我们先回顾一下它的用法:

public class TestOldDate {public static void main(String[] args) {// 获取表示当前时刻的Date对象Date date1 = new Date();// 通过Calendar等到指定日期时间的Date对象,采用当前的系统时区Calendar calendar = Calendar.getInstance(TimeZone.getDefault());calendar.set(2020, 2, 10, 0, 0, 0);Date date2 = calendar.getTime();// 进行时间比较System.out.println("date1 is after date2: " + date1.after(date2));// 进行时间的加减法,如获得昨天的这个时刻:calendar.setTime(date1);calendar.set(Calendar.DAY_OF_MONTH, calendar.get(Calendar.DAY_OF_MONTH) - 1);Date date3 = calendar.getTime();// 对日期格式化输出DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");System.out.println("date3: " + df.format(date3));}
}
/* Output:
date1 is after date2: false
date3: 2020-02-07 23:55:39
*/

如果你用习惯了JDK 1.1版本的日期时间API,可能会觉得上述例子中的用法也没有多大的问题。但是,仔细思考一下就会发现这其中的逻辑跟我们人类对时间的处理逻辑不太像,比如要对时间做加法,首先要将需要操作的Date对象设置到Calendar,然后对Calendar做加法,最后调用Calendar的接口得到结果。时间的加法难道不应该直接对Date对象加上一个时间段就行了吗?

相信很多小伙伴都会遇到这种情况,自己写出来的代码可读性不够好。这其中原因可能是对领域的理解不够深,设计出来的领域模型没能准确的表达业务逻辑(如JDK 1.1的日期时间模型),或者开发前根本就没有进行领域建模。这样容易导致采用了一种“机器思维”去进行开发,而不是按照我们平常思考问题的思维去开发。

JDK 1.8引入了全新的日期和时间API来解决老版本的API所存在的种种问题,下面,我们来看一下比之前更准确地表达日期和时间的领域模型:

JDK 1.8的日期和时间领域模型中的领域知识明显比老版本的领域模型要丰富很多,而且模型更加符合人类思考日期和时间的思维。下面,我们看下新的日期和时间API的用法:

public class TestNewDate {public static void main(String[] args) {// 获取表示当前时刻的LocalDateTime对象LocalDateTime date1 = LocalDateTime.now(ZoneId.systemDefault());// 获取指定时间的LocalDateTime对象LocalDateTime date2 = LocalDateTime.of(LocalDate.of(2020, 2, 10),LocalTime.of(0, 0, 0));// 进行是时间比较System.out.println("date1 is after date2: " + date1.isAfter(date2));// 进行时间的加减法,如获得昨天的这个时刻:LocalDateTime date3 = date1.minus(Period.ofDays(1));// 对时间进行格式化输出DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");System.out.println("date3: " + df.format(date3));}
}
/* Output:
date1 is after date2: false
date3: 2020-02-07 23:56:51
*/

实现同样的功能,JDK 1.8版本的日期和时间API明显更加简洁,而且代码的逻辑更加符合人的思维,可读性更好(比如使用.now()函数创建当前时刻的LocalDateTime对象,代码阅读起来就跟人类的自然语言一样)。由此可见,设计出一个高质量的领域模型对于软件系统是多么的重要。

在这个例子中,JDK并没有显式地使用DDD提供的战术建模手段对日期和时间API进行设计,但是从JDK 1.1到JDK 1.8版本中的变化,其中就蕴含着DDD最核心的内容:设计出更符合业务规则和人类思维的领域模型。从这个例子中我们也能看出,DDD并没有传说中的那么神秘,也未必一定要运用在复杂的系统,即使是一个简单的日期和时间API,其中也可以看到它的身影。

如果让你对JDK 1.1的日期和时间API进行优化,相信很多人都设计不出像JDK 1.8版本的这样优秀的API,不管在经验,还是在方法上我们都欠点火候。简单的API如此,更别说设计复杂的大型系统了。这时,我们需要一些具体的建模方法来指导设计。

DDD的建模方法

DDD主要提出了两种建模方法来帮助我们设计出高质量的领域模型:战略建模和战术建模。

战略建模根据领域知识对系统进行限界上下文和子域的划分,战术建模具体为每个限界上下文设计出领域模型。而这两者中又内涵很多知识点,光看下面的这张DDD的概念图,你可能会觉得DDD太过复杂了。

确实,DDD的学习曲线比较陡,特别是第一次看Eric Evans所著的《领域驱动设计——软件核心复杂性应对之道》时,会有种不知所云的感觉。再看Vaughn Vernon所著的《实现领域驱动设计》可能会好点了,但是里面提到的各种概念还是没能很清晰地理解。所谓“实践出真知”,只有通过不断地实践,才能学习到DDD的精髓,体会到它的魔力。下一篇文章,我们将开始通过实践一个简单的业务功能着手介绍DDD的各种理论知识。

http://weixin.qq.com/r/Tx2zqxDE602UrVTI90hd (二维码自动识别)

领域驱动设计:软件核心复杂性应对之道_人人都可以领域驱动设计(一)相关推荐

  1. 解读《领域驱动设计 软件核心复杂性应对之道》(一)

    最近学习了两遍<领域驱动设计 软件核心复杂性应对之道>.这本书是2000年出头由一个老外写的.然后经过了国人翻译. 2000年出头,技术架构还没有现在这么多好用的工具,也没有云原生的概念. ...

  2. 领域驱动设计 软件核心复杂性应对之道_DDD - 领域驱动设计对软件复杂度的应对(上)...

    不管是因为规模与结构制造的理解力障碍,还是因为变化带来的预测能力问题,最终的决定因素还是因为需求.Eric Evans 认为"很多应用程序最主要的复杂性并不在技术上,而是来自领域本身.用户的 ...

  3. 《领域驱动设计-软件核心复杂性应对之道》阅读笔记(二)

    第二部分 模型驱动设计的构造块 第4章 分离领域 4.1模式:LAYERED ARCHITECTURE 在面向对象的程序中,常常会在业务对象中直接写入用户界面.数据库访问等支持代码.而一些业务逻辑则会 ...

  4. 领域驱动设计_软件核心复杂性应对之道

    领域驱动设计_软件核心复杂性应对之道 转载于:https://www.cnblogs.com/MarvinGeng/archive/2013/02/21/2920968.html

  5. 《领域驱动设计:软件核心复杂性应对之道(修订版)》—第2章 2.1节模式:Ubiquitous Language...

    本节书摘来自异步社区<领域驱动设计:软件核心复杂性应对之道(修订版)>一书中的第2章,第2.1节模式:Ubiquitous Language,作者[美]埃里克•埃文斯(Eric Evans ...

  6. 领域驱动设计:软件核心复杂性应对之道

    http://vdisk.weibo.com/s/AbB5G02cEZ-Zo 转载于:https://www.cnblogs.com/dyh-air/p/7774955.html

  7. 复杂性应对之道——抽象

    写本文的原因是,抽象是软件设计中最重要的概念.但抽象这个概念本身又很抽象,我们有必要花一些时间深入理解抽象.抽象的层次性,以及不遗余力的不断提升我们抽象能力. 抽象的力量 没有抽象思维,就没有人类光辉 ...

  8. Linux下开源pcb设计软件,KiCAD更好用的开源免费的原理图、PCB设计软件

    有没有一款PCB设计工具非常适合初学者?它最好满足以下条件: 可以永远免费使用全部的功能 - 从建库到布局布线,生成各种需要的文件,企业的产品设计也可以放心使用: 除了Windows下,还能够运行在M ...

  9. 开关电源仿真与设计基于spice 第2版 中译本_新书推荐 开关电源控制环路设计Christophe Basso 著...

    前前言: 机械工业出版社的朋友最近跟我聊起这本书,说销量很不错,读者反映也很好,最近又加印了一批,如果喜欢此书还没入手的,最近可以下单了.下文是一年前新书发售时我写的,再次印刷了我就再推荐一次哈~~ ...

最新文章

  1. 不相交轮换的乘积怎么求_谁能告诉我 轮换的乘积 怎么做?具体题目是
  2. Java8 快速实现List转map 、分组、过滤等操作
  3. 厉害了,用Python实现自动扫雷!
  4. pandas使用groupby函数按照多个分组变量进行分组聚合统计、使用agg函数计算分组的多个统计指标(grouping by multiple columns in dataframe)
  5. 深度对比三种主流微服务配置中心
  6. linux系统怎样指定gpu运行,linux服务器如何指定gpu以及用量
  7. 数字图像处理之图像边缘
  8. java中qrcode_如何在Java中使用QRGen创建QRCode
  9. React脚手架学习笔记
  10. raft算法_学习分布式一致性协议:自己实现一个Raft算法
  11. SQL vs NoSQL:异同比较
  12. Win 下面配置 memcache
  13. 工具分享:VISIO 2010版windows_64正版软件32位(附下载链接)
  14. 让SlickEdit 自动编译Keil C51工程
  15. c语言求阶乘的两种算法(递归和循环)
  16. js 京东关闭广告 pink
  17. dede 后台 一直显示验证码不正确的原因
  18. Java中重写父类方法
  19. oc-分类(catgory)的概念及使用
  20. EventBus介绍与使用

热门文章

  1. mybatis3 中 @Provider 的使用方式
  2. 云服务器主机内网 ip 和外网 ip 的区别
  3. Hibernate JPA中@Transient、@JsonIgnoreProperties、@JsonIgnore、@JsonFormat、@JsonSerialize等注解解释
  4. 19-6/28作业:100以内偶数求和
  5. HihoCoder 1323 回文字符串
  6. navicat for mysql 数据库备份与还原
  7. Mantle--国外程序员最常用的iOS模型字典转换框架
  8. 三层架构与设计模式思想部署企业级数据库业务系统开发
  9. MyEclipse使用总结——MyEclipse文件查找技巧 ctrl+shift+R ctrl+H
  10. [jQuery]3D效果的标签云