当前位置:主页 > 查看内容

预算管控服务(库存和产品账平台)的DDD设计案例

发布时间:2021-06-09 00:00| 位朋友查看

简介:一.?背景 ?????本文预算管控服务建设作为一个DDD设计的例子介绍 目标是是呈现一次DDD设计的过程 为了减少绘图和描述的工作量 文中会对预算管控业务需求和功能做简化。请重点关注设计的流程 这是我们想传达的重点 忽略设计细节的合理性。 另外 对于预算管控服……
一.?背景

?????本文预算管控服务建设作为一个DDD设计的例子介绍 目标是是呈现一次DDD设计的过程 为了减少绘图和描述的工作量 文中会对预算管控业务需求和功能做简化。请重点关注设计的流程 这是我们想传达的重点 忽略设计细节的合理性。

另外 对于预算管控服务来讲 不一定要用DDD来进行分析设计 基于传统的数据驱动就完全可以满足需求 但作为介绍DDD实施过程 预算管控是一个不错的例子 不需要画太多的图 。在这里我们不讨论什么类型项目合适DDD 可以参考

大致的共识为复杂度高的业务适合DDD。而复杂度一般体现在

业务流程长

业务场景多

业务概念多

业务系统干系人多

业务系统需要长期维护且持续有变更

业务背景

需要设计一个适用于本地生活场景的资源预算规划和管控服务 业务需求上主要包括两方面的用例

品牌发放权益需要有一定的限额 不能无限制的发放。包括品牌、门店、活动、人群、权益等维度个人消费者参与活动领取权益有次数的限制 不能无限额领取或使用。包括在活动、品牌、门店、商品等维度

目前各业务线针对以上需求 各自实现了部分能力 整体上看较零碎、不完善、不统一。本次目标是设计一个统一的平台为各业务方提供基础能力

二.?战略设计2.1?业务梳理2.1.1?业务定位 目标分析

协同分析阶段 需要各干系方共同参与 如 业务运营 业务产品 运营产品 平台架构 业务系统方的技术等。

目标 聚焦业务需求和平台定位 确定平台的能力范围和服务方式

输出需求文档

提供一个统一的记账能力 以平台的方式为各个系统提供记账服务。

主要功能

记账销账各维度的查账库存创建库存扣减、查询库存缩扩容

细化要求

作为平台能为客户提供逻辑上的数据隔离 即A产品方默认不能访问B产品方数据。如需要访问需要经过授权同意作为平台需要提供同步记账能力和异步记账能力 并提供明确的“能力范围”承诺作为平台需要为产品方提供方案避免重复记账除记账之外 需要提供对应的销账能力需要提供常用的记账周期 账期 如时账 日账 周账 月账 季度账 年度账 终身账。需要提供自定义记账周期 账期 的能力需要提供一单多账记账能力 即一张单据 需要同时记录日账和终身账需要提供多维度的查账能力 如按产品方 记账主体 产品 账期时间 以及基于这些维度的组合条件查账需要提供批量查账能力 如主体下单一产品的批量账期时间 主体下的批量产品的单一账期时间 及其它可能的批量组合技术上需要保证账单存储和记账动作的事务技术上需要保证分库分表的数据存储均衡性技术上需要尽量保证分库分表的数据库读写均衡分布 对可能出现的数据倾斜场景 需要给出明确的说明 和使用限制性规范能提供性能基准承诺 由测试团队对典型场景压测给出《平台性能报告》 作为平台对外服务的一部分库存的创建 扣减 查询 扩容 缩容 缩容量不能少于剩余库存 库存冻结 解冻库存管理

主要功能

库存创建库存扩容库存缩容库存扣减库存回补库存查询

细化要求

满足去UMP的所有要求 去UMP为一个内部项目 各种限定型规则在此不细列 2.1.2?业务抽象可视化

通过事件风暴或四色建模法来可视化。我们这里选择事件风暴法。过程主要涉及

识别领域名词 示意 不包括全部

识别领域命令 示意 不包括全部

这里列了主要的命令

场景分析

主要是识别发出命令的主体是谁 如C端消费者 B端消费者还是某个系统。主要是通个主体在具体Usecase中去串联命令对于领域对象 对应领域名词 的影响。串联业务流程完成领域分析

识别领域事件

在命令发出后对一个领域对象 聚合根 将产生影响 往往对内 聚合根 会生成数据或发生状态变更 对外 向其他聚合根 发送消息或触发事件。

这些事件是业务专家重点关心的结果

这里是先识别领域事件 还是先识别命令可以根据设计者的习惯和熟悉度 自行选择

最后 整合命令 领域对象和领域事件的关系 得到业务梳理的输出文档 实际命令可能比图中多 如库存冻结和预扣等

2.2?统一领域语言 示意 不包括全部

2.1章中几个阶段是一个来回讨论的阶段 通常需要经过很多轮的修改和妥协 以至于早期列出的领域名词、领域事件和命令远多于上面的图例 但最后大家需要统一确定其中关键的领域名词、领域事件 并统一领域语言 在后续的讨论和设计阶段均使用统一语言建模。这里我们用下面的统一语言仅示例产品账

术语

描述

记账主体 principal mainPrincipal subPrincipal

记账主体 id 如 抽奖活动中的消费者记账 则为cid

账单 accounting?document accounting?doc

名词 一次记账请求提交的数据为一条记录。指产品方提交给记账平台的原始单据数据

记账 keep?account

动词 记录record的过程

销账 write?off?account

动词组 记账的反向操作

金额(amount)

记账的数量

账(account)

按账期?统计的在该周期内的数额总和相关数据

账期(account?cycle)

账期 会计周期 的类型 如 日账 月账 终身账等

账期值(account?cycle?value)

账期值。如对于自然日类型的账期 账期值可以是“20210415”代表4月15这天的账

记账类型(operate?type)

操作类型指 记账或销账

2.3?限界上文识别

最后 当领域名词、领域事件和命令都统一并清理好之后 我们需要圈定合适领域出来 这里要注意 并没有统一的最佳答案 圈定原则只是遵循现实世界的松紧耦合关系 某些场景下可能有多种选择 本例较简单 示例如下

2.4?问题子域识别

在战略设计阶段的最后 按“一个子域负责解决一个独立业务价值的问题”的原则 将限界上下文划分到不同的问题子域 Subdomain 中 同时还需要从更大的域视角来俯览全局 并按照以下三种类型进行标注

核心域 Core?Domain 是当前产品的核心差异化竞争力 是整个业务的盈利来源和基石 如果核心域不存在 那么整个业务就不能运作。对于核心域 需要投入最优势的资源 包括能力高的人 和做严谨良好的设计。通用子域 Generic?Subdomain 该类问题在界内非常常见 所以很可能有现成的解决方案 通过购买或简单修改的方式就可以使用。支撑子域 Supporting?Subdomain 该类问题解决的是支撑核心域运作的问题 其重要程度不如核心域 又不属于通用子域 具备强烈的个性化需求 难以在业内找到现成的解决方案 需要专门的团队定制开发

问题子域 是对业务问题的进一步澄清和划分 同时也是对于资源投入优先级的重要参考 相对限界上下文来说 问题子域是对业务问题更大粒度的划分 是在限界上下文识别后与问题域匹配的一个过程。

通过对于子域进行识别、划分和类型标注 团队能够实现软件架构在业务边界上的内聚和解耦 便于逆向应用“康威定律”。

在?DDD?的概念中 限界上下文和问题子域是两个不同维度的概念 限界上下文可能只是真实问题子域的一部分表达 也可能限界上下文中的一些领域名词超出实际问题子域的范围 理论上来说没有绝对的依赖关系。需要根据实际需求和成本综合考虑 既要保证便资源分配的合理 又要在降低落地成本的同时保证后期演进的适度兼容。

问题子域识别过程的产出物 如下图所示

2.5?限界上下文映射 示意 不包括全部

这里只示例产品账的。明确限界上下文映射关系 是为了更明确各context之间的关系 在IDDD中给出了9种关系 在本例种只涉及到3种 实际项目中可能比这个复杂的多 尤其是涉及集成和遗留系统的场景。

明确contex之间关系 有助于后续保证系统之间的依赖关系 为后续架构模式的补充模块做好准备。

三.?战术设计3.1领域建模3.1.1?领域对象提取 聚合/实体识别

偷个懒 这里只示意产品账的实体和部分值对象

3.2?业务服务识别

业务服务识别 是为后续系统实现进行的基于业务边界的模块拆分分析 常见的拆分方法有

基于限界上下文进行拆分 每个限界上下文为一个服务 优点是每个服务都很小 代码量少 缺点是拆分粒度太细 导致服务数量过多 增加架构设计的复杂度和运维成本。基于子域进行拆分 每个子域为一个服务 优点是服务数量相对较少 架构复杂度和运维成本相对更低 缺点是拆分粒度在某些场景下会非常大 导致单个服务变成“小单体” 增加开发成本和代码分层复杂度。

通过对于业务服务进行划分 团队能够获得对软件架构模块拆分的直接指导 并且还能够依据“逆康威定律”依据架构结果进行开发团队的划分和组建。

下面是预算管控子域的服务拆分示例

子域

服务

预算管控子域

库存服务

产品账服务

3.3?业务服务接口识别

单独对业务服务的接口能力进行识别 是符合面向接口编程原则的 提前定义服务的概要设计方案 可以让后续团队成员更快开展工作 也方便后续接口的详细设计

这里提前识别服务接口 是为了避开技术实现细节的影响。我们在基于具体技术实现的情况下设计接口 通常会干扰领域驱动的设计。我们试想下基于swagger文档 设计API时 我们是否容易保证API的归属正确领域服务。所以提前的概要识别和设定很重要

下面是库存和账服务接口识别示例

子域

聚合根/实体

接口能力

读写

账上下文

账单

记账

账本

单主体单产品单账期查账

单主体批量产品单账期查账

库存上下文

库存

创建库存

扣减库存

缩扩容库存

查询库存

四.?技术实现

在完成了战略设计和战术设计之后 就可以考虑具体的技术详设 这个阶段会设计到具体的架构模式选择 架构风格和基础技术 存储等的选择。

包括且不限于

架构风格选择 单体 soa 微服务 restful rpc webservice ODATA等架构模式选择 传统分层 六边形 简洁 洋葱等补全组件 如rpc客户端 mtop gatway acl等 这里要分清应用层 基础设施和领域技术框架选型 技术栈 服务治理体系API设计 openapi swagger blueprint等领域模型类设计 参考领域模型设计类图持久化选择 这里要考虑哪些需要存储RDB 哪些用Nosql 哪些只需要内存中。在上例产品账中的账本就不需要持久化应用层设计模式选择 因应用需要 或运营策略需要支持能力要考虑合适的模式支持考虑其他需求的实现 易测试性 性能 易维护和运维 安全等

在本例里只示例产品账的领域模型参考

?

其中账本 accountbook 不需要持久化 其他领域对象均需要持久化

五.?总结

最后需要时刻提醒的。没到最后实现阶段之前应该杜绝提前考虑技术细节和技术实现 否则很容易偏离DDD


本文转自网络,原文链接:https://developer.aliyun.com/article/784607
本站部分内容转载于网络,版权归原作者所有,转载之目的在于传播更多优秀技术内容,如有侵权请联系QQ/微信:153890879删除,谢谢!

推荐图文

  • 周排行
  • 月排行
  • 总排行

随机推荐