DDD实战之五:战略设计之上下文映射和系统分层架构(下)

简介: DDD实战之五:战略设计之上下文映射和系统分层架构(下)

该服务序列图展示出,实际上“接龙”、“店铺”这 2 个上下文没有发生关联关系。但这个服务序列图设计,有个“坏味道”的感觉:让群买菜小程序客户端承担了过多业务逻辑,这是不合理的。于是,我们将服务序列图调整为如下:

image.png

该服务序列图会导致如下的 2 个上下文之间的关系:

image.png

确认接龙付款

确认接龙付款从产品界面原型可以看出,确认接龙付款是从“查看接龙详情”界面发起的。客户在该界面上点击相应的商品加入购物车、或从购物车移除,然后点击“我要接龙”按钮进入该用例。

该用例允许用户设置提货方式、提货时间、联系人等信息后,点击“确认付款”按钮完成支付。该按钮点击后,按照产品原型设计,需要完成如下任务:

  • 创建订单;
  • 更新关联商品的销量,以便于后续商品列表和详情页面显示商品销量;
  • 如果下单客户首次购买对应店铺商品,则为该店铺初始化对应客户资料,以便于商家后续维护客户资料;
  • 记录客户参与了该接龙,以便于客户“浏览我的接龙”时,可包含该接龙;

根据上面的逻辑,我们画出服务序列图设计如下:

image.png

该服务序列图展示的相关限界上下文关系如下图:

image.png

这里可以看到上下文之间的调用关系比较多,并且“订单”与“商品”、“订单”与“客户”之间,还存在数据一致性的要求,不利于系统的“松耦合”。为了降低上下文之间的耦合性,我们分析业务需求发现:其实“订单创建”后“增加商品销量”、以及“为指定店铺初始化客户”是可以有一定的数据延迟的,并不需要通过“强”服务调用关系保障严格的数据一致性。为此,我们将服务序列图修改如下:

image.png

根据改进后的服务序列图,可以调整上下文映射关系如下图:

image.png

结算订单收入

结算订单收入分为两步:第一步,在客户确认订单完成、或机器人超时自动确认订单完成时,订单上下文通知商家账户上下文记录待结算的订单 ID(由于订单上下文缺乏“判断什么订单属于待结算状态”这样的领域知识,故只能由商家账户上下文来记录);第二步,系统机器人定时触发商家账户上下文对待结算订单进行收入结算。服务序列图设计如下:

image.png

其中第一步的操作,可以和“发送订单提醒”中的“订单已完成”领域事件合并处理。不过,因为这里是不可丢失的领域事件,所以这就要求采用“可靠事件模式”。基于该服务序列图,识别出“订单”和“商家账户”上下文的关系如图:

image.png

结算佣金收入

结算佣金收入可以和结算订单收入同时进行,也可以分开在两个用例中异步执行。考虑到为了将来支持允许品牌商在加盟政策中设置结算周期,故将其分开在两个业务用例异步执行。为此,设计其服务序列图如下:

image.png

该序列图展示出商家账户和订单的上下文关系如图:

image.png

3限界上下文映射图

     

我们将上面针对各跨上下文业务用例分析后,得到的上下文映射关系进行汇总后最终得出下图:

image.png

图中实线是服务调用关系,属于“强关系”;虚线是消息通知关系,属于“弱关系”。

通过该限界上线文映射关系可以看出:我们总共有 9 个限界上下文,其中有强依赖关系的涉及到 9 个、强依赖关系链有 9 条。分别是:接龙依赖于店铺、商品和订单,店铺依赖于平台集成,订单依赖于商品,商家账户、员工、客户依赖于鉴权,商家账户依赖于订单。9 个上下文,理论上最多有 72 条依赖链条,我们分析汇总后只有 11 条,已经是很好的设计。

基于这样的综合评估,我们认为目前的设计已经到了“可接受程度”,暂时不再做更多的优化和调整了,以避免“过度设计”。

02系统架构和代码框架


1业务子域与上下文的映射

     

完成了限界上下文的关系映射,其实就有了对整体系统架构进行分层设计的基础。系统整体架构设计从分层角度来看,包括:边缘层、业务价值层、基础层。边缘层一般都是各种针对前端 UI 的控制器,业务价值层和基础层包含所有的限界上下文,其中基础层放的是对应到支撑子域、通用子域的限界上下文,而核心子域对应的限界上下文作为业务价值层。

为了区分业务价值层和基础层,我们先将前面得出的业务子域(见第三篇中全局分析内容)、与限界上下文进行如下表所示的关系映射:

image.png

需要说明的是:其中“商家管理”和“店铺管理”虽然是支撑子域,但由于分别被合并到“商家账户”、“店铺”上下文来开发实现,故其中逻辑的代码实现也被划分到了“业务价值层”。

2菱形对称架构简介

在对整个系统进行“分层架构设计”之前,我们还需要先熟悉一个软件架构模式——菱形对称架构(以下简称菱形架构),如下图所示:

image.png

对“菱形架构”的说明如下:

菱形架构的基础,是依赖于“领域层”的界定。这涉及到后面才会进行的 DDD 战术设计内容,这里不做展开,您只需要知道:“领域层”放的是业务领域的关键业务知识,包括“聚合(内含实体对象、值对象)”和“领域服务”两类内容。事实上,我们所追求的“高内聚”主要体现的“领域层”,因为业务需求变化而引起的变化,我也希望主要通过“领域层”的“聚合”和“领域服务”的变化来实现。所以说,“领域层”是 DDD 的“核心代码所在地”。

所有非“领域逻辑”层的代码,我们都希望封装到“北向网关”或“南向网关”中去。具体说明如下:

“北向网关”其实就是上下文向外提供服务、或接受消息通知的入口处。如果上下文只需要向外提供同一个进程内部的应用服务调用接口、或接受消息通知(通过消息总线),则需要“本地”服务;如果上下文需要作为独立进程(这时候一般是云原生的独立“微服务”)向外输出服务、或接受消息通知(通过消息中间件),则需要将“本地服务”包装为“远程”服务。

也就是说:北向网关中的“本地服务”和“远程服务”是一一对应的,“远程服务”只负责将远程调用的出入参做格式转换并传给“本地服务”,而“本地服务”负责调用领域层的“聚合”或“领域服务”来完成具体的业务逻辑(关于“聚合”和“领域服务”的内容,我会在本专题后面的章节中演示)。

“南向网关”其实就是上下文用来将这 3 类技术细节从业务逻辑中“剥离”出来的主要手段(图中只画了第一种):访问底层数据库、调用其它上下文服务、向其它上下文发布消息通知。这 3 个技术细节的封装,在 DDD 战术设计中分别叫“资源库”、“客户端(也可以叫防腐层——ACL)”、“消息发布者”。

从图中可以看出,“南向网关”有“端口”和“适配器”两种角色。简单点来说,“端口”是抽象接口(以 java 为例就是 interface),而“适配器”则是“接口实现”(以 java 为例就是实现了对应 interface 的类)。并且,一般来说“适配器”都是通过依赖注入(DI,控制反转 IoC 的一种)的方式集成到限界上下文的代码中(java spring 中一般是 bean 注入)。

“南向网关”区分“端口”和“适配器”两个角色的好处:一方面是可以让限界上下文内的任何代码都不直接依赖于具体的底层技术细节,如:采用哪种数据库(oracle 还是 mysql、甚至 nosql 数据库)、怎么调用其它上下文服务(本地调用还是远程 RPC)、怎么发布消息通知(本地消息总线、还是消息中间件);另一方面的好处是允许我们随时将构建在一个“微服务”甚至“单体应用”中的多个限界上下文进行拆分到多个进程(即多个“微服务”中),而并不会引起“领域层”、以及“北向网关”的任何代码修改(只要替换并重新打包被依赖注入的“适配器”类即可)。

很明显可以看出,“菱形架构”其实是限界上下文内部所采用的一个“软件架构模式”。而在整个系统范围内,因为包含多个限界上下文,DDD 设计理念并没有要求所有的上下文都严格遵循“菱形架构”——而完全可以根据实际需要(尤其是“基础层”的上下文),视情况而采用其它架构模式(如 MVC 三层架构、大数据计算架构等)。

3系统分层架构图

     

有了前面的将上下文分为“基础层”和“业务价值层”、以及菱形架构概念的基础,再考虑到“群买菜”系统前端界面针对 3 类用户:商家、客户、平台运营,前两者使用微信小程序,最后一个使用 PC 端,以及相应“伴生系统”的协作边界。我们最后画出系统架构分层设计图如下:

image.png

对于上图,需要特别说明的是:

其中腾讯地图、短信系统、微信公众号因为不涉及到业务流程,只是一个功能点,故前面的业务子域、上下文、业务用例都没有展现。

有的上下文有“事件订阅”。这是根据我们前面“限界上下文映射图”中的描述,需要进行消息订阅的上下文才有。

其中比较特殊的一点:“平台集成上下文”没有“领域层”,这是因为它主要完成对微信公众号接口、短信接口、微信开放平台接口的封装,并不存在 DDD 战术设计所需要的“实体”对象这一“领域层”必须的基本要素。

4代码框架结构    

基于前面的系统分层架构设计,结合菱形架构模式,我们给出目标系统的如下代码框架结构(采用 java spring 框架开发):

image.png

对上图中各目录的划分和命名说明如下:

foundation 目录存放的是“基础层”限界上下文,valueadded 目录存放的是“业务价值层”限界上下文,edge 目录存放的是“边缘层”限界上下文;

本质上,每个限界上下文都可以作为独立的 java 工程存在。但因为本项目由我一个人开发,所以就没有划分工程了;

每个限界上下文,采用“上下文名称+context”命名风格。如:“订单上下文”命名为 ordercontext;

每个限界上下文中,其内部目录结构说明如下:

  • north 目录存放的是“北向网关”的内容,包括 local 和 remote 子目录,分别对应北向网关的“本地服务”和“远程服务”。有的上下文的 north 目录下有 subsrciber 子目录,是为了存放消息订阅者代码的。
  • south 目录存放的是“南向网关”的内容,包括 port 和 adapter 子目录,分别对应南向网关的“端口”和“适配器”。
  • domain 目录存放的是“领域层”内容,也就是核心的业务逻辑所在。
  • pl 目录存放的是“发布语言”,其实就是北向网关的“本地服务”向外提供服务时,允许外部调用服务所使用的出入参对象类型。之所以将出入参对象类专门设定一个目录来管理,是因为这些出入参其实是和 domain 目录下的“实体类”是不同的,我们不希望将“领域层”内部的业务逻辑暴露出去(也就是不将“实体类”的业务逻辑暴露出去)。
  • 业务价值层有个 sharedcontext,这是因为考虑到代码复用、可能会出现某些“值对象”、“发布语言(即服务接口出入参)”类被多个上下文共用,具体细节我在后面的战术设计中会讲到。

对于“群买菜”系统来说,由于小程序前端界面已经存在,本次是服务端做 DDD 改造,故不打算对前后端交互接口进行调整。为此,我为其设计了“边缘层”,也就是 BFF 层。这就是 edge 目录存放的代码内容。

好了,本节作为“群买菜”系统 DDD 战略设计的第二篇,就先到这儿。下节我们将完成战略设计的最后一步:相关战略技术决策。

相关文章
|
10天前
|
监控 安全 API
使用PaliGemma2构建多模态目标检测系统:从架构设计到性能优化的技术实践指南
本文详细介绍了PaliGemma2模型的微调流程及其在目标检测任务中的应用。PaliGemma2通过整合SigLIP-So400m视觉编码器与Gemma 2系列语言模型,实现了多模态数据的高效处理。文章涵盖了开发环境构建、数据集预处理、模型初始化与配置、数据加载系统实现、模型微调、推理与评估系统以及性能分析与优化策略等内容。特别强调了计算资源优化、训练过程监控和自动化优化流程的重要性,为机器学习工程师和研究人员提供了系统化的技术方案。
130 77
使用PaliGemma2构建多模态目标检测系统:从架构设计到性能优化的技术实践指南
|
3天前
|
机器学习/深度学习 算法 数据可视化
基于深度混合架构的智能量化交易系统研究: 融合SSDA与LSTM自编码器的特征提取与决策优化方法
本文探讨了在量化交易中结合时序特征和静态特征的混合建模方法。通过整合堆叠稀疏降噪自编码器(SSDA)和基于LSTM的自编码器(LSTM-AE),构建了一个能够全面捕捉市场动态特性的交易系统。SSDA通过降噪技术提取股票数据的鲁棒表示,LSTM-AE则专注于捕捉市场的时序依赖关系。系统采用A2C算法进行强化学习,通过多维度的奖励计算机制,实现了在可接受的风险水平下最大化收益的目标。实验结果显示,该系统在不同波动特征的股票上表现出差异化的适应能力,特别是在存在明确市场趋势的情况下,决策准确性较高。
20 5
基于深度混合架构的智能量化交易系统研究: 融合SSDA与LSTM自编码器的特征提取与决策优化方法
|
4天前
|
机器学习/深度学习 前端开发 算法
婚恋交友系统平台 相亲交友平台系统 婚恋交友系统APP 婚恋系统源码 婚恋交友平台开发流程 婚恋交友系统架构设计 婚恋交友系统前端/后端开发 婚恋交友系统匹配推荐算法优化
婚恋交友系统平台通过线上互动帮助单身男女找到合适伴侣,提供用户注册、个人资料填写、匹配推荐、实时聊天、社区互动等功能。开发流程包括需求分析、技术选型、系统架构设计、功能实现、测试优化和上线运维。匹配推荐算法优化是核心,通过用户行为数据分析和机器学习提高匹配准确性。
24 3
|
2天前
|
监控 Java 数据中心
微服务架构系统稳定性的神器-Hystrix
Hystrix是由Netflix开源的库,主要用于微服务架构中的熔断器模式,防止服务调用失败引发级联故障。它通过监控服务调用的成功和失败率,在失败率达到阈值时触发熔断,阻止后续调用,保护系统稳定。Hystrix具备熔断器、资源隔离、降级机制和实时监控等功能,提升系统的容错性和稳定性。然而,Hystrix也存在性能开销、配置复杂等局限,并已于2018年进入维护模式。
11 0
|
2天前
|
前端开发 搜索推荐 安全
陪玩系统架构设计陪玩系统前后端开发,陪玩前端设计是如何让人眼前一亮的?
陪玩系统的架构设计、前后端开发及前端设计是构建吸引用户、功能完善的平台关键。架构需考虑用户需求、技术选型、安全性等,确保稳定性和扩展性。前端可选用React、Vue或Uniapp,后端用Spring Boot或Django,数据库结合MySQL和MongoDB。功能涵盖用户管理、陪玩者管理、订单处理、智能匹配与通讯。安全性方面采用SSL加密和定期漏洞扫描。前端设计注重美观、易用及个性化推荐,提升用户体验和平台粘性。
13 0
|
17天前
|
弹性计算 API 持续交付
后端服务架构的微服务化转型
本文旨在探讨后端服务从单体架构向微服务架构转型的过程,分析微服务架构的优势和面临的挑战。文章首先介绍单体架构的局限性,然后详细阐述微服务架构的核心概念及其在现代软件开发中的应用。通过对比两种架构,指出微服务化转型的必要性和实施策略。最后,讨论了微服务架构实施过程中可能遇到的问题及解决方案。
|
26天前
|
Cloud Native Devops 云计算
云计算的未来:云原生架构与微服务的革命####
【10月更文挑战第21天】 随着企业数字化转型的加速,云原生技术正迅速成为IT行业的新宠。本文深入探讨了云原生架构的核心理念、关键技术如容器化和微服务的优势,以及如何通过这些技术实现高效、灵活且可扩展的现代应用开发。我们将揭示云原生如何重塑软件开发流程,提升业务敏捷性,并探索其对企业IT架构的深远影响。 ####
40 3
|
1月前
|
Cloud Native 安全 数据安全/隐私保护
云原生架构下的微服务治理与挑战####
随着云计算技术的飞速发展,云原生架构以其高效、灵活、可扩展的特性成为现代企业IT架构的首选。本文聚焦于云原生环境下的微服务治理问题,探讨其在促进业务敏捷性的同时所面临的挑战及应对策略。通过分析微服务拆分、服务间通信、故障隔离与恢复等关键环节,本文旨在为读者提供一个关于如何在云原生环境中有效实施微服务治理的全面视角,助力企业在数字化转型的道路上稳健前行。 ####
|
16天前
|
Java 开发者 微服务
从单体到微服务:如何借助 Spring Cloud 实现架构转型
**Spring Cloud** 是一套基于 Spring 框架的**微服务架构解决方案**,它提供了一系列的工具和组件,帮助开发者快速构建分布式系统,尤其是微服务架构。
130 68
从单体到微服务:如何借助 Spring Cloud 实现架构转型
|
18天前
|
设计模式 负载均衡 监控
探索微服务架构下的API网关设计
在微服务的大潮中,API网关如同一座桥梁,连接着服务的提供者与消费者。本文将深入探讨API网关的核心功能、设计原则及实现策略,旨在为读者揭示如何构建一个高效、可靠的API网关。通过分析API网关在微服务架构中的作用和挑战,我们将了解到,一个优秀的API网关不仅要处理服务路由、负载均衡、认证授权等基础问题,还需考虑如何提升系统的可扩展性、安全性和可维护性。文章最后将提供实用的代码示例,帮助读者更好地理解和应用API网关的设计概念。
47 8
下一篇
DataWorks