架构演进之 DDD:从 CRUD 到领域驱动设计

大家好,我是G探险者!

今天来聊一聊DDD。

在软件开发的世界里,架构从来不是一开始就复杂的。

绝大多数系统,最初都只是简单的 CRUD 系统。但随着业务的增长,系统复杂度不断增加,原有的开发模式逐渐暴露出问题。于是,新的架构思想开始出现。

DDD(Domain-Driven Design,领域驱动设计)正是在这样的背景下诞生的。

理解 DDD 的最好方式,并不是直接学习那些复杂的概念,而是从软件架构的演进过程来看:

为什么我们最终需要 DDD。


一、第一阶段:CRUD时代 ------ 数据库驱动开发

在企业软件早期,大多数系统都是围绕数据库构建的。

典型架构结构:

复制代码
Controller → Service → DAO → Database

系统本质上是:

sql 复制代码
页面 + 表 + SQL

开发流程通常是:

  1. 设计数据库表
  2. 编写 SQL
  3. 提供接口
  4. 页面展示数据

这种模式的核心特点是:

  • 数据库是系统中心
  • 业务逻辑很薄
  • 系统主要是增删改查

这种开发方式就是我们熟悉的:

CRUD(Create Read Update Delete)模式

这种模式非常适合:

  • 管理后台
  • CMS系统
  • 配置系统
  • 权限系统

直到今天,大量企业系统仍然采用这种模式。

但当业务复杂度上升时,问题开始出现。


二、第二阶段:三层架构 ------ 软件工程化

随着系统规模扩大,软件工程开始强调结构化设计,于是出现了经典的 三层架构

复制代码
表现层(Controller)
业务层(Service)
数据层(DAO)

职责划分:

职责
Controller 接收请求
Service 业务逻辑
DAO 数据访问

这种架构带来的改进:

  • 代码结构更清晰
  • 业务逻辑与数据访问分离
  • 更利于团队协作

三层架构成为 Java 企业开发的主流模式。

但随着系统规模继续扩大,一个新的问题逐渐出现。


三、第三阶段:Service 膨胀

在三层架构中:

  • Controller 很薄
  • DAO 只负责数据库

于是,所有业务逻辑都堆到了:

Service层

随着业务增加,Service层逐渐变成:

复制代码
状态判断
流程控制
业务规则
外部系统调用
事务控制
日志处理
异常处理

最终形成所谓的:

Fat Service(肥胖服务层)

一个 Service 方法可能:

  • 几百行代码
  • 大量 if-else
  • 多个系统调用

Service逐渐变成:

业务逻辑的大泥球


四、第四阶段:贫血模型

与此同时,系统中的领域对象往往非常简单。

例如一个订单对象:

java 复制代码
class Order {
    Long id;
    Integer status;
    BigDecimal amount;
}

它通常只有:

  • getter
  • setter

而业务逻辑却写在 Service:

css 复制代码
orderService.pay(order)
orderService.cancel(order)
orderService.refund(order)

这种模式被称为:

贫血模型(Anemic Domain Model)

问题是:

  • 对象只有数据,没有行为
  • 业务规则散落在各个 Service
  • 代码难以理解
  • 系统难以维护

随着系统复杂度增加,这种问题会越来越严重。


五、第五阶段:业务复杂度爆炸

当系统进入核心业务阶段时,复杂度会快速增长。

例如一个订单系统,可能涉及:

  • 下单
  • 支付
  • 发货
  • 退款
  • 售后
  • 库存锁定
  • 营销活动
  • 价格计算

各种业务规则:

复制代码
已支付订单不能取消
库存不足不能下单
优惠券规则
会员等级规则
退款时间限制

如果这些规则散落在:

  • Service
  • SQL
  • Controller

系统很快会变得:

  • 难以理解
  • 难以维护
  • 难以扩展

这时开发者往往会发现:

功能可以做,但系统越来越难改。


六、DDD的出现:业务驱动架构

在这样的背景下,Eric Evans 在 2003 年提出了:

Domain-Driven Design(领域驱动设计)

DDD的核心思想是:

软件设计应该围绕业务领域进行,而不是围绕技术实现。

传统架构关注:

复制代码
数据库
接口
框架

DDD关注:

复制代码
业务模型
领域概念
业务规则
系统边界

简单来说:

传统架构 DDD
技术驱动 业务驱动
数据库中心 领域模型中心

七、DDD核心思想

DDD包含几个关键概念。

1 领域模型

系统应该围绕业务模型设计。

例如订单系统核心对象:

css 复制代码
订单 Order
订单项 OrderItem
支付 Payment
优惠 Coupon

领域对象不仅有数据,还应该有行为:

scss 复制代码
order.cancel()
order.pay()
order.refund()

业务规则应该由领域对象负责。


2 统一语言(Ubiquitous Language)

DDD强调:

开发人员和业务人员应该使用统一的业务语言。

例如:

  • 订单
  • 库存锁定
  • 支付确认
  • 退款申请

这些概念应该直接体现在代码中。

这样代码就能表达业务。


3 限界上下文(Bounded Context)

在复杂系统中,同一个概念在不同系统中可能含义不同。

例如"订单":

系统 含义
交易系统 用户购买记录
仓储系统 发货任务
财务系统 结算凭证

DDD提出:

每个业务上下文拥有自己的模型

这就是:

Bounded Context(限界上下文)


八、DDD与微服务

随着微服务架构的发展,人们发现:

DDD提供了一种非常自然的服务拆分方式。

因为:

复制代码
Bounded Context ≈ Microservice

例如:

css 复制代码
订单上下文 → Order Service
库存上下文 → Inventory Service
支付上下文 → Payment Service

DDD帮助架构师回答一个关键问题:

服务应该如何拆分?


九、DDD的真正价值

很多人认为 DDD 只是:

  • 多几个类
  • 多几层结构

其实并不是。

DDD真正解决的是:

复制代码
复杂业务系统如何组织

它帮助架构师:

  • 理解业务
  • 划分系统边界
  • 管理业务复杂度
  • 支持系统长期演进

十、架构演进时间线

从架构演进角度看,软件开发经历了这样一条路径:

markdown 复制代码
CRUD开发
      ↓
三层架构
      ↓
Service膨胀
      ↓
贫血模型
      ↓
业务复杂度爆炸
      ↓
DDD出现
      ↓
领域建模
      ↓
Bounded Context
      ↓
微服务架构

DDD并不是为了让系统变复杂,而是为了:

用更好的模型管理复杂业务。


十一、结语

从架构演进的角度来看,DDD的意义在于:

让软件系统真正反映业务世界。

当系统结构与业务结构一致时,软件才能具备:

  • 可理解性
  • 可维护性
  • 可演进性

这正是领域驱动设计的核心价值。


相关推荐
武子康2 小时前
大数据-248 离线数仓 - 电商分析 Hive 离线数仓维表设计实战:快照表、拉链表与 DIM 增量加载全流程
大数据·后端·apache hive
Are_You_Okkk_2 小时前
适配集团/事业部/扁平化组织:开源知识库的落地策略与价值
人工智能·架构·开源
孟沐2 小时前
MyBatis 新手入门查阅文档(从基础到增删改查,大白话版)
后端
董员外2 小时前
从零实现 AI 编程助手:LangChain.js + ReAct 循环实战
前端·javascript·后端
gp3210262 小时前
什么是Spring Boot 应用开发?
java·spring boot·后端
mcooiedo2 小时前
Spring Boot与MyBatis
spring boot·后端·mybatis
anyup2 小时前
弃用 vue-i18n?只用 uView Pro 我照样做国际化!
前端·架构·uni-app
惊讶的猫2 小时前
springboot常用注解
java·spring boot·后端
掘金者阿豪2 小时前
MySQL迁移,别再信“改几行配置就能跑”:金仓KingbaseES深度兼容实战
后端