你好,今天简单写写DDD领域驱动设计。
字少总结版
- 什么是DDD:DDD是将业务领域概念和规则映射到软件设计的方法,能打通产品、设计、编码人员的信息壁垒。
- DDD、ER和UML三者关系:三者在软件开发中相互关联但侧重点、范围和目的不同,DDD可结合UML,ER作用可弱化。
- DDD的核心概念有哪些:包括事件风暴、领域建模、聚合、值对象、泛化建模、限界上下文和CQRS。
- DDD有必要落地吗:取决于项目需求,落地DDD可更好理解业务、提高系统可维护性和扩展性,但需考虑成本和项目情况。
- 低配版的DDD落地:包括领域分析、简单领域建模和基础编码实现,可省略一些复杂内容,后续应逐步完善。
- 借鉴意义:即使不使用DDD完整方法论,也可借鉴其重视业务理解、统一语言、关注领域模型等理念,提高软件质量。
什么是DDD
DDD(领域驱动设计)是一种通过将业务领域的概念和规则映射到软件设计中的方法。
DDD在业务讨论、编程和设计之间建立了紧密的联系,使得业务需求能够准确地转化为软件设计和实现,从而提高软件的质量和业务价值。
也就是一套设计方案的输出,打通了产品、设计、编码三方人员的信息壁垒。
在业务讨论中,DDD有助于业务人员和开发人员使用统一的语言来描述业务流程、规则和概念,从而减少沟通障碍,确保双方对业务的理解一致。通过事件风暴等技术,能够识别出业务中的领域事件、命令和领域名词,为业务讨论提供清晰的框架和基础。
在编程和设计方面,DDD的作用主要体现在以下几个方面:
- 领域建模:DDD使用领域模型来表达业务领域的结构和行为,领域模型是对业务领域的抽象和概括,能够准确反映业务的本质。
- 代码结构:DDD将业务逻辑封装在领域层中,使得代码结构更加清晰,易于维护和扩展。同时,通过合理划分聚合、实体和值对象等,能够提高代码的可读性和可理解性。
- 系统架构:DDD强调限界上下文的概念,将系统划分为多个相对独立的子系统,每个子系统都有自己的领域模型和业务逻辑。这种架构方式有助于提高系统的可扩展性和灵活性。
- 设计原则:DDD遵循一些设计原则,如模型驱动设计、统一语言等,这些原则能够指导开发人员在编程和设计过程中做出正确的决策,确保系统的设计符合业务需求。
DDD(领域驱动设计)、ER(实体关系模型)和UML(统一建模语言)三者关系
DDD(领域驱动设计)、ER(实体关系模型)和UML(统一建模语言)在软件开发中都起着重要的作用。
DDD、ER和UML在软件开发中相互关联,但各自具有不同的侧重点、范围和目的。在实际应用中,它们可以结合使用,以构建高质量的软件系统。
有了DDD之后需要UML来描述领域模型,ER的作用就可以弱化了。
- UML是一种用于可视化、详述、构造和文档化软件系统的标准建模语言。在DDD中,可以使用UML来绘制领域模型图,以表达领域对象、它们之间的关系以及业务规则。
- ER模型主要用于数据库设计,描述实体、属性以及实体之间的关系。在DDD中,领域模型中的实体和关系与ER模型有一定的关联,因为领域模型中的信息最终可能需要存储在数据库中。
侧重点不同:
- DDD侧重于从业务领域的角度出发,通过深入理解业务领域的概念、规则和流程,来设计软件系统的架构和模型。它强调领域模型的重要性,以及业务逻辑与技术实现的紧密结合。
- ER主要关注数据库层面的设计,侧重于描述数据的存储结构和关系,以确保数据的一致性和完整性。
- UML是一种通用的建模语言,可用于多种软件建模场景,包括需求分析、设计、实现等阶段,它提供了丰富的图形和符号来表达各种软件元素和它们之间的关系。
范围不同:
- DDD涵盖了从业务分析到软件设计和实现的整个过程,包括领域模型的建立、聚合的设计、限界上下文的划分等。
- ER主要集中在数据库设计阶段,关注数据的结构和关系。
- UML的应用范围更广泛,可以用于描述软件系统的各个方面,不仅仅局限于领域模型或数据库设计。
目的不同:
- DDD的目的是通过建立与业务领域紧密契合的模型,来提高软件的质量、可维护性和可扩展性,更好地满足业务需求的变化。
- ER的目的是为了设计合理的数据库结构,以支持数据的存储和管理。
- UML的目的是提供一种标准化的方式来表达软件系统的设计,促进团队之间的沟通和理解。
DDD的核心概念有哪些
- 事件风暴:从识别领域事件开始,通过参与人员各自写出事件并共同讨论,形成统一语言。事件风暴有助于理清业务流程,其结果可通过表格形式保存,同时还包括识别命令和领域名词等内容。
- 领域建模:用领域模型图表达,通常使用UML。DDD的领域模型兼顾业务和技术视角,强调模型驱动设计和统一语言的核心模式,确保领域模型与业务需求、系统实现保持一致。
- 聚合:具有整体部分关系且需维护不变规则的一组领域对象称为聚合,聚合根有全局唯一标识。聚合的作用包括维护不变规则、分析业务规则和确定事务范围等。
- 值对象:DDD把领域对象分为实体和值对象,值对象没有单独标识且不可变,可分为原子值对象和复合值对象。值对象的优点包括内存和数据库布局灵活、不变性带来更高程序质量等,实体和值对象的本质区别在于同一性和可变性。
- 泛化建模:泛化是一种强大的抽象机制,能够同时表现出不同对象间的共性和个性。可以通过归纳法或演绎法识别泛化,在数据库设计和代码实现中需要根据具体情况选择合适的策略。
- 限界上下文:通过维护概念一致性实现分而治之,强调元素在上下文中的界限。在设计微服务时可根据限界上下文进行考虑,并注意上下文间的集成和防腐层模式。
- CQRS:将增删改功能称为Command,查询称为Query,命令要走领域模型,查询不走领域模型,直接用SQL和DTO。根据需求还可以考虑应用服务分离和数据库实例分离等策略。
DDD形成的交付物
在软件设计、编码过程,可能形成的文档就是这些。
事件风暴:
- 表格形式的事件风暴结果,包括业务流程、命令、领域事件、执行者、查询数据、领域对象等信息。
- 表格形式业务规则。
- 表格形式的统一语言,业务模型名称中英文、缩写等。
领域建模:
- 用UML绘制的领域模型图。
限界上下文:
- 微服务设计文档,根据限界上下文设计微服务的架构和集成方式。
CQRS:
- 系统架构设计文档,说明CQRS的实现方式,包括命令和查询的处理流程以及数据存储的分离策略。
其他的还可能包括相关的源码、测试用例等交付物,具体取决于项目的需求和实施情况。
交付物例子如下:
首先是事件风暴。
业务流程 | 命令 | 领域事件 | 执行者 | 查询数据 | 领域对象 |
---|---|---|---|---|---|
订单管理 | 创建订单 | 订单已创建 | 用户 | 订单详情 | 订单 |
订单管理 | 修改订单 | 订单已修改 | 用户 | 订单详情 | 订单 |
订单管理 | 取消订单 | 订单已取消 | 用户 | 订单详情 | 订单 |
再者业务规则。
规则编号 | 模块 | 规则描述 | 举例 | 影响的主要功能 |
---|---|---|---|---|
R001 | 订单管理 | 一个订单的总金额不能超过用户的信用额度 | 用户甲的信用额度为 1000 元,订单 A 的总金额为 800 元,可以通过;订单 B 的总金额为 1200 元,不能通过 | 创建订单 |
R002 | 订单管理 | 订单必须包含有效的商品信息 | 订单 C 中包含了已下架的商品,不能通过 | 创建订单 |
R003 | 订单管理 | 订单状态只能在规定的流程中进行转换 | 订单 D 从待支付状态直接转换为已完成状态,不符合流程,不能通过 | 订单状态变更 |
R004 | 订单管理 | 订单的配送地址必须在服务范围内 | 订单 E 的配送地址超出了服务范围,不能通过 | 创建订单 |
R005 | 订单管理 | 订单的支付金额必须与订单总金额一致 | 订单 F 的支付金额为 90 元,订单总金额为 100 元,不能通过 | 支付订单 |
统一语言。
中文名称 | 英文名称 | 缩写 |
---|---|---|
订单 | Order | OD |
订单总金额 | Total Order Amount | TOA |
用户信用额度 | User Credit Limit | UCL |
商品信息 | Product Information | PI |
订单状态 | Order Status | OS |
配送地址 | Delivery Address | DA |
服务范围 | Service Area | SA |
支付金额 | Payment Amount | PA |
DDD有必要落地吗
DDD是否有必要落地取决于具体的项目需求和情况。
DDD的落地可以带来一些好处,例如:
- 更好地理解业务领域:通过事件风暴和领域建模等方法,能够深入理解业务领域的概念、规则和流程,从而设计出更符合业务需求的系统。
- 提高系统的可维护性和可扩展性:DDD强调领域模型的核心地位,将业务逻辑封装在领域层中,使得系统的结构更加清晰,易于维护和扩展。
- 促进团队协作:统一语言的使用和明确的领域划分有助于团队成员之间的沟通和协作,减少误解和冲突。
- 更好地应对业务变化:DDD的设计理念使得系统能够更好地适应业务的变化,因为领域模型能够更准确地反映业务的本质,从而更容易进行调整和扩展。
然而,DDD的落地也需要一定的成本和投入,包括培训团队成员、改变开发流程等。此外,对于一些简单的项目,可能不需要过于复杂的DDD架构。
因此,在决定是否落地DDD时,需要综合考虑项目的规模、复杂性、业务需求的稳定性以及团队的技术能力和经验等因素。如果项目具有较高的复杂性和业务需求的频繁变化,那么DDD的落地可能会带来显著的好处;如果项目相对简单,可能可以采用更轻量级的方法来满足需求。
总的来说,DDD是一种有价值的设计方法,但需要根据具体情况来判断是否有必要落地。
低配版的DDD落地
低配版的DDD落地可能没那么复杂,包里面需要有个domain
就行。
具体的过程是这样的。
领域分析:
- 识别关键的领域事件和命令,了解业务的基本流程和操作。
- 提取重要的领域名词,对业务概念有初步的理解。
简单领域建模:
- 绘制基本的领域模型图,展示主要的领域对象及其关系。
- 确定核心的实体和聚合,明确它们的职责和边界。
基础编码实现:
- 按照领域模型进行初步的代码结构设计,将相关的逻辑组织到对应的模块中。
- 实现基本的领域逻辑,确保业务的关键功能能够正常运行。
为了贯彻统一语言,一开始就建立词汇表,业务规则表可以暂缓,但最好尽快建立。
在低配版本的DDD落地中,可以省略一些相对复杂或次要的内容,例如:
- 深入的泛化建模:如果业务中泛化关系不太复杂,可以暂时简化或省略对泛化的详细建模。
- 全面的限界上下文划分:可以先不进行过于精细的限界上下文划分,而是将重点放在核心业务领域的建模上。
- 复杂的CQRS实现:可以暂时采用较为简单的查询方式,不进行应用服务分离和数据库实例分离等复杂的策略。
- 完善的分析模式应用:对于一些较为复杂的分析模式,可以在后续逐步引入和应用。
需要注意的是,低配版本的DDD落地是为了在资源有限或项目初期快速验证概念的情况下进行的简化,但随着项目的发展,应逐步完善和扩展DDD的应用,以充分发挥其优势。
借鉴意义
DDD落地是有一定成本的,这是DDD的概念和工作范式定义的。但它对于提高软件质量、可维护性和可扩展性具有重要的意义。
即使项目不使用DDD的完整方法论,仍然可以从DDD中借鉴一些有益的理念和方法。
- 重视业务理解:像DDD一样深入理解业务领域,确保软件设计与业务需求紧密契合,避免单纯从技术角度出发进行设计。
- 统一语言的思想:在项目中,尽量促进业务人员和开发人员之间使用统一的语言进行沟通,减少误解,提高沟通效率。
- 关注领域模型:虽然不一定要构建完整的DDD领域模型,但可以借鉴其对业务领域进行抽象和建模的思路,使软件设计更具逻辑性和结构性。
- 明确职责划分:学习DDD中聚合的概念,明确各个模块或组件的职责和边界,降低代码的耦合度,提高代码的可维护性。
- 重视规则和约束:注意识别业务中的不变规则和约束,并在软件设计编码中加以体现和维护,确保软件的正确性和稳定性。
- 提高代码的表意性:借鉴DDD的表意接口模式,使代码更具有表达力,能够清晰地反映其意图和功能。
- 考虑灵活性和可扩展性:在设计编码时,要考虑到未来业务的可能变化,使软件具有一定的灵活性和可扩展性,便于后续的功能添加和修改。
这些借鉴意义可以帮助不使用DDD的项目在软件设计编码过程中更好地理解业务、提高代码质量、增强软件的可维护性和适应性。
关于作者
来自全栈程序员nine的探索与实践,持续迭代中。
欢迎关注、评论、点赞。