领域驱动设计(DDD)概述

领域驱动设计(DDD)是一种软件开发方法论,它强调以业务领域为中心进行软件开发,以提高软件质量和业务对齐度。

DDD的特点

DDD的核心特点包括:

  1. 业务边界确定:通过定义清晰的业务领域和子域,明确软件需要解决的问题域。2. 模型与代码一致性:确保业务模型与代码实现保持一致,方便业务人员和开发人员之间的沟通。3. 统一语言:建立业务和技术人员共同使用的统一语言,减少沟通成本,提高开发效率。

战略设计与战术设计

DDD将设计分为两个层面:

  • 战略设计:从业务角度出发,建立领域模型,划分领域边界,形成统一语言的限界上下文。- 战术设计:关注模型到软件实现的转化,涉及聚合根、实体、值对象等概念的具体实现。

DDD在微服务中的应用

DDD在微服务架构中的应用主要解决以下问题:

  • 确定微服务的边界,避免服务过于碎片化或过于集中。- 通过限界上下文指导微服务的设计,确保服务的独立性和可维护性。

DDD的好处与局限

  • 好处:提高软件的可维护性,加强业务与技术的对齐,促进团队间的有效沟通。- 局限:需要较高的设计能力和业务理解,实施初期可能会增加开发成本和时间。

领域与子域

  • 领域:指一个组织或系统中的特定业务范围。- 子域:领域内部的更细分的业务领域。

核心域、通用域、支撑域

  • 核心域:对组织成功至关重要的领域。- 通用域:多个组织或系统共有的领域。- 支撑域:为其他领域提供支持的领域。

通用语言与限界上下文

  • 通用语言:业务和技术团队共同使用的统一术语和概念。- 限界上下文:明确通用语言适用的范围,保证语言的一致性。

实体与值对象

  • 实体:具有唯一标识和生命周期的对象,可以有多种属性和行为。- 值对象:描述实体属性的对象,通常不可变。

聚合与聚合根

  • 聚合:一组相关对象的集合,它们一起作为数据修改的单元。- 聚合根:聚合中的主要实体,作为外部对象与聚合交互的入口。- 设计原则:确保聚合的一致性和完整性,避免过度耦合。

如何设计聚合

  • 确定聚合边界,明确哪些对象属于同一个聚合。- 定义聚合根,作为外部与聚合交互的接口。- 遵循聚合的设计原则,保持聚合的独立性和一致性。 通过以上内容,我们可以看到DDD不仅仅是一种设计方法,更是一种思维模式,它帮助我们从业务的角度出发,构建高质量、易于维护的软件系统。

领域驱动设计(DDD)概述

边界识别在DDD中,边界的识别至关重要,主要分为两种类型:- 聚合边界:定义了数据的一致性和操作的边界。- 限界上下文边界:作为微服务的边界,一个微服务可以包含一个或多个聚合。

DDD的优势与局限### 优势- 提供了从战略到战术的完整设计方法。- 适用于高复杂度业务系统,有助于建立稳定的领域模型。- 强调团队与领域专家合作,促进知识传递。- 提升架构设计能力,适用于新项目和系统演进。

局限- 适用于业务系统,对于特定领域如人工智能等不太适用。- 并非万能,更适用于业务逻辑复杂的系统。- 存在缺陷,如依赖专家经验,实施成本高。

领域与子域领域是特定范围或问题的集合。子域是领域细分的产物,如自然科学中的研究方法。

核心域、通用域、支撑域根据重要性和功能属性,子域可分为:- 核心域:与公司核心竞争力相关。- 通用域:多个子域共用的领域,如认证、权限。- 支撑域:具有企业特性但不通用的领域。

通用语言与限界上下文### 通用语言- 确保团队内各种角色顺畅沟通。- 与领域模型和代码实现关联。

限界上下文- 确定语义所在的上下文环境。- 定义模型和通用语言的适用范围。

实体与值对象### 实体- 拥有唯一标识符,标识符保持不变。- 在战略设计阶段是领域模型的重要对象。

值对象- 通过属性值识别,没有唯一标识符。- 用于属性归类,如地址信息。

结论DDD是一种强大的设计方法,尤其适用于业务逻辑复杂的系统。然而,它也有其局限性和挑战,需要根据具体场景和需求进行选择和应用。

public User{ //实体
    public string ID; // 唯一标识
    public string Name; //单一属性的值对象
    public Address Address; // 属性集合的值对象
}
public class Address{ //值对象
    public string city;
    ...
}

值对象与聚合设计在领域驱动设计(DDD)中的应用

值对象的特性- 运行形态:值对象仅包含属性,不包含行为,属于贫血模型。它们一旦创建,便不可修改,只能通过创建新的值对象来替代。- 数据库形态:值对象在数据库中的形态是本文讨论的重点。在传统的数据库设计中,数据表之间存在关联,如人员与地址的关系。但这种设计可能导致数据表数量过多,或者丢失地址的独立性和完整性。

DDD对数据建模的影响- 领域建模:领域驱动设计(DDD)以领域建模为核心,相对弱化了数据建模的作用。在DDD中,数据库被视为数据的存储仓库,其设计不必严格遵循传统的数据库范式。- 值对象的作用:DDD引入值对象的目的是减少数据表的数量和复杂的表关联,从而将设计重心从数据建模转移到领域建模。

值对象的存储方式- 平铺属性:值对象可以作为平铺的属性存储在人员表中。- JSON对象:也可以将值对象作为JSON大对象直接存储在人员表的Address字段中。

值对象的利弊- 简化设计:值对象有助于简化数据库设计。- 查询困难:如果将值对象存储为JSON,根据值对象属性的查询将变得困难。- 概念完整性:平铺存储可能导致实体表中存在大量缺乏概念独立性和完整性的字段。

聚合与聚合根- 聚合:聚合由业务逻辑紧密关联的实体和值对象组成,是数据持久化的基本单元,每个聚合对应一个仓储。- 聚合根:聚合根是聚合内统一控制业务逻辑的特殊实体,具有属性、行为和自身的业务逻辑。它还负责管理聚合内的其他实体和值对象,并作为聚合对外的接口。

设计聚合的方法- 事件风暴:在事件风暴过程中,识别所有可能的事件和行为。- 领域对象:找出产生这些事件和行为的实体、值对象等。- 关系梳理:梳理这些领域对象之间的关系,确定聚合根。- 聚合组合:将与聚合根功能紧密相关的实体和值对象组合为聚合,边界应遵循单一职责和高内聚的原则。

注意事项- 在设计聚合时,应根据业务需求和逻辑关系来确定聚合的边界,以确保系统的灵活性和可维护性。

寻找聚合

保险行业投保业务的聚合设计

一、事件风暴与实体识别在保险行业的投保业务中,首先通过事件风暴识别出关键实体和值对象,例如:- 投保单:记录投保的详细信息。- 客户:投保人的基本信息。

二、聚合根的确定聚合根是聚合内的核心实体,它能够管理聚合内的其他实体。在投保业务中,以下实体可以作为聚合根:- 投保单:作为管理投保信息的根实体。- 客户:作为管理客户信息的根实体。

三、聚合的构建根据业务需求和聚合根,构建聚合,包括与聚合根功能紧密相关的实体和值对象。例如:- 投保单聚合:包含投保单、被保人、投保人等。- 客户聚合:包含客户信息及相关值对象。

四、对象引用与依赖关系在聚合内,明确实体、值对象与聚合根之间的依赖关系。例如:- 被保人和投保人作为值对象,在投保单聚合中保存了客户信息的冗余数据,确保投保单的独立性和一致性。

五、限界上下文的划分将业务密切相关的聚合进一步划分到一个限界上下文中,以保持业务的清晰和边界的明确。

聚合的设计原则1. 一致性边界内建模:聚合内的实体和值对象遵循统一的业务规则。2. 设计小聚合:避免聚合过大,导致管理复杂和操作冲突。3. 唯一标识引用:通过聚合根ID引用其他聚合,降低耦合度。4. 最终一致性:聚合内数据强一致性,聚合间数据最终一致性。5. 应用层服务调用:通过应用层实现跨聚合的服务调用。

参考资料- 欧创新,《DDD实战课》