流程与模型之痛:Scrum 断层、事务脚本与贫血 MVC
入门与动机 · 第 2/15 篇
上一篇:《DDD 是什么:历史、价值与本质收益》
下一篇:《架构基础:SOLID、OOA/OOD 与隐式业务显式化》
开头:理想流程与现实落差
很多团队名义上在跑 Scrum,实际却是 轻设计、重编码、库表先行。DDD 要解决的,不仅是「怎么写类」,更是 流程与模型之间的断层——以及由此带来的事务脚本、贫血 MVC 等面向过程写法。
本篇从 Scrum 流程问题讲起,对比事务脚本、贫血模型与充血模型,为理解 DDD 的建模方式做铺垫。
一、传统 Scrum 流程:理想与现实
理想中的 Scrum
详细设计有三种内部视图,侧重点不同:
| 视图 | 侧重点 |
|---|---|
| 流程图 | 逻辑分支 |
| 顺序图 | 交互 |
| 状态机图 | 状态流转 |
流程图、时序图、状态机图是流程视图中最重要的三种,可称为 流程三剑客。
例如订单系统中,订单状态变更命令的通用流程、订单/物流状态节点与领域事件,可以用流程图与状态机建模:


现实中的 Scrum
轻量级流程的关键点往往是:设计好库表,把隐式字段显式化(ER 图),再用代码生成工具——优点是 快。

二、管理面问题:设计与编码断层
1. 设计被弱化
常见做法:库表、接口定义个大概,简单设计文档甚至省略,对着原型直接建表、定义 API、开写。美其名曰 轻量级迭代——进度优先,软件质量与「生命值」先靠边。
后果包括:
- 初级开发并未真正理解需求,一周后才发现走弯路或白干;
- 数据驱动开发 从库表到接口到代码一气呵成,但未做 变与不变的隔离,变和不变紧耦合,埋下大量隐患。
2. 需求澄清的假象
团队里常有初级程序员:串讲时拍胸脯说「绝对清楚了」,一周 code review 却发现交付与预期差距巨大。中高级甚至架构师也会因设计不充分,写到一半冒出 隐形字段、隐性流程、隐性接口,加字段、改表、改 Entity、改 API——为线上预埋风险。
3. 业务与开发隔离
业务写完 PRD 就等验收;开发埋头写代码。同一词、同一功能若理解有偏差,各自留心底,验收时才甩锅——根因是 业务与开发隔离。

如何强化设计与编码的依赖、拉通断层? DDD 是有效路径:引入领域专家,用 通用语言 做领域驱动建模。
三、通用语言与领域驱动关键点
什么是通用语言?
电商项目组讨论时,可能出现:
- 程序员 A:「我们购买商家的产品」
- 程序员 B:「用户买商品」
- 产品经理:「我们采购店家商品」
- 测试:「用户购买物品」
表达同一意思,却不统一。通用语言 就是项目所有角色对 同一业务词汇 有统一定义,避免一词各表、鸡同鸭讲——实践中并不容易。
在 事件风暴 等协作中,团队达成共识、能准确描述业务涵义与规则的语言,就是通用语言。它贯穿 DDD 全过程,名词可对应实体(如商品、订单),动词对应领域事件或命令(如「商品已下单」「订单已付款」)。
领域驱动的关键点
- 以领域为切入点:先提炼领域概念、构建领域模型表达业务,尽量避免过早牵扯技术细节;
- 编码是模型的翻译:类名、方法名、变量名应表达领域概念,见码明义。
三个特点
(1)思维模式转变
数据驱动:根据需求做数据建模 → ORM 映射表 → 范式优化关联。数据模型是需求的直接翻译,未蕴含稳定的领域知识;需求一变,模型和库表都要变,中间缺少稳定层级,系统响应变化能力差。
(2)协同方式转变
产品提需求、研发做方案并直译成数据模型;研发方案含大量技术细节,产品难以判断是否与业务一致,认知差异随迭代放大,系统变成大泥球。
DDD 引入 领域专家 与 模型驱动设计:领域专家从易变需求中提炼稳定边界与规则,与产品、研发共建领域模型;模型变更对应需求与代码变更,协作以模型为中心。

(3)精炼循环
统一语言 → 提炼概念 → 明确边界 → 构建模型 → 绑定实现,各环节 相互影响、反馈、迭代,沉淀稳定深层模型。设计根本思想:分离变和不变,识别稳定/不稳定模型,保证领域模型稳定性,提升代码生命值。
四、技术面:事务脚本与 MVC 贫血模型
1. 库表驱动 = 事务脚本模式
事务脚本(Transaction Script,TS)核心:事务 + 脚本。
- 事务:实际需要执行的一段原子业务;
- 脚本:一组原子业务的编排,通常映射到用户的一个行为。
TS 是 过程式 的,逻辑用 if、while、for 表达,不含面向对象设计。一次用户动作对应一次业务请求,需要脚本层编排事务,事务层操作数据库——与经典三层(脚本层 / 事务层 / 数据库层)等价,也对应 Handler、Manager 等变体。
特点:不同用户动作对应的脚本一般相互隔离;不同脚本可复用同一事务;建模时 不需要任何 OO 设计模式。
2. 贫血模型的传统 MVC
MVC 中 M/V/C 对应 Model、View、Controller;Web 后端常见分层为 Repository(数据访问)→ Service(业务逻辑)→ Controller(接口)。
贫血模型:所有业务逻辑不在实体对象内,而在 Business Logic / Service 层。领域对象(Entity、BO、VO)几乎只做 数据传输,破坏封装,是典型 面向过程 风格。

典型结构示例:
// Controller + VO
public class UserController {
private UserService userService;
public UserVo getUserById(Long userId) {
UserBo userBo = userService.getUserById(userId);
// convert userBo to userVo
return userVo;
}
}
// Service + BO(贫血:只有数据,无业务逻辑)
public class UserService {
private UserRepository userRepository;
public UserBo getUserById(Long userId) {
UserEntity userEntity = userRepository.getUserById(userId);
// convert to UserBo
return userBo;
}
}UserBo、UserEntity、UserVo 都是 只含数据、不含业务逻辑 的贫血对象;业务集中在 UserService——即 重 Service、轻 BO,面向过程思维。
使用 Spring 时,Domain 类常仅作数据存储,Spring 管理 Logic 层 singleton Bean;若在 Domain 里硬塞业务方法,Bean 引用与构造会变得复杂——这也是贫血模型流行的技术原因之一。
五、充血模型与 DDD 开发模式
充血模型:数据与业务逻辑封装在 同一个类 中,满足 OO 封装,是面向对象风格。
分层仍可分 Controller、Repository、Service,区别在 Service 层:
| 模式 | Service 层组成 | 特点 |
|---|---|---|
| 贫血 MVC | Service 类 + BO(纯数据) | 重 Service 轻 BO,面向过程 |
| 充血 DDD | Service 类 + Domain(数据+逻辑) | 轻 Service 重 Domain,面向对象 |
层次关系变为:Client → Business Facade → Business Logic → Domain Object → DAO。Business Logic 只做事务、权限等薄封装,符合单一职责。
贫血模型 在「失血模型」基础上,对象含一些状态变化但停留在内存,不关心持久化。
为什么贫血模型仍占主流?
- 业务简单:大量 CRUD,贫血够用;充血模型也偏薄,意义不大。
- 充血设计更难:需事先设计数据暴露哪些操作;贫血则需求来了在 Service 加方法即可。
- 思维与转型成本:多年习惯,无痛点不愿改。
结论:业务简单时贫血简单够用;业务复杂时,充血 + DDD 前期设计投入更多,但复用性与维护性更有优势——这正是 DDD 的价值区间。
小结
- Scrum 轻流程 常导致设计与编码断层、业务与开发隔离。
- 通用语言 与 精炼循环 是 DDD 拉通断层的核心手段。
- 事务脚本 + 贫血 MVC 是数据驱动、面向过程的典型;充血 Domain 是 DDD 战术层的方向。
下一篇进入 SOLID、OOA/OOD 与 隐式业务显式化,补齐架构基础。