DDD架构落地
领域驱动设计(Domain-Driven Design,DDD)是一种软件开发方法,旨在帮助开发者更好地理解和设计复杂领域,并将领域模型直接映射到软件架构中。
要在项目中成功落地DDD,您可以采用以下一般性的步骤:
第一步:理解领域:
首先,您需要深入了解项目所涉及的领域。
这包括与领域专家合作,探索业务需求,收集和整理领域知识。
领域知识将成为您的领域模型的基础。
第二步:分解问题域、划分领域:
将领域划分为子领域(subdomains),识别出主要的业务概念和关系。
每个子领域可以有自己的领域模型,并负责特定的业务功能。
第三步:定义限界上下文:
为每个子领域定义限界上下文(bounded context),限界上下文是一个清晰定义了领域模型的边界的范围。
在限界上下文内,领域模型的概念是一致的,但不同限界上下文之间可以有不同的模型和语言。
界限上下文,基本可以对应到 落地层面的 微服务。
这就是 DDD 建模和 微服务架构, 能够成为孪生兄弟、 天然统一的原因。
第四步:定义统一语言:
DDD 战略设计的第一步就是统一语言,也叫通用语言(UBIQUITOUS LANGUAGE),用于定义上下文 的含义。
如果定义统一语言,不同的团队,可以使用不同的 工具,可以使用思维导图、excel表格等等。
第五步:创建领域模型:
设计DDD中的常用模型,如实体(Entity)、值对象(Value Object)、聚合根(Aggregate Root)、仓储(Repository)、领域事件(Domain Events)等,以便更好地表达领域模型。
使用领域知识创建领域模型,这是DDD的核心。
领域模型是一种反映领域中实体、值对象、聚合根、仓储等概念的抽象模型。
可以使用面向对象编程来表现领域模型,并使用通用语言来描述领域概念。
第六步:领域模型映射:
将领域模型映射到代码中,可以使用对象关系映射(ORM)工具或手动编码。
确保领域模型的设计反映了领域知识和业务规则。
包括两个维度的映射:
-
微服务层面的映射:BC到微服务的映射
-
微服务内部的映射:领域对象的映射 :如 entity 的映射
第七步:开发代码,并且测试领域模型:
通过一键代码生成工具,生成领域模型的骨架代码,并且完成领域业务代码的开发。
编写单元测试和集成测试来验证领域模型的正确性。
使用模拟对象(Mocks)等技术来隔离领域模型的测试。
第八步:持续演化:
随着项目的推进,持续改进和演化领域模型。与领域专家保持紧密合作,根据业务需求进行调整和扩展。
反馈循环:随着项目的演进,接受来自实际使用的反馈,不断改进领域模型和架构。
第九步:效能提升
领域驱动设计是一种强大的方法,可以帮助解决复杂领域中的问题,但它也需要投入时间和精力来构建和维护领域模型。
DDD工具优化:
考虑使用专门的DDD工具或框架,如EventStorming、CQRS(Command Query Responsibility Segregation)、Event Sourcing等,以更好地支持领域驱动设计。
团队协作:
要成功落地DDD,需要一定的学习和实践,同时也需要团队的共识和支持。
在整个项目中,确保团队成员之间的良好沟通和协作,特别是与领域专家的沟通,以确保领域模型的准确性。
文档和培训:
编写文档来记录领域模型和限界上下文,以帮助团队成员理解和使用它们。还可以提供培训以确保团队对DDD的实践有足够的了解。
监控和性能优化:
在生产环境中监控应用程序,确保领域模型的性能和可伸缩性。根据实际需求进行性能优化。
领域驱动设计与敏捷开发相结合
领域驱动设计和敏捷开发是两种不同的方法论,但可以相互结合,提高开发效率和软件质量。
在敏捷开发过程中,团队通常采用迭代式的开发模式,不断地根据用户反馈和需求变化进行调整和优化。
这种敏捷开发模式与领域驱动设计的思想相契合,因为领域驱动设计强调将业务领域建模为一个相对独立的系统,同时也强调不断优化和迭代。
以下是一些结合领域驱动设计和敏捷开发的方法:
-
划分迭代周期:在敏捷开发中,团队通常会划分出多个迭代周期来实现软件的开发和交付。在每个迭代周期中,可以采用领域驱动设计方法进行领域建模和设计,以确保软件系统的质量和可维护性。
-
与领域专家和用户紧密合作:在敏捷开发中,团队需要与领域专家和用户紧密合作,及时获取用户反馈和需求变化。在领域驱动设计中,也需要与领域专家和用户紧密合作,以确保领域建模的准确性和实用性。
-
重构和优化:敏捷开发中,团队需要不断地重构和优化代码,以提高软件系统的质量和可维护性。在领域驱动设计中,也需要不断地优化领域建模和设计,以提高系统的可扩展性和可维护性。
-
测试和验收:在敏捷开发中,团队需要进行测试和验收,以确保软件系统的质量和稳定性。在领域驱动设计中,也需要进行测试和验收,以确保领域建模和设计的准确性和实用性。
为什么微服务需要DDD?TDD和DDD有何关系?
首先,说说微服务设计和拆分的困境:
微服务解决大单体架构的的很多问题,比如扩展性、弹性伸缩能力、小规模团队的敏捷开发等等。
但是微服务实践过程中,大部分架构师遇到很多难题:
-
微服务的粒度应该多大呀?
-
微服务到底应该如何拆分和设计呢?
-
微服务的边界应该在哪里?
拆分微服务的时候,两种情况:
-
有的颗粒度过大, 还是大单体
-
有的颗粒度过小,导致上线和运维工作量巨大。
很多“水货架构师”,在拆分微服务的时候凭借感觉:简单的把微服务理解为小单体,粗暴的把原来一个大单体包拆分为多个部署包,导致后期工程风险严重失控。从而陷入了微服务设计和拆分的困境。
其次,说说解决困境的两个方面
微服务设计和拆分的困境,分成两个方面:
-
理论面,缺乏一套系统的理论和方法指导。
-
落地面,缺乏一套可以参考的代码骨架。
最后,说说DDD的理论指导价值和落地指导价值
DDD 就是这种不可多得的微服务设计和拆分的理论和方法指导。
DDD 指导了两个层面的设计和建模:
-
宏观层面:指导了微服务外部的建模,包括系统和系统之间, 微服务和微服务之间依赖关系的建模。
-
微观层面:指导微服务内部的建模,包括 领域对象建模, 微服服务落地的各层关系的建模。
正因为如此,DDD现在非常火爆,有其巨大生产价值、经济价值的, 绝不仅仅是一套概念那么简单。
各个大厂的大致情况是:
-
新项目都尽可能结合DDD进行设计建模、工程落地
-
老项目也在使用DDD进行从点到面的改造,以榨取软件的最佳性能。
什么是TDD?
测试驱动开发是一种开发方法,其核心理念是在编写实际代码之前先编写测试用例。
这些测试用例描述了所期望的代码行为。
开发者根据这些测试用例来编写代码,以确保代码通过所有测试并符合预期。
TDD的步骤通常是:
编写测试用例 -> 运行测试(测试应该失败) -> 编写代码 -> 再次运行测试(测试应该通过)。
常见的TDD框架包括JUnit(Java)、RSpec(Ruby)和unittest(Python)。
适合TDD这种模式的项目具备以下特点:
-
项目的需求必须足够清晰,而且程序员对整个需求有足够的了解。
-
项目的复杂度和依赖性要低。对于一个业务模型及其复杂、内部模块之间的相互依赖性非常强的项目,采用TDD反而会得不尝失,这会导致程序员在拆分接口和写测试代码的时候工作量非常大。另外,由于模块之间的依赖性太强,我们在写测试代码的时候可能不采取一些桥接模式来实现,这样势必加大了程序员的工作量。
TDD和DDD有何关系?
DDD的一个根本能力,提升了可测试性。DDD为TDD的落地,提供很好的基础支撑和前置条件。
在问题DDD的前置问题
附1:说说,你对微服务是怎么理解的?
微服务是由Martin Fowler大师提出的。微服务是一种架构风格,通过将大型的单体应用划分为比较小的服务单元,从而降低整个系统的复杂度。
微服务,是一种架构风格,它将应用构建为一个小型自治服务的集合。通俗地说,就像蜜蜂通过对蜡制的等边六角形单元来构建它们的蜂巢。他们最初从使用各种材料的小单元开始,一点点的搭建出一个大型蜂巢。
微服务优点:
优势 | 说明 |
---|---|
独立开发 | 所有微服务都可以根据各自的功能轻松开发 |
独立部署 | 根据他们所提供的服务,可以在任何应用中单独部署 |
故障隔离 | 即使应用中的一个服务不起作用,系统仍然继续运行 |
混合技术栈 | 可以用不同的语言和技术来构建同一应用程序的不同服务 |
粒度缩放 | 各个组件可根据需要进行扩展,无需将所有组件融合到一起 |
微服务缺点:
1、服务调用的复杂性提高了:网络问题、容错问题、负载问题、高并发问题。
2、分布式事务: 尽量不要使用微服务事务。
3、测试的难度提升了。
4、运维难度提升:单体架构只要维护一个环境,而到了微服务是很多个环境,并且运维方式还都不一样。所以对部署、监控、告警等要求就会变得非常困难。
5、微服务拆分, 缺乏统一的标准,拆分不合理会导致后面 出现 内部混乱,从 "大泥球" 演变成 更多的 “小泥球”。
附2:说说,微服务架构中的DRY是什么?
DRY(Don’t Repeat Yourself) , 代表:不要重复自己。
DRY促进了重用代码/代码复用。这意味着在多个地方不要重复同样的代码,而应该将它们封装为库或服务,以便在其他地方调用。这种思想可以促进代码的模块化和可重用性,提高开发效率和质量。
所以,从微服务出发, 就演进出来了 技术中台、数据中台、业务中台的架构。
但是DRY反过来导致紧耦合。
附3:说说,设计微服务的最佳实践是什么?
- 微服务设计的规范和原则
- 1.准备好微服务治理基础设施
- 2.单一责任原则(SRP)
- 3.松耦合原则
- 4.领域驱动原则,不数据驱动原则,也不是界面驱动原则
- 5.架构分层职责明确,严守调用规范,规避 “微服务小泥球”
- 6.进行全方位的监控、记录
- 7.通过CI/CD实现devops (开发运维一体化),提升工程效能
- 8.基于业务需求变化频率进行微服务拆分
- 9.基于吞吐量进行微服务拆分
- 10.基于技术异构因素进行微服务拆分
注意其中的核心点:领域驱动原则,不数据驱动原则,也不是界面驱动原则