DDD领域驱动设计内容分享(三十七):领域驱动设计(DDD)与微服务的双剑合璧

目录

一、领域驱动设计概述

二、领域驱动设计的核心要点

1、领域模型

2、通用语言

3、限界上下文

4、聚合

5、仓储

6、应用服务

7、领域服务

8、领域事件

三、DDD VS 微服务

1 微服务划分与限界上下文对齐

2 聚合作为微服务的数据边界

3 仓储与微服务的数据访问层对应

4 应用服务与微服务的 API 层对应

5 领域服务与微服务的业务逻辑层对应

6 领域事件与微服务的业务逻辑层对应

7 共享内核模式与通用库

8 策略模式与外部化配置

9 持续集成与持续交付

10 分布式跟踪与监控

四、总结与展望


一、领域驱动设计概述

领域驱动设计,Domain-Driven Design,简称 DDD,是一种软件设计方法论,它强调以业务领域为核心来构建软件架构,DDD 由 Eric Evans 在其 2003 年的同名书籍中首次提出并进行了系统性地阐述,自此在软件研发领域中产生了广泛的影响。

DDD 的出现是为了解决复杂业务领域的软件建模问题,随着企业应用的复杂性和规模的不断增长,传统的以数据为中心或者以技术为中心的设计方法往往难以应对,DDD 通过引入领域模型、通用语言、限界上下文等概念,帮助开发团队更好地理解和应对业务领域的复杂性。

DDD 强调业务领域的核心地位,使得开发出的系统更加贴近业务需求,易于理解和维护,同时,DDD 提供了一套完整的建模工具和方法论,有助于开发团队形成统一的语言和思维模式,提高沟通效率,此外,DDD 的模块化设计思想也有助于提高系统的可扩展性和可重用性。但是,DDD 的实施难度比较大,需要开发团队具备一定的业务领域知识和经验,同时,DDD 的建模过程相对复杂,需要投入较多的时间和经历,此外,对于某些简单或者变化较少的业务领域,采用 DDD 可能会显得过于繁重。

随着软件行业的不断发展和演进,DDD 具有广阔的未来发展趋势:

  • 随着微服务和云原生架构的普及越来越多的企业开始将系统拆分为小型独立的服务单元,这和 DDD 的限界上下文和模块化设计思想不谋而合,因此 DDD 在微服务架构中会发挥更大的作用

  • 随着人工智能和机器学习技术的不断发展,领域模型可以更加智能化地描述业务规则和逻辑从而进一步提高软件系统的智能化水平

  • 随着开发团队对业务领域领结和建模能力的不断提升,DDD 有望在更多类型的项目中得到应用并取得更好的效果

那 DDD 和其他设计方法相比,他们之间有什么关系呢?

首先我们来看面向对象设计,Object-Oriented Design,简称 OOD,是一种流行的设计方法,它强调将现实世界中的事物抽象为对象,并通过类和对象之间的关系来描述系统结构,与 OOD 相比,DDD 更加注重业务领域的建模和理解,而不仅仅是技术实现。DDD 中的领域对象通常比 OOD 中的对象更加贴近业务概念,并且 DDD 强调使用通用语言来促进开发团队和业务专家之间的沟通。

再看面向服务设计,Service-Oriented Design,简称 SOD,也是一种常见的流行的设计方法,它强调将系统划分为一系列独立的服务单元,虽然 SOD 和 DDD 都关注系统的模块化划分和服务之间的接口定义,但是 DDD 更加关注业务领域的建模和领域服务的划分,而 SOD 更加注重服务的复用和组合。

二、领域驱动设计的核心要点

1、领域模型

DDD 强调首先要理解业务领域,然后构建一个能够准确反应业务领域的模型,这个模型不仅包括业务实体和他们之间的关系,还包括业务过程中的规则和逻辑。而这个模型就是领域模型,它是关于某个特定业务领域的软件模型,用于对业务领域进行建模,以更好地理解业务和问题域。

领域模型通常通过对象模型来实现,这些对象同时包含了数据和行为,并且表达了准确的业务含义,它不仅关注数据的结构,还关注数据在业务领域中的行为和业务规则。

在 DDD 中,领域会被进一步划分为子领域,每个子领域对应一个更小的问题或者业务范围,这种划分有助于降低业务理解和系统实现的复杂度,领域模型就是对这些子领域进行建模的结果,它描述了子领域内的实体、值对象、聚合根、领域服务、领域事件等概念及其之间的关系。

  • 实体:具有唯一标识符的领域对象,在业务领域中具有持续的存在性

  • 值对象:描述实体的属性或者状态的对象,没有唯一标识符,且不可变

  • 聚合根:是一个聚合的跟实体,负责协调聚合内的其他实体和值对象的行为

  • 领域服务:标识在领域中执行的操作或者行为的服务,通常是无状态的

  • 领域事件:标识在领域中发生的事件的对象,用于出发其他领域的行为。

在 DDD 中,领域模型的设计是一个迭代的过程,需要与开发团队和业务专家进行密切的合作和沟通,通过不断地反馈和调整,可以逐步完善领域模型,使其更好地满足业务需求。

2、通用语言

通用语言是指在整个软件生命周期内,由领域专家、开发人员和其他角色共同使用的一种统一的、明确的语言,这种语言以业务领域为核心,贯穿于 DDD 的战略设计和战术设计的各个层面。

通用语言的重要性:

  • 消除沟通障碍:在软件开发过程中,领域专家和开发人员往往因为背景知识、术语理解等方面的差异而产生沟通障碍,通用语言通过明确术语和概念的定义,使得双方能够使用同一种语言来描述和理解业务领域,从而消除沟通障碍

  • 提高开发效率:通用语言能够帮助开发人员更快地理解业务领域,减少在需求分析、设计、开发等阶段中的反复沟通和确认,有助于缩短开发周期,提高开发效率

  • 保证代码质量:通用语言能够确保开发人员编写的代码与业务需求保持一致,通过通用语言中的术语和概念来命名代码中的类、方法、变量等,可以让代码更加易于理解和维护

在 DDD 中,通用语言的建立需要经历以下步骤:

  • 识别领域对象:首先需要识别出业务领域中的关键对象,如实体、值对象,这些对象将构成通用语言中的名词部分,这一部的难度和能力要求都很高

  • 定义术语和概念:针对识别出的领域对象,需要明确定义其术语和概念,包括对象的名称、属性、行为以及与其他对象的关系等,这些构成通用语言中的动词和形容词部分

  • 建立限界上下文:为了避免术语和概念的歧义,需要建立限界上下文来明确通用语言的适用范围

  • 持续迭代和完善:通用语言的建立也是一个持续迭代和完善的过程,随着业务的发展和变化,需要不断地对通用语言进行调整和优化,以确保其始终与业务需求保持一致

3、限界上下文

限界上下文是指在一个特定的业务领域内,通用语言所描述的对象、术语和概念具有明确的含义和边界,这个边界定义了模型的适用范围,使得团队所有成员能够明确地指导什么应该在模型中实现,什么不应该在模型中实现。

限界上下文的重要性:

  • 明确业务边界:通过定义限界上下文,可以明确划分出不同业务领域的边界,有助于避免不同领域之间的概念混淆和术语歧义,使得每个领域都能保持其独立性和一致性,对应到研发中,如果应用架构设计合理的化,可以简单地把一个应用等同于一个限界上下文

  • 促进团队协作:限界上下文为开发团队提供了一个明确的工作边界,团队成员可以清楚地了解自己所负责的领域范围,从而更好地进行任务分配和协作,有助于降低团队之间的沟通成本,提高开发效率

  • 保证系统一致性:限界上下文有助于维护系统的业务一致性,在每个限界上下文中,领域模型、通用语言和业务规则都得到了明确的定义和约束,这可以确保系统在各个层面上能够保持一致,降低系统的业务复杂度

  • 支持技术实现:限界上下文为技术实现也提供了指导,在系统设计和开发过程中,可以根据限界上下文的划分来确定系统的模块划分、接口定义等,有助于保证系统的技术一致性,降低系统的技术复杂度

在 DDD 中,识别和定义限界上下文需要经历以下步骤:

  • 理解业务领域:首先需要深入理解业务领域,识别出其中的关键业务对象、业务流程和业务规划,有助于为后续的限界上下文划分提供基础

  • 划分业务领域:根据业务相关性、耦合强弱程度等因素,将业务领域划分为多个子领域,每个子领域对应一个相对独立的业务范围,具有一定的业务内聚性

  • 定义限界上下文:针对每个子领域,定义其对应的限界上下文,明确每个限界上下文中的对象、术语和概念的含义和边界,以及与其他限界上下文之间的关系和交互方式等

  • 持续优化和调整:随着业务的发展和变化,需要不断地对限界上下文进行优化和调整,可能设计到重新定义限界上下文的边界、调整对象之间的关系以及引入新的通用语言

4、聚合

聚合是指将一组具有业务相关性的领域对象组合在一起,形成一个整体的概念。这个整体具有明确的业务含义和边界,并且可以通过聚合根来进行访问和操作。

聚合的重要性:

  • 业务一致性:聚合内的对象共同保证业务规则的一致性,当对聚合中的某个对象进行操作时,聚合根会根据业务规则协调内部对象的状态变化,以保持数据的一致性

  • 封装复杂性:通过将具有业务相关性的对象组合在一起,聚合可以封装内部的复杂性,外部对象只需要通过聚合根与聚合进行交互,而不需要了解聚合内部的详细实现,有助于降低系统的复杂性和提高可维护性

  • 明确责任边界:聚合具有明确的责任边界,每个聚合都有自己的业务职责和范围,负责处理与之相关的业务逻辑,有助于避免不同聚合之间的职责交叉和混乱

在 DDD 中,设计和实现聚合需要遵循以下原则:

  • 选择合适的聚合根:每个聚合都需要一个聚合根,它负责协调和管理聚合内部的对象。聚合根具有全局唯一的标识,并且外部对象只能通过聚合根来访问和操作聚合

  • 保持聚合的完整性:聚合是一个整体的概念,需要保持其完整性。在对聚合进行操作时,应该遵循业务规则,确保聚合内部对象的状态变化是一致的

  • 设计小聚合:为了降低系统的复杂性和提高可维护性,应该尽量设计小的聚合。每个聚合只关注一个核心业务概念,并且只包含与之紧密相关的对象

  • 避免跨聚合引用:为了保持聚合的独立性和完整性,应该避免跨聚合引用。不同聚合之间的对象不应该直接相互引用或调用,而应该通过领域事件或应用服务来进行间接的交互

5、仓储

仓储是用于封装数据访问逻辑的接口,主要负责领域模型的持久化和检索。

仓储类似于仓库管理员的角色,但它管理的不再是具体的货物,而是领域模型中的聚合,在层次结构上,位于领域模型和数据模型之间,为两者提供一个边界,并隔离它们,使开发人员可以专注与领域模式,不需要过多考虑如何进行持久化。

仓储和数据访问层区别在于仓储限定了只能通过聚合根来持久化和检索领域对象,确保了所有的改动和不变性都由聚合来处理。通过隐藏聚合持久化和检索的底层技术细节,实现领域层的持久化无关性,这就意味着领域层不需要知道如何具体地持久化领域对象。

6、应用服务

应用服务在 DDD 中负责协调领域对象来执行特定的应用程序任务。它位于应用层,作为展现层和领域层之间的桥梁,用来表达用例和用户故事的主要手段,并通过应用服务接口来暴露系统的全部功能。

应用服务在整个系统中主要负责编排和转发,它将要实现的功能委托给一个或多个领域对象来实现,而应用服务本身只负责处理业务用例的执行顺序以及结果的拼装,这种方式隐藏了领域层的复杂性机器内部实现机制。

应用层相对比较薄,除了定义应用服务之外,在该层可以进行安全认证、权限校验、持久化事务控制等操作。此外,应用层还可以用于发送基于事件架构模式的消息给其他系统,或者用于创建其他消息形式发送给客户等,比如 Email 等。

7、领域服务

领域服务属于领域层,用于执行特定于某个领域的任务。它表示一个无状态的操作,用于实现特定于某个领域的任务,这些任务通常不适合放在实体或者值对象上,因为他们可能涉及多个领域对象的协作和转换。

领域服务的适用场景:

  • 执行一个显著的业务操作流程,比如计算订单金额,需要合并各种优惠等规则,这些操作不是实体或者值对象的职责,是需要独立出来作为一个服务来处理的

  • 对领域对象进行转换,将一个领域对象转换为另一种类型或者格式,此时需要领域服务来完成

  • 以多个领域对象作为输入参数进行计算,并产生一个值对象作为结果,此时需要领域服务来协调不同领域对象之间的交互和数据流转

领域服务的特点:

  • 领域服务通常是无状态的,这就是意味着它不保存任何与特定操作相关的状态信息,每个服务调用都是独立的,不依赖于先前的调用

  • 领域服务应该与通用语言保持一致,他们的命名和操作应该反应业务领域的术语和概念

  • 领域服务可以处理业务规则的验证、协调不同对象的操作和数据一致性等。它可以作为跨领域操作的协调者,负责处理不同对象之间的交互和数据流转

8、领域事件

领域事件是领域模型中的一部分,用于表示在领域中发生的有意义的事情,表示了领域状态的变化或者业务操作的执行,当某个重要事件在业务领域内发生时,领域事件会被发布,以便其他部分的应用程序可以知道并做出相应的反应。

领域事件用于实现业务解耦和形成完整的业务闭环,通过将领域中所发生的活动建模成一系列的离散事件,可以实现不同部分的应用程序之间的松耦合,一个领域事件的触发可以进一步推动业务流程的进行,形成完整的业务闭环。

领域时间还可以用于维护领域模型的完整性和一致性,当领域中的状态发生变化时,通过发布领域事件,可以确保相关部分的应用程序得到通知,并做出相应的调整,以保持数据的一致性。

那究竟什么样的场景要被定义成领域事件呢?

  • 可以通过捕捉业务、需求人员或者领域专家口中的关键词来识别领域事件,比如,当 XXX 发生时,如果 XXX 就 XXX,这些关键词可能意味着一个领域事件的触发条件或者后续动作

  • 领域事件必须是对业务有价值的,并且有助于形成完整的业务闭环,它们可以是业务流程中的一个步骤,比如提交订单等,也可以是定时发生的事件,比如每日定时对账完成,还可以是一个事件发生后引发的后续动作,比如用户连续输错密码后锁定账户

领域事件的具体实现方式:

在实现领域事件时,需要考虑事件的构建、发布和订阅机制,事件的构建需要明确事件的触发条件、事件所携带的数据以及事件的类型等信息。事件的发布需要将事件通知给感兴趣的部分应用程序,可以通过事件总线或消息队列等方式进行,事件的订阅需要定义哪些部分的应用程序对哪些类型的事件感兴趣,并在事件发生时进行相应的处理。

三、DDD VS 微服务

简单讲,微服务架构是一种将单一应用程序划分为一组小的服务的方法,每个服务运行在其独立的进程中,并通过轻量级通信机制进行通信。微服务的实践与领域驱动设计(DDD)的理念有许多共同之处,我们来看看领域驱动设计(DDD)中的核心要点如何应用在微服务架构实践中。

1 微服务划分与限界上下文对齐

在微服务架构中,服务的划分是一个关键问题,DDD 中的限界上下文为微服务的划分提供了天然的指导,每个限界上下文可以对应一个微服务,这样可以确保每个微服务都具有明确的业务边界和职责。当然微服务的拆分相对比较复杂,这个后面会有专门的一篇文章来讲解如何进行微服务的拆分。

2 聚合作为微服务的数据边界

在 DDD 中,聚合是保证数据一致性的关键单元,在微服务架构中,可以将聚合作为微服务的数据边界,这意味着一个微服务应该负责管理和维护其内部的聚合数据,而不是直接访问其他微服务的数据库。

3 仓储与微服务的数据访问层对应

DDD 中的仓储模式可以为微服务提供数据访问层的抽象,每个微服务可以定义自己的仓储接口来封装数据访问逻辑,这样实现底层数据存储的解耦和灵活替换。

4 应用服务与微服务的 API 层对应

DDD 中,应用服务负责协调领域对象来执行应用程序的任务,在微服务架构中,可以将应用服务与微服务的 API 层对应起来,就意味着微服务的 API 层应该反应其业务领域的能力和操作,而不是暴露底层的实现细节。

5 领域服务与微服务的业务逻辑层对应

当某些业务逻辑不适合放在实体或者值对象上的时候,可以将其放在 DDD 的领域服务中去,在微服务架构中,这些领域服务可以成为微服务的业务逻辑层的一部分,提供与业务相关的操作和服务。

6 领域事件与微服务的业务逻辑层对应

DDD 中的领域事件可以用于实现微服务间的解耦通信,当某个微服务中的重要事件发生时,它可以发布一个领域事件来通知其他感兴趣的微服务,这样可以实现微服务间的松耦合和异步通信。

7 共享内核模式与通用库

在某些情况下,不同的限界上下文之间可能需要共享一些通用的概念或者逻辑,在 DDD 中,可以通过共享内核模式来实现,而在微服务架构中,这些共享的概念或者逻辑可以被提取出来形成通用的库或者服务供多个微服务使用,但是需要注意的是过渡共享可能会导致微服务之间的耦合度增加,需要谨慎使用这种模式。

8 策略模式与外部化配置

在 DDD 中策略模式常用于处理业务规则的变化,通过将策略封装成可互换的组件来提高系统的灵活性,在微服务架构中这种策略模式可以与外部化配置相结合使得微服务的行为可以通过配置文件或者环境变了进行动态调整而无需修改代码,这有助于实现微服务的配置化管理和快速相应业务需求的变化。

9 持续集成与持续交付

DDD 和微服务都强调快速相应业务需求的重要性,因此采用 CI/CD 实践可以加快从代码提交到生产部署的速度,同时确保每次变更都经过自动化测试验证,从而提高软件的质量以及可靠性。在实施 CI/CD 时需要注意将业务领域的知识融入自动化测试中以确保测试的有效性和覆盖率。

10 分布式跟踪与监控

在微服务架构中由于服务间存在大量的跨进程通信因此需要对分布式系统进行跟踪和监控以确保系统的可观察性和可维护性,可以利用现代化的 APM(应用性能管理)工具来实现对微服务架构的全方位监控包括性能指标、错误日志、调用链路等信息,从而为故障排查和优化提供有力支持。

四、总结与展望

通过将 DDD 的核心理念应用于微服务架构的实践中我们可以构建出更加高效、可维护的软件系统。DDD 提供了强大的建模工具和方法论帮助开发团队深入理解业务领域并构建出高质量的领域模型,而微服务架构则为这些模型提供了灵活的运行环境和扩展机制,两者相辅相成共同推动着软件开发的进步与发展。

在未来,随着云计算、容器化等技术的普及和发展,我们可以期待看到更多创新的实践将 DDD 与微服务更紧密地结合起来为构建更加复杂、更加智能的软件系统提供强大的支持。

  • 18
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
领域模型是软件开发中用于描述业务领域的概念和关系的一种建模方式。它主要用于帮助开发人员理解业务需求,并将其转化为可执行的软件系统。 在领域模型设计中,DDD(Domain-Driven Design,领域驱动设计)是一种常用的方法论。DDD强调将业务领域作为软件开发的核心,通过深入理解业务需求,将业务逻辑和领域模型进行有效的建模和设计。 在DDD中,领域模型是对业务领域中的实体、值对象、聚合根、领域服务等概念进行建模和描述的一种方式。它通过定义实体之间的关系、属性和行为,以及业务规则和约束,来描述业务领域的核心概念和逻辑。 领域模型设计的过程通常包括以下几个步骤: 1. 领域分析:深入理解业务需求,识别出业务领域中的核心概念和关系。 2. 实体建模:将业务领域中的实体抽象成具有属性和行为的对象,并定义它们之间的关系。 3. 聚合根设计:将相关联的实体组织成聚合根,通过聚合根来管理和维护实体之间的一致性和完整性。 4. 值对象定义:将不可变的、没有唯一标识的对象抽象成值对象,用于描述业务领域中的属性和属性集合。 5. 领域服务划分:将业务领域中的复杂业务逻辑抽象成领域服务,通过服务来实现业务操作和交互。 6. 领域事件设计:定义领域中的事件,用于表示业务领域中的状态变化和重要的业务行为。 通过合理的领域模型设计,可以提高软件系统的可维护性、可扩展性和可理解性,使开发人员更加专注于业务逻辑的实现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

之乎者也·

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值