DDD初步总结

在当今快速发展的商业环境中,局部问题的解决已不足以应对整体的挑战。我们需要从系统或生态的角度出发,推动整个商业链条的前进。这种转变不仅催生了新的岗位和角色,也对技术发展提出了新的要求。

一、背景与趋势

1. 系统化思维

  • 面对商业问题,我们需要超越单一视角,采用系统化思维来寻求解决方案。
  • 技术发展趋向于两极分化,初级开发人员更专注于工具使用,而高级研发人员则需要更全面的能力。

二、架构师的新要求

2.1 全局观

  • 顶层设计: 结合成本、效率、稳定性和性能等多维度因素进行设计。
  • 物理架构与应用架构: 确保设计的全局性和可持续性。

2.2 基本素质

  • 前瞻性: 对未来技术趋势的洞察力。
  • 问题解决: 拥有解决复杂问题的思路和方法。

2.3 能力要求

  • 发现问题: 敏锐地识别潜在问题。
  • 定义问题: 清晰地界定问题的范围和性质。
  • 解决问题: 系统性地提出解决方案,应对一类问题。 通过上述内容,我们可以看到,随着技术的发展和商业需求的变化,架构师的角色变得更加关键。他们需要具备全局观、前瞻性思维以及强大的问题解决能力,以推动技术与商业的共同进步。
    领域驱动设计(六) - 架构设计浅谈_领域驱动设计

架构设计要点

1. 清除单点

  • 系统每层级都应有集群策略,同时考虑容器的自动增删功能,以增强系统的弹性和可靠性。

2. 数据一致性

  • 复杂业务可以通过消息中间件和不同级别的对账机制来保证数据一致性。

3. 强弱依赖

  • 在成本可接受的情况下,可以建立备份流程以临时支撑系统运行,但需注意这可能导致一定时间内的数据不一致。

4. 热点和极限值处理

  • 隔离享用专有资源,适用于大客户与普通客户分离的场景。
  • 根据客户大小进行提前预热。
  • 采用简单逻辑、限流、排队等措施。
  • 对于IM场景,可以从业务上区分用户级别,实现分级处理,以提供差异化的用户体验。

5. 资损流程

  • 资损流程对数据一致性要求较高,设计时需增加对账、总额控制、异常处理和风控设计。

6. 离线数据流

  • 针对规模大、来源广、生产链路长的离线数据流,需增加数据完整性校验、数据正确性校验、数据延迟监控、数据生产失败监控、端到端数据正确性规则校验、数据错误或延迟的兜底预案以及数据回滚重刷工具等机制。

7. 异常流程设计

SOLID原则

  • SOLID原则是一套指导软件开发的设计理念,包括以下五个方面:
  • 单一职责原则:一个类应该只有一个引起它变化的原因。
  • 开闭原则:软件实体应对扩展开放,对修改关闭。
  • 里氏替换原则:子类型必须能够替换其基类型。
  • 接口隔离原则:客户端不应该依赖于它不使用的接口。
  • 依赖倒置原则:高层模块不应依赖于低层模块,两者都应该依赖于抽象。 有兴趣的读者可以深入研究SOLID原则,以提升软件设计的质量和可维护性。
    领域驱动设计(六) - 架构设计浅谈_DDD_02

软件设计原则与架构设计

一、设计原则

1. 单一职责原则单一职责原则强调模块或类应承担单一功能,其划分依据是功能而非实体。在实际应用中,可以通过拆分模块来实现职责的单一化。

2. 开闭原则开闭原则提倡通过抽象和继承来扩展功能,同时保持原有代码的稳定性。实现多态是关键,它直接影响函数的执行顺序。

3. 里氏替换原则里氏替换原则要求子类能完全实现父类的方法。如果不能,建议使用依赖、聚合或组合关系代替继承。

4. 接口隔离原则接口隔离原则主张客户端不应依赖其不需要的接口,类间依赖应建立在最小接口上,与单一职责原则有关联。

5. 依赖倒置原则依赖倒置原则指出高层模块不应依赖低层模块,而应依赖抽象。抽象不应依赖具体实现,具体实现应依赖抽象。

二、架构设计

1. 常见架构常见的架构包括MVC分层、六边形架构、CQRS、事件驱动和微服务等。在领域驱动设计(DDD)中,推荐使用CQRS、六边形和事件驱动架构。

2. 架构模式的混合使用实际应用中,系统往往采用混合架构模式。关键在于能否清晰表述层次职责和层次间的依赖关系。

3. DDD的经典层次结构

  • UI表现层:负责显示信息和解释用户指令。
  • 用户接口层:提供数据API接口给UI表现层。
  • 应用接口层:定义任务,指挥领域层解决问题,管理安全和事务。
  • 领域层:控制业务状态和规则,与基础设施层交互。
  • 基础设施层:提供技术能力,包括数据持久化。

3.1 MVC分层

3.1.1 设计原理分层架构要求上层只能与下层耦合。通常采用松散分层架构,解决逆向调用问题的方法包括:

  • 观察者模式:底层发布事件,高层接收。
  • 调停者模式:底层定义接口,高层实现,并可传递实现作为参数。

三、架构设计的表述架构设计的表述应清晰描述层次职责和依赖原则,区分依赖细节和依赖抽象。

领域驱动设计(六) - 架构设计浅谈_领域驱动设计_03

分层架构与六边形架构概述

3.1 分层架构

3.1.1 经典松散分层架构在经典的分层架构中,逆向调用是一个需要注意的问题。这种架构通常由多个层次组成,每层都有其特定的职责。

3.1.2 领域层依赖问题领域层的实现不应依赖于基础设施层。通过将领域接口的实现放在应用层,并由应用层引用基础设施,可以解决这一问题。

3.1.3 依赖倒置原则依赖倒置原则强调高层模块不应依赖低层模块,而是两者都应依赖于抽象。这意味着抽象不应依赖于细节,而细节应依赖于抽象。

3.1.4 应用层的角色在领域驱动设计(DDD)中,应用层通常很薄,不包含业务逻辑。它的主要职责是控制事务、安全认证和消息通知。应用层接收端指令,通过资源库获取聚合实例,并执行领域服务。

3.1.5 领域事件的发布当领域层需要发布领域事件时,应用层可以注册订阅方到事件上,实现事件的存储和转发。这允许领域层专注于其核心逻辑,同时保持与基础设施层的解耦。

3.2 六边形架构(Adapter六边形)

3.2.1 设计原理六边形架构是一种从分层架构转换而来的概念。端口和适配器的作用是将外部输入转换为系统API可理解的参数,并委托给内部系统处理。

3.2.2 适配器的类型

  • 输入适配器:接收用户指令,向应用程序发起请求,调用端口。
  • 输出适配器:响应请求,将结果输出到外部设备或工具,实现端口。

3.2.3 六边形架构的优点

  • 易于开发用于测试的适配器。
  • 应用程序和领域模型可以独立开发。
  • 接入方可以并行开发,通过适配器与系统交互。

3.2.4 适配器与端口的关系适配器和端口共同工作,确保系统的灵活性和可测试性。通过适配器,系统可以轻松地与外部世界交互,同时保持内部逻辑的清晰和独立。

领域驱动设计(六) - 架构设计浅谈_应用程序_04

六边形架构概述

适配器与协议在六边形架构中,适配器扮演着至关重要的角色。它们负责实现与外部系统或组件的通信协议。这些协议通常由公共组件来完成。存储系统在领域驱动设计(DDD)中被视为一种客户端,其存取服务通过资源库模式来实现。

核心域与适配器的交互核心域通过适配器与外部客户端进行交互。如果领域服务需要发布事件,这些事件同样需要通过适配器进行转发。这在架构图中通常用特定的颜色区域来表示。

架构边界六边形架构的边界由外六边形定义。在两个六边形之间,设计了一个适配转发器,它的任务是自动将用户的请求路由到合适的适配器上。适配器随后将请求传递给应用程序。

适配器与应用程序的职责交接在适配器和应用程序之间,存在一个职责交接的过程。这个过程确保了请求的顺利传递和处理。

六边形架构的图形表述六边形架构可以用不同的图形来表述,以更直观地展示其结构和工作流程。

结构性描述

  1. 适配器:实现与外部系统的通信协议。
  2. 存储系统:作为客户端,通过资源库模式与核心域交互。
  3. 核心域:通过适配器发布事件,与外部系统进行交互。
  4. 适配转发器:位于两个六边形之间,自动路由用户请求。
  5. 职责交接:适配器与应用程序之间确保请求的顺利处理。

总结六边形架构通过明确的边界和职责划分,实现了系统的高内聚和低耦合,为软件的可维护性和可扩展性提供了良好的基础。

领域驱动设计(六) - 架构设计浅谈_应用程序_05

3.3、CQRS事件驱动

3.3.1、设计原理

这种架构模式会带来系统的复杂性和基础依赖,但同时也能解决数据显示的复杂性问题,CQRS架构比较适合异构数据和需要读写分离的应用。概要设计如下图所示:

领域驱动设计(六) - 架构设计浅谈_应用程序_06

CQRS架构概述

CQRS(Command Query Responsibility Segregation)架构模式是一种将读操作和写操作分离的设计思想,以提高系统的性能和可扩展性。在实现CQRS架构时,需要特别注意以下两个关键组件:

查询模型查询模型是专门用于显示的模型,它不包含在领域模型中。设计查询模型时,需要考虑以下几个要点:

  • 视图数量:设计时需注意视图的数量,以避免数据冗余和复杂性增加。
  • 查询过滤器:通常在处理器中内置查询过滤器功能,用以减少不必要的视图生成。
  • 状态修改:在查询过程中,不应直接或间接修改对象的状态。

命令处理器命令处理器是负责更新对象状态的组件。其设计要点包括:

  • 状态更新:执行命令后,对象状态应该被更新。
  • 领域事件发布:命令执行完毕后,必须发布一个领域事件,用于更新查询模型。

设计细节CQRS架构的实现细节如下:

  • 除了getById()方法外,其他所有查询方法应从原始查询接口中分离出来。
  • 查询模型与命令处理器应独立设计,以确保它们各自职责清晰。

架构设计图详细的CQRS架构设计图将展示查询模型和命令处理器的交互方式,以及它们如何通过领域事件进行通信。

领域驱动设计(六) - 架构设计浅谈_基础设施_07

四、工程设计

在软件开发过程中,源码目录的结构设计对于多人协作、项目打包、发布和部署等方面至关重要。特别是在跨国团队中,良好的目录结构可以大大提高开发效率。本章节将分享笔者在前公司实施的一些经验,供参考。

1. 目录结构设计原则

目录结构的设计应与项目架构紧密结合。例如,如果采用领域驱动设计(DDD)模式,可以将项目分为三个主要层次:应用服务层、领域服务层和领域层。这构成了一级设计。而领域内的服务、聚合、实体等则属于二级设计。

2. 模块设计规范

  • 顶级目录:固定顶级目录结构,如com.xxx
  • 上下文名称:根据业务领域确定,例如refund
  • 一级层次:区分为domainapplicationport.adapterrepository等。
  • 模块:根据具体业务进一步细分,例如submodule
  • 二级层次:根据架构设计进一步细分,如servicemodelevent等。

3. 模块设计示例以下是模块设计的一个示例,展示了如何根据上述规范构建目录结构:

  • 顶级目录 + 上下文名称 + 一级层次 + 模块 + 二级层次
  • 例如:com.xxx.refund.domain.submodule.service
  • 进一步细分:com.xxx.refund.domain.flowlog.service

4. 注意事项

  • 保持目录结构的一致性,以便于团队成员理解和维护。
  • 根据项目需求和团队习惯,适当调整目录结构规范。
  • 跨国团队应考虑时区、语言和文化差异,确保沟通顺畅和协作高效。 通过上述内容,我们可以看到源码目录的设计是一个需要综合考虑多方面因素的系统工程。合理的设计不仅可以提高开发效率,还能为项目的长期维护打下坚实基础。
    领域驱动设计(六) - 架构设计浅谈_数据_08
    在软件开发过程中,设计一个清晰、有条理的架构对于项目的可维护性和扩展性至关重要。以下是根据所提供的信息重新编写的内容,以提高架构设计的清晰度和结构性:

设计原则

  • 避免通用后缀:不推荐使用通用的后缀名称,因为它们可能引入不必要的噪音并限制层次调用。
  • 模块化:使用模块来区分不同的功能或服务,以提高代码的组织性和可维护性。

架构层次

  • 第一层:基础层,通常包含项目的基础设置和服务。
  • 第二层:业务逻辑层,处理具体的业务需求和逻辑。
  • 第三层:领域层(Domain Layer),可能不直接包含代码,而是定义了业务规则和领域模型。

设计图参考

附上一张其他优秀架构师的设计图,以供参考和启发。

结构化内容

  1. 基础层:定义项目的基础架构和通用服务。
  2. 业务逻辑层:实现具体的业务需求,处理业务逻辑。
  3. 领域层:抽象业务规则,定义领域模型,指导业务逻辑层的实现。

注意事项

  • 保持架构的灵活性,以适应未来可能的需求变更。

  • 确保各层之间的接口清晰,降低耦合度。 通过遵循上述原则和结构,可以构建一个既清晰又灵活的软件架构。
    领域驱动设计(六) - 架构设计浅谈_基础设施_09

  • 收藏

  • 评论

  • 举报

相关文章