韩宇斌—DDD战略建模在重构业务系统时的实践 v0712

文字内容
1. DDD战略建模 在重构业务系统时的实践 韩宇斌 罗辑思维-得到后端业务线Leader
4. 韩宇斌 • Business Dev 现就职于罗辑思维得到后端,听书方向的技术负责人,擅长利用 DDD 和 OO 思想 对业务需求进行分析建模与设计开发。 • 在好大夫在线负责电话咨询业务时,创新了“不挂机切换会议室”的业务流程并技 术实现,极大提高了运营的工作效率并节省成本,荣获优秀员工。 • 在 ToB 类软件公司担任过开发和项目经理,具有从客户原始需求转换成可落地的技 术设计并实施的经历;在 ToC 类互联网公司一线负责过许多类型各异的业务系统, 能够深入理解业务目标并落地。
5. 得到App && 听书
6. • DDD战略建模在重构业务系统时的实践 一. 用领域驱动来把握真正的业务需求 二. 领域驱动设计指导架构设计与建模 三. 用限界上下文来保护领域
7. 领域驱动设计帮住我解决了工作的难题 无路可退 :入职第一个任务 左右为难 :实现技术重构的目标,满足不了业务需求! 不去实现,又不知道该做什么?
8. 背景知识:商家视角的电商业务基本流程 卖货 收钱 发货 算账
9. 得到app电商业务涉及的组织和系统 卖货 收钱 发货 算账
10. 得到app目前如何确认收入 下单 收钱 发货 订单记录 支付记录 权益记录 OrderId ✅ 损失或呆账 OrderId 严格匹配 OrderId ✅ 确认收入
11. 谁还没有个过去 收钱 支付记录 收了钱没发货? ✅ 损失或呆账 严格匹配? 发货 权益记录 财务:没有 订单,出了 问题我信谁? 发货了没收钱? ✅ 确认收入
12. 没有订单时,听书业务实现售卖流程的调用关系
13. 没有订单时,听书业务实现所有售卖流程的调用关系
14. 财务: 必须记录订单及交易状态 下单 CreateOrder 订单记录 OrderId ✅ 损失或呆账 收钱 PayOrder 支付记录 OrderId 严格匹配 发货 SignOrder 订单化 权益记录 OrderId ✅ 确认收入
15. 实现了“订单化”后的调用关系
16. 实现了“订单化”后,依赖与耦合加剧
17. 原系统架构的问题很快暴露 订单加个“签收时间”字段 20多天才能上线 投入与收益不匹配!
18. 财务:尽快把所有交付内容都接入“订单化” 如果再有修改, 怎么办? 内部实现个系统, 代理全部“订单化”相关的功能, 这样再有修改,只改这个代理服务就行了! 实现隔离变化!
19. 接到的重构任务: 订单代理(订单化)系统 实现 一个代理服务, 对接 交易平台组的订单系统和基础平台组的支付系统, 推动 若干个业务系统改造,改成调用新的代理服务。
20. 订单代理系统如何隔离变化
21. “同时满足”了业务需求和技术目标 业务需求:所有的商品都实现“订单化” 技术:不光都实现“订单化”,我们还实现个“订 单化的代理系统”,应对外部系统的变化。
22. 方案确定了! 但这是业务的目标吗?
23. 实现“订单化”并不是业务的真正需求 开发最关心的是 业务关心的是 完成全部商品的订单化, 一定要正确的交付(面向现在), 实现订单代理系统, 能够高效准确的算账(面向未来), 降低业务系统与外部系统的耦合 把过去的账给解释 清楚(面向过去) 订单代理系统的目标在财务那里只是个过程! 真正的业务需求是什么???
24. 面临的挑战 无路可退 :入职第一个任务 左右为难 :实现“订单代理系统”,满足不了业务需求! 不去实现“订单代理系统”,那该做什么?
25. 没有把握真正需求的原因
26. 领域驱动设计的工作方式 • 全程强调“领域”的开发过程 • 需求 = 问题域+业务期望 • 统一语言:领域通用语言 • 用领域模型指导设计及编码实现
27. 一定要正确的交付权益(面向现在) 能够高效准确的算账(面向未来) 把过去的账给解释 清楚(面向过去) • 问题域:电商的发货与算账 • 业务期望:精确交付
28. 理解“订单化”在需求中的作用和意义
29. 提炼和理解一些“统一语言”
30. 领域驱动设计,找到真正的业务需求 订单代理系统 财务核算级别的精确交付
31. 一. 用领域驱动来把握真正的业务需求 二. 领域驱动设计指导架构设计与建模 三. 用限界上下文来保护领域
32. 电商的基本业务模型 付钱 订单 收钱 卖货 算账 收货 签收 发货
33. “个体户”或“小商贩” 订单 收钱 卖货 算账 上货 发货
34. 订单代理系统架构的弊端 • 每个业务依然是个“小商贩”,相同功能的代码依然会重复 • 改成调用订单代理系统,交付数据的准确性依然达不到财务要求
35. 需求:财务核算级别的精确交付 “小商贩”模式能解决技术问题,但不能满足业务需求 交易领域中缺少 一个专注交付的子领域
36. 重新理解和确定了领域问题 • 得到后端的核心子领域问题:是“履约”,是交付 订单交付系统
37. 指导建模 :把握领域并识别限界上下文 • 目标:让业务方从“小商贩”入驻“超市”
38. 订单交付系统接管业务的交易行为
39. 订单交付系统满足了业务和技术的目标 卖货 收钱 发货 • 业务方不再是“小商贩”,入驻“超市”成为“卖家” • 交付的数据达到财务精准核算的要求 算账
40. 一. 用领域驱动来把握真正的业务需求 二. 领域驱动设计指导架构设计与建模 三. 用限界上下文来保护领域
41. 强调上下文的重要性 由机场“登机流程上下文”业务规则调度,和乘客去主动触发登机所需要的 动作,完全可以表现为两种设计,伪代码如下。 前者 登机流程上下文.排队(乘客) 登机流程上下文.安检(乘客) 登机流程上下文.摆渡(乘客,航班) 登机流程上下文.登机(乘客,航班) 后者 乘客.排队(机场) 乘客.我要安检(机场) 乘客.我要坐摆渡车(摆渡车) 乘客.我要上飞机(航班) 前者是有序的安全的,不会给机场制造意外,后者机场是不可控的。
42. 确定了领域和限界上下文后,就要保护 保护是手段 •目的:边界内的“完美世界”不可侵犯 •依据:边界,限界上下文内的规则
43. 这样保护了订单交付领域
44. 保护领域:规范可以进入上下文内的对象模型 进入机场上下文的时,“人物”要变为“乘客” 进入订单交付上下文的时,“业务对象”要变为“商品”
45. 保护领域:规范可以进入上下文内的对象模型 之前,进入各业务上下文的模型,由业务自己决定 客户端通过场景来判断该进入哪个业务上下文 If 听书 { 准备听书的参数(tid) ,请求听书的接口 } else if 课程{ 准备课程的参数(cid+ctype) ,请求对应的接口 } else if 电子书{ 准备课程的参数(bid) ,请求对应的接口 } else …… 课程 听书 电子书
46. 保护领域:规范可以进入上下文内的对象模型 老版本APP 新版本APP 商品模型 课程 ProductID ProductType 听书 网关转发 商品 商品 商品 防腐层 电子书
47. 保护领域:用领域事件解耦与其它上下文的关系 • 发布统一的领域事件;由外部系统的上下文来修改适配。
48. 保护领域:把握领域的职责 • 领域之外的事少管。节操币并不属于订单交付上下文内的商品。
49. 保护领域:把握领域的职责 • 领域之外的事少管。把节操币充值的交付,“让”给交易中心,
50. 保护领域:使用上下文隔离相同事物的不同内涵 • 之前,用户一次购买,却产生两笔订单
51. 保护领域:使用上下文隔离相同事物的不同内涵 • 一次购买,产生两笔订单的适用用场景 商家B 商家A 下单(订单B) 卖货 收钱 下单(订单A) 卖货 收钱 发货
52. 保护领域:使用上下文隔离相同事物的不同内涵 • 商城上下文 和 业务交互上下文 是合作关系,接力完成一笔订单的交付 卖货 收钱 发货
53. 保护领域:使用上下文隔离相同事物的不同内涵 • 商城同步的订单交付不再创建新订单
54. 保护领域:保护业务抽象行为的一致性 实现层面的设计
55. 保护领域:保护业务抽象行为的一致性 • 推进破坏“业务抽象行为一致性”的产品下线 • 某产品权益:有效期内可零元购买“得到”内容 • 所有购买场景,增加if……else…… • 破坏设计,污染代码
56. 保护领域:保护业务抽象行为的一致性 • 推进破坏“业务抽象行为一致性”的产品下线 财务和老板们确认 特殊的技术驱动 法务确认法律风险 产品经理修改规则 客服部门去面对用户
57. 结语1:DDD指导的设计建模带来的几个长尾收益 • 可以快速支持商城售卖各种商品 • 可以快速接入书单等多商品打包的购买 • 可以快速接入各种产品的赠送功能 • 客户端可以封装统一的结算台组件 • 从每月核查财务数据的工作中解放了 ……
58. 结语2:不要把DDD只当做一门技术来学习 ta可以是指导开发过程的方法论
61. 希望对大家有所启发!