本文与大家一起学习并介绍领域驱动设计 (Domain Drive Design) 简称 DDD,以及为什么我们需要领域驱动设计,它有哪些优缺点,尽量用一些通俗易懂文字来描述讲解领域驱动设计,本篇并不会从深层大论述讲解落地实现,这些大家可以在了解入门后再去深层次学习探讨或在后续进阶和高级篇了解,希望通过本文介绍,可以让大家快速了解 DDD 并有一个基础的认知,DDD 本身就是理论的集合,很难在不积累理论情况下来有效的实施 DDD,仅仅看一些代码案例后就开搞,最终出来东西也是东施效颦,莫要好高骛远。 最后期望大家在工作中能多思考,如你所负责项目如果用 DDD 如何设计、以及会面临哪些挑战。
学习了解 DDD 之前,期望大家可在温顾下以往我们所了解掌握一些知识,努力让自己所学所掌握的内容沉淀下来,推荐阅读系列。
领域驱动设计 (DDD) 提出是从系统的分析到软件建模的一套方法论。将业务概念和业务规则转换成软件系统中的概念和规则,从而降低或隐藏业务复杂性,使系统具有更好的扩展性,以应对复杂多变的现实业务问题。总结它是一套完整而系统的设计方法、是一种设计思维、一种方法论,并不是"系统架构",一种架构设计原则、思维。
善于处理高复杂业务的产品研发、可帮助我们提炼稳定的产品内核 (领域模型中称为核心域);
通过建模可提高建模高内聚、降低模型间的耦合度,提高系统的可扩展性与稳定性;
强调团队与领域专家的合作沟通,有助于建立一个沟通良好的团队组织;
统一设计思想与设计规范,有助于提高团队成员的架构设计能力和面向对象设计能力;
现有的微服务建构都是遵循领域驱动设计的架构原则;
如果你负责的软件系统并不复杂,那么,你确实不需要学习领域驱动设计!
领域驱动设计的思维是:对象 + 行为 + 服务,所有的设计围围绕着对象、行为、服务展开;
时下流行架构设计思维是:基于 MVC 分层架构进行纵向扩展,分业务模块进行产品横向扩展;
三层应用架构:数据 - 应用 (业务逻辑层)-展现,通常是以数据位为起点进行数据库分析设计。
服务层过重,数据模型失血,没东西;
面条式编程或者面向数据库编程,服务层围绕数据库作业完成业务逻辑,经常一条线撸到底;
代码一整块一整块的过重,很难扩展复用;
数据库模型只是数据库映射,没有相关的行为支撑,行为都被上一层 Service 给完成等了,因此是失血 的领域模型;
架构四层在 DDD 分层结构中将三层中业务逻辑拆解为应用层和领域层,核心业务逻辑表现下沉到领域层去实现,以业务领域模型为核心建模 (面向对象建模),更能体现对现实世界的抽象,其优点如下
没有谁能够做到领域驱动设计的一蹴而就,所谓"理论联系实际",在刚开始接触或学习设计领域驱动时,总会有一种诉求希望能给出公式般的设计准则或规范,似乎软件设计就像拼积木一般,只要遵循图示给出的拼搭过程,不经思考就能拼出期待的模型,这似乎不切实际的幻想,要掌握领域驱动设计,首先要了解掌握一些概念以知识理论,在此基础之上思考这些概念背后蕴含的原理,设计原则,思考限界上下文 (Bounded Context) 边界的划分,实际还是围绕"高内聚、低耦合"原则的体现,只是我们考虑什么内容才是高内聚,如何抽象才能做到低耦合,在分层架构中,各层之间该如何协作?出现了依赖如何解耦,仍然需要从重用与变化的角度去思考设计决策。
领域驱动设计强调以"领域"为核心驱动力,通过模型驱动设计来保障领域模型与程序设计的一致,领域模型不应该包含任何技术实现因素,模型中的对象真实的表达了领域概念,却不受技术实现的约束,领域模型本身和技术无关,领域驱动从设计上划分为战略设计和战术设计。
强调业务战略上的重点,如何按重要性分配工作,以及如何进行最佳,遵循量大原则:
必须指导设计决策,以便减少各个部分之间的相互依赖,在使用设计意图更为清晰的同时而又不失去关键的互操作性和系统性;
必须把模型的重点放在捕获系统概念核心,也就是系统的"远景"上。
整个业务领域的一部分,关注与宏观业务,通过对大领域进行划小在业务间划分出概念上分界线,便于在系统筹划阶段决策如何分配资源 (人、钱)。
关注点在于系统物理划分,根据你对领域的分割结果及公司或部门的组织结构决策如何划分子系统,比如分出几个,系统间如何交互,该层面往往暂不会涉及够多技术细节。
依赖于领域模型和通用预言,通过技术模式将领域模型和通用预言中的概念映射到代码实现中。随着模型的进化,代码实现也会进行重构,以更好的体现模型概念。
代表领域中的概念,如实体、值对象、领域服务、模块等;
用于管理对象的生命周期。如聚合、工厂、仓库等;
用于集成或跟踪,如领域事件等;
领域/子域:什么领域?从广义上将,领域即是一个组织所做的事情以及所包含的一切,领域可大可小有界限,不是无限大,如电商领域,交易领域,购物领域等,比如我们常听客户说 “我们有这样几块业务” 一般来说这里所谓"几块儿"就是指子域 。
实体 (entity):这个词被我们广泛使用,甚至过分使用,实体是一个重要的概念,一个典型实体应具备 3 个要素 (身份标识、属性、领域行为),必须有唯一的身份标识,没有身份标识的领域对象就不是实体。如:User 对象就是一个实体。
属性:实体的属性用来说明主体的静态特征,并持有数据与状态。
@Data
public class Product{
private String sku;
private String name;
private Price price;
}
@Data
public class Product{
private String sku;
private String name;
private Price price;
//变更状态的领域行为
public void changePriceTo(Price newPrice){
//设计产品新加个
.......
}
}
举个小例子:订单项和订单的关系:多对一,一个订单里有多条订单项,一个订单项,只会出现在一个订单里,组合关系,部分不能脱离主体单独存在
public class Order {
int id;
User user;
}
public class OrderItem {
private int id;
private Product product;
private int num;
private Order order;
}
6) 聚合根:聚合中需要指定一个实体作为聚合根来作为整个聚合的对外触电,也就是说外部只能通过聚合根实现对内部对象的访问,这样的限制可以对内部对象实现最大化的保护。
几乎所有项目的发展都有这样一个规律:初期需求简单,中后期业务激增系统复杂度升级,导致最初的设计理念需要大刀阔斧的改革,所以,系统越复杂、代码规模越大,DDD 的优势就越明显。
微服务划分的一个重要理论基础就是领域驱动设计,但由于 DDD 门槛高、概念多,体系庞大又抽象,再加上实践经验和案例缺少,很多开发人员对 DDD 存在不少疑惑,或只停留在平时依靠检索或身边同事谈及耳闻了解 DDD,通过本篇初步认识了领域驱动设计、前期我们先暂短介绍这里,后续会将从代码层面入手分享 DDD 实现落地。
作者:京东物流 边雷
来源:京东云开发者社区 自猿其说 Tech 转载请注明来源