DDD 全程是 Domain-Driven Design,中文叫领域驱动设计,是一套应对复杂软件系统分析和设计的面向对象建模方法论。
以前的系统分析和设计是分开的,导致需求和成品非常容易出现偏差,两者相对独立,还会导致沟通困难,DDD 则打破了这种隔阂,提出了领域模型概念,统一了分析和设计编程,使得软件能够更灵活快速跟随需求变化。
我们可以在一个进程内部署单体应用,也可以通过远程调用来完成功能调用,这就是目前的微服务方式,更多的时候我们是两种方式的混合,比如 A 和 B 在一个部署单元内,C 单独部署,这是因为 C 非常重要,或并发量比较大,或需求变更比较频繁,这时候 C 独立部署有几个好处:
C 独立部署资源:资源更合理的倾斜,独立扩容缩容。
弹力服务:重试、熔断、降级等,已达到故障隔离。
技术栈独立:C 可以使用其他语言编写,更合适个性化团队技术栈。
团队独立:可以由不同团队负责。
架构是可以演进的,所以拆分需要考虑架构的阶段,早期更注重业务逻辑边界,后期需要考虑更多方面,比如数据量、复杂性等,但即使有这个方针,也常会见仁见智,没有人能一下子将边界定义正确,其实这里根本就没有明确的对错。
即使边界定义的不太合适,通过聚合根可以保障我们能够演进出更合适的上下文,在上下文内部通过实体和值对象来对领域概念进行建模,一组实体和值对象归属于一个聚合根。
按照 DDD 的约束要求:
第一,聚合根来保证内部实体规则的正确性和数据一致性;
第二,外部对象只能通过 id 来引用聚合根,不能引用聚合根内部的实体;
第三,聚合根之间不能共享一个数据库事务,他们之间的数据一致性需要通过最终一致性来保证。
有了聚合根,再基于这些约束,未来可以根据需要,把聚合根升级为上下文,甚至拆分成微服务,都是比较容易的。
DDD 的相关术语与基本概念
讨论完宏观概念以后,让我们来认识一下 DDD 的一些概念吧,每个概念我都为你找了一个 Spring 模式开发的映射概念,方便你理解,但要仅仅作为理解用,不要过于依赖。
另外,这里你可能需要结合后面的代码反复结合理解,才能融汇贯通到实际工作中。
领域
映射概念:切分的服务。
领域就是范围。范围的重点是边界。领域的核心思想是将问题逐级细分来减低业务和系统的复杂度,这也是 DDD 讨论的核心。
子域
映射概念:子服务。
领域可以进一步划分成子领域,即子域。这是处理高度复杂领域的设计思想,它试图分离技术实现的复杂性。这个拆分的里面在很多架构里都有,比如 C4。
核心域
映射概念:核心服务。
在领域划分过程中,会不断划分子域,子域按重要程度会被划分成三类:核心域、通用域、支撑域。
决定产品核心竞争力的子域就是核心域,没有太多个性化诉求。
桃树的例子,有根、茎、叶、花、果、种子等六个子域,不同人理解的核心域不同,比如在果园里,核心域就是果是核心域,在公园里,核心域则是花。有时为了核心域的营养供应,还会剪掉通用域和支撑域(茎、叶等)。
通用域
映射概念:中间件服务或第三方服务。
被多个子域使用的通用功能就是通用域,没有太多企业特征,比如权限认证。
支撑域
映射概念:企业公共服务。
对于功能来讲是必须存在的,但它不对产品核心竞争力产生影响,也不包含通用功能,有企业特征,不具有通用性,比如数据代码类的数字字典系统。
统一语言
映射概念:统一概念。
定义上下文的含义。它的价值是可以解决交流障碍,不管你是 RD、PM、QA 等什么角色,让每个团队使用统一的语言(概念)来交流,甚至可读性更好的代码。
通用语言包含属于和用例场景,并且能直接反应在代码中。
可以在事件风暴(开会)中来统一语言,甚至是中英文的映射、业务与代码模型的映射等。可以使用一个表格来记录。
限界上下文
映射概念:服务职责划分的边界。
定义上下文的边界。领域模型存在边界之内。对于同一个概念,不同上下文会有不同的理解,比如商品,在销售阶段叫商品,在运输阶段就叫货品。
https://zhuanlan.zhihu.com/p/91525839