写点什么

阅读者 (二十八):实现领域驱动设计

  • 2014-05-15
  • 本文字数:2398 字

    阅读完需:约 8 分钟

从 Eric Evans 写下经典名著 Domain-Driven Design: Tackling Complexity in the Heart of Software 至今,DDD 刚好发展了十年的时间。它几乎成了开发复杂软件系统主要的领域设计方法,既是面向对象(组件)设计的补充,又超越了面向对象(组件)设计。DDD 中提出的诸多概念如实体、值对象、聚合等,已经成为了耳熟能详的设计术语。DDD 社区的发展也如火如荼,似乎并没有被层出不穷的设计思想所取代,相反,它仍在强劲地发展,吸收了许多新的概念与方法,例如函数式编程思想、Event Source、CQRS 等。然而,就我个人所观察到的情况来看,许多项目虽然号称应用了 DDD 设计,但主要都停留在 Eric 所谓的“战术设计”层面。即使是战术层面,依旧有许多程序员没有弄明白实体与值对象之间的区别,不知道该怎么定义聚合以及聚合根,更谈不上合理地划分上下文(Context)。

我不明白其中内含的真实原因,只能冒昧地揣测是否 DDD 显得高高在上?究其原因,会否还是 Eric 惹的祸,他的那本经典之作美则美矣,却显得有些不接地气?至少,我的阅读感受正是如此。虽然在之后,国内也引进了其他一些与 DDD 相关的著作,例如 Jimmy Nilsson 的著作《领域驱动设计与模式实战》。这些书好虽好,却并没有全面深入地阐述领域驱动设计,更谈不上完整地实践,直到 Vaughn Vernon 的《实现领域驱动设计(Implementing Domain-Driven Design)》的出现。

这本书首先吸引我的是书中的第 2 章至第 4 章。虽然书中内容几乎忠实地反映了 Eric Evans 的 DDD 理论,但作者却创造性地在一开始就着眼于 DDD 的战略性设计,包括领域(Domain)、子域(Subdomain)、受限上下文(Unbounded Context)、上下文映射(Context Map)以及架构。以第 4 章架构为例,书中对 DDD 经典的分层架构进行了深入探讨与分析,并颠覆性地提出将基础设施层(Infrastructure Layer)置于用户接口层(User Interface Layer)之上。最初读来,简直让我莫名惊诧,然而仔细思索,从依赖倒置原则的角度来分析,实在是合乎情理。坦白说,它彻底解决了之前一直纠缠在我心底的一个问题:若我们视实体为 Repository 以及数据访问的对象,应将实体置于哪一层?在 DDD 中,实体对象承担了领域业务行为,但同时又可能通过 ORM 与数据表产生映射。基础设施层的数据访问对象(即传统的 DAO)需要调用这些实体对象。若它处于最底层,则会造成业务行为与基础设施的混合。若将实体与数据映射对象分离,既会造成对象之间的重复,又会导致不好的贫血对象。而将基础设施层放在分层架构的上端,非常巧妙地解决了这一问题。

我尤其喜欢本书引荐的由 Corkburn 提出的六边形(Hexagonal)架构。它完全突破了传统分层架构的窠臼,以独到的边界划分手法指导我们遵循关注点分离原则。该架构模式对端口(Port)与适配器(Adapter)的强调,使得我们可以在架构分析与设计时,更加关注系统之间的集成点,从而形成可视性极强的物理架构。这对于建立可伸缩的分布式架构尤有价值。我已在多个项目的架构设计中,运用了六边形架构模式,可谓收获颇丰。书中还提到了相对较新的 RESTful 架构,CQRS 架构以及事件驱动的架构模式和网格分布式计算。该书的附录还进一步探讨了聚合对象与事件源的组合设计。这些内容有助于我们树立整体的 DDD 架构观,可以说弥补了 Eric 书中对这些内容的空白。

Vaughn Vernon 是真正懂得写作的技术专家,他非常懂得如何“讨好”读者。翻开书,阅读第一章,你就会爱上它,爱上 DDD。书中给出的例子实在太棒了。看看他对 saveCustomer() 方法的版本演进,你会幡然醒悟,原来代码应该这样写。领域对象是一位谨慎的保密者,他严格地谨守着自己的秘密,只把业务外部行为暴露给你,使得你可以读懂它,却不应该干扰它的内部实现。这正是 DDD 中通用语言的价值。身为一名技术人员,我们精通 Java、C#、Scala、Ruby 等等语言,却忘了在企业开发中,真正需要展现的其实是业务通用语言。写代码首先是与人交流,而不是机器。

本书的精彩章节有很多,几乎阅读每篇都会有感悟。但我个人认为,尤其彰显本书价值的是第 8 章与第 10 章。并非其他章节不够好,但相对于实体、值对象等容易理解的概念而言,聚合总是被人所误用,又或者让人茫然不知所措。第 10 章总结了非常实用的聚合设计原则。例如,在一致性边界之内对真正的不变量进行建模的原则;设计小聚合的原则;通过唯一标识引用其他聚合的原则。在边界之外使用最终一致性的原则。

至于第 8 章介绍的 Domain Event,则是因为它不同于 Eric 的著作,将事件当做了与实体同等地位的头等公民。结合本书对事件驱动以及事件源的讲解,相信你在之后的领域建模时,会重视对领域事件的识别。若能正确地理解事件,则可以更好地掌握 CQRS 模式,并因地制宜地运用这一模式。

该书书名为 Implementing(实现) Domain-Driven Design,就说明作者的意图是要让 DDD 真正落地。怎么做到?——上实例!书中给出的虽然是虚拟案例,却非常接近真实。作者甚至按照一种演进设计的方式深入浅出地介绍了这两个完整案例。最能够帮助人理解的是,他在讲授 DDD 时,还结合案例给出了之前欠佳的反面案例,并通过识别设计的坏味道,运用 DDD 方式对其进行改进。作者甚至创造了虚拟的场景,使得我们在阅读这些内容时,就好像真正参与了设计师的讨论,甚至能听到他们的唇枪舌剑,最后是 DDD 专家的总结陈词,真好比身临其境地加入了这个虚拟团队,一起学习,一起分享,共同成长。

坦白说,我在阅读本书时方才发觉自己在 DDD 上的浅薄无知。或许是自己的悟性不够,未能很好地理解 Eric 提出的 DDD 概念。阅读此书,让我有醍醐灌顶之感。现在,对于 DDD,我已渐窥门径。若能多结合项目实践,定能登堂入室,甚至走得更远。


感谢张逸对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ )或者腾讯微博( @InfoQ )关注我们,并与我们的编辑和其他读者朋友交流。

2014-05-15 08:568390
用户头像

发布了 109 篇内容, 共 40.9 次阅读, 收获喜欢 14 次。

关注

评论

发布
暂无评论
发现更多内容

直播带货系统源码(开源系统版)——如何搭建测试呢?

开源直播系统源码

软件开发 直播源码 语音直播源码 连麦直播

两数之和 II - 输入有序数组

面试官问

LeetCode 两数之和

博云入选Gartner中国云管理工具市场指南代表厂商

BoCloud博云

云原生 Gartner 云管理平台 云管理

助力人工智能迈向新阶段,YLearn因果学习开源项目重磅发布!

九章云极DataCanvas

人工智能 开源项目 因果学习 YLearn

你玩过轻量系统软总线应用吗?

OpenHarmony开发者

OpenHarmony

XGRIDS三维重建服务,构建云上数字孪生世界

阿里云弹性计算

容器 3D渲染 弹性计算 GPU算力

【古月21讲】ROS入门系列(1)——ROS命令工具的使用及创建工作空间和功能包

秃头小苏

ROS 7月月更

用什么承受全部的数据-RDD、DataFrame还是Dataset

怀瑾握瑜的嘉与嘉

spark 7月月更

简述Serverless原理及运用

南城FE

Serverless 前端 7月月更

数据治理实战篇!选择什么样的工具让数据治理落地更简单

雨果

数据治理

Wallys/WiFi6 MiniPCIe Module 2T2R 2×2.4GHz 2x5GHz MT7915 MT7975

wallys-wifi6

IPQ4019 IPQ6010 ipq6018 QCN9074 MT7975

【愚公系列】2022年7月 Go教学课程 011-字符串类型

愚公搬代码

7月月更

java零基础入门-String

喵手

Java 7月月更

这一次带你透彻解析RocketMQ消息中间件

Java永远的神

Java 程序员 面试 RocketMQ 消息中间件

面试官:小伙子你来说下缓存穿透、缓存雪崩、缓存击穿

Java永远的神

Java redis 程序员 面试 程序人生

团队管理之git提交规范:commit记录那点事儿

南极一块修炼千年的大冰块

7月月更

首届京东科技合作伙伴大会召开,博云携手京东科技共创产业数字化新增长

BoCloud博云

容器 云原生 PaaS

uWebSockets.js 遇见 Http3

devpoint

JavaScript websocket HTTP3.0 7月月更

从预测到决策,九章云极DataCanvas推出YLearn因果学习开源项目

九章云极DataCanvas

人工智能 YLearn 开源工具包 因果推断

LeetCode-112. 路径总和(java)

bug菌

Leet Code 7月月更

不知道这4种缓存模式,你可能并不是真的懂缓存

Java永远的神

Java 缓存 程序员 面试 后端

Android 自动化测试

沃德

android 程序员 7月月更

2022最新面试八股文,共计12w字,200多页,16个Java技术栈

Java全栈架构师

Java spring 程序员 面试 程序人生

【C语言】进阶指针seven

謓泽

7月月更

YLearn因果学习开源项目「贡献者计划」精彩来袭!

九章云极DataCanvas

AI 开发者 因果学习 YLearn

什么是微软 Edge 浏览器 Tracking Prevention 的 Org Relationship Mitigation 策略

汪子熙

JavaScript html 前端开发 web开发 7月月更

好家伙!阿里人用5个案例就彻底讲清了SpringSecurity安全框架

程序员小毕

Java spring 程序员 面试 springsecurity

Python爬虫挺刑的,去VX公众某位置,平台登录加密参数扣取

梦想橡皮擦

Python 爬虫 python 爬虫 7月月更

mysql进阶(二)你真的了解索引吗?

No Silver Bullet

索引 MySQL 数据库 7月月更

语音驱动嘴型与面部动画生成的现状和趋势

行者AI

算法 人工智能’

电商订单支付时防止重复支付的原理

程序员小毕

Java 程序员 面试 程序人生 后端

阅读者(二十八):实现领域驱动设计_语言 & 开发_张逸_InfoQ精选文章