MVC vs. DDD
vs. / vs / v.s / v.s. / Vs. / ... / 底哪种才算正确?
https://spencerlam.hk/blog/2024/01/13/vs/这里有不算权威,但应该是正确的解释。
MVC
在过去的若干年中,MVC编程模型大行其道,通过将模型层
、服务层
、控制层
等不同层次的职责分离,淘汰了更古老的页面模板方式。

以常见的电商订单系统为例来说明,它的典型工作过程应该是下面这样的。
会有一个
OrderController
类,专门负责处理客户端(PC
、APP
或小程序
)发过来的下单请求。会有一个
OrderService
类,专门负责各种业务逻辑处理,它的工作内容应该包括但不限于下面这些。OrderService
可能会需要通过其实现类OrderServiceImpl
来完成上述方法。OrderServiceImpl
通过调用底层的数据访问层DAO/Mapper
来操作数据库中的数据。DAO/Mapper
将DO/PO
作为映射,实现对数据的CRUD操作。
它的伪代码可能是这样的。
public class FulfillService {
@Resource
private UserDAO userDAO;
@Resource
private CartDAO cartDAO;
@Resource
private WarehouseDAO warehouseDAO;
@Resource
private OrderDAO orderDAO;
public void preAllocateWarehouse() {
// 校验用户账户
userDAO.check();
// 渲染购物车
cartDAO.render();
// 库存检查
warehouseDAO.check();
// 创建预订单
orderDAO.createPreOrder();
// 其他几百行业务代码
......
}
}

这基本上是一种面向数据库编程
的范式,而不是面向真实世界业务编程
的范式。
MVC最大的问题在于:代码和真实的业务流程、业务模型、业务语义完全脱节,导致可维护性极差。
哪怕是某个人自己写的代码,过了几个月后,他可能自己都看不懂了,更别说其他负责系统维护的工程师。
而且这种代码越到后期就越难于维护:当数量庞大的Controller
、Service
、Dao
以及DO
们混在一起的时候,整个系统已经无解了——要么原封不动,要么推倒重来,没有第三种选择。
DDD
它是什么
DDD的全称是Domain Driven Design
,翻译过来就是领域驱动设计
。
这里的领域
指的是具体的业务分类,比如电商、社交、团购、教培、打车等不同的业务。
DDD的核心思想就是通过聚焦业务来优化软件设计流程,提高软件开发质量、提高可用性和复用性
。
它是一套系统的设计方法论,从战略层面(业务规划)
到战术设计(需求实现)
都很规范,让编码工作更加清晰明了,而且完全面向业务。
用大白话说,DDD就是一种一切围绕业务的软件设计方法论
,而不是像MVC那样围绕数据库编程
。

2003年,Eric Evans出版了一本叫做《Domain-Driven Design: Tackling Complexity in the Heart of Software》(《领域驱动设计:软件核心复杂性应对之道》)的技术图书。
2005年,Alistair Cockburn提出了针对DDD的第一个系统设计架构:六边形架构(Hexagonal Architecture),又叫做端口适配器架构(Ports & Adapters Architecture)。
2008年,Jeffrey Palermo提出了洋葱架构(Onion Architecture)。
2012年,Robert C. Martin提出了改进后的整洁架构(The Clean Architecture)。

虽然DDD中也有数据库操作,也存在CRUD,但它的关注点却始终在业务上。
来看一段DDD的伪代码,并把它和前面的MVC伪代码比较一番就能明白其中的差别。
/**
* 仓库领域模型服务
*
*/
public class WarehouseDomainService {
@Resource
private WarehouseApiGateway warehouseApiGateway;
/**
* 为订单分配最近的仓库
*
*/
public Warehouse preAllocateWarehouse(Order order) {
// 查询所有的仓库信息
Warehouses warehouses = warehouseApiGateway.getAll();
// 从所有的仓库里选择一个距离订单收货地址最近的仓库
Warehouse warehouse = warehouses.selectNearest(order.getDeliveryAddress());
// 检查库存是否充足
if(warehouse.isInventoryEnough(order.getItems())) {
// 将履约订单分配给选择的仓库
order.allocateToWarehouse(warehouse);
// 锁定订单对应的库存
warehouse.lockInventory(order);
return warehouse;
}
return null;
}
}
不是什么
很显然,每种理论、方法都有它的边界。
DDD无法代替团队的技术决策,例如,是使用Spring Boot还是使用Spring Cloud,又或者Flask和Gin呢。
系统性能低的问题和DDD没有半毛钱关系。
DDD本质上仍然是属于
软件工程
而不是产品设计
范畴,好的产品经理仍然是不可或缺的。
取舍
存在即合理
,每种方法都有它自己的适用场景,DDD也并不是用来代替MVC的。
比如,如果只是一个公司内部的小应用系统,就不用搞的像中标几百万甚至上千万的大项目那样折腾,也不用想什么限界上下文
、防腐层
之类的东西,闭着眼睛实现对数据(库)的CRUD就好了,可以非常快地整活。
但如果真的是个大项目,那可就要坐下来好好思忖一番了,因为相比于代码的Bug
,真正决定软件复杂性、可用性的是思考模式和设计方式,而且需求与实现之间的脱节实在是稀松平常。

所以,确切地来说,MVC适用于变化极少且较为简单的业务,而DDD则适用于变化频繁且较为复杂的业务。
MVC模式既是一种思想,也是一种代码架构,而DDD仅仅是一种思想,与实现它的代码架构无关(虽然迄今为止有好几种DDD的实现架构,但并无好坏之分,只有是否适用之别)。
实现
总体上来讲,DDD从初始的分析到最终的编码实现,大致会经过这么三个阶段。

关注公众号后回复 模型
即可获得领域模型
栏目剩余文章的访问密码。
