从技术债务到架构升级,滴滴国际化外卖的变革

c6d5408f7cbc5e2f87eca3bf2b9d4ee2.gif

背 景

82117221e394557f5567ae81a522a8e9.gif

商家营销简述

c2fd876f5c6e1e6279da793078e707d6.png

在外卖平台的运营中,我们致力于通过灵活的补贴策略激励商家,与商家共同打造良好的合作关系,也会提供多样化的营销活动,帮助商家吸引更多用户下单。通过这些活动,不仅能够提高商家的销量,还能让用户感受到实际的优惠,从而增强他们对平台的粘性。

7b56ce3baed28ebc8c2fcc0d7996d229.gif

前端技术特点

业务特点:营销场景玩法多、活动类型多、活动链路长、活动规则复杂。

中后台技术特点:活动配置表单规则多、联动复杂。

前台技术特点:终端类型多(PC/EXE/PAD/PHONE)、代码重复度高、用户输入校验规则复杂。

业务技术架构

0d0fae11da1b917020a91c0c1d4f8a00.png

活动链路

1460a94546612b24e2b99ba65af57640.png

商家营销相关项目迭代时间较长,积累的历史技术债务越来越多,结合业务背景和以上的技术特点,之前对历史项目进行过一波代码治理,比如:多端代码复用、后台复杂度治理等。    

2023年的治理更多解的是代码重复及腐化相关的问题,而外卖商家营销活动的配置能力还处于非常基础的阶段,2024年,我们结合业务新诉求的契机,从系统架构治理维度,对商家营销前端项目做了一个全面的升级。

34482a6fef815996e73680f0b336cc93.gif

现状

外卖商家营销活动,按活动来源区分主要有四大类:平台招商、代运营、品牌代建、商户自营销,按类型区分主要有四大类:特价菜、买赠、免配、满减。前后端底层区分这些活动渠道及类型都是case by case的形式,以招商活动创建为例:

不同活动类型,优惠信息都放在不同的字段里,特价菜是specialItemRule,免配是freeDeliveryRule,满减是reductionRule,买赠是buyGiftsRule,且规则rules字段层级嵌套冗余,字段属性没有规律可循,以下列举了两类活动的部分字段。

特价菜活动规则字段示例

"specialItemRule": [{"rulePurposeType": 0,"rules": [{"type": 3,"content": {"discountValueRange": null,"discountValueList": [10, 11, 20],"discountType": 1}}],"selectItemNumRange": {"min": 1,"max": 10},"itemPromoRangeValue": {"min": 1,"max": 50},"picLimit": 1,"priceLimit": null,"itemType": 0,"checkItemPriceDay": 7}]

满减规则字段示例

"reductionRule": [{"rulePurposeType": 0,"rules": [{"type": 1,"content": {"threshold": 10,"discount": 5}}, {"type": 1,"content": {"threshold": 20,"discount": 8}}]}]

9412be4aeb911e93a361df51e7d928a6.gif

面临的挑战

2024年随着国际化外卖营销业务需求明显增长,比如:需要从0到1搭建连锁品牌商家自运营能力、拓展新的营销活动类型(商家券),按照现有的架构及配置能力来看,存在以下几个问题:

  • 产品需求迭代支撑效率低:涉及通用字段,需要重复修改,特价菜+免配+满减+买赠,4种活动类型改4次,如果再算上活动渠道修改,需要再翻倍,4种渠道✖️4类活动 = 16 次。

  • 开发遗漏:活动链路长,以当前最为复杂的招商活动为例,从运营后台配置招商计划=>商户前台报名招商活动,是一个较长的链路,由于系统数据模型不够灵活,导致修改字段及UI展示时无规律可循,经常需要梳理遗漏点。

  • 可拓展性差:当前架构下,如果新增活动类型,则涉及全链路所有接口改动,可复用性低。

由于业务发展的契机,国际化外卖商家侧需要新增一个连锁品牌管理端,借助这个项目,我们进行了商家营销架构的升级。

88f537892ee5352b86fb544f735b2124.gif

解决方案

fff062f372f34617752d692421443699.gif

问题分析

商家营销配置能力薄弱主要体现在底层数据结构缺乏通用性和扩展性。

从全局配置维度来看:

4e3e82c6c7a5e919b9d61c70a2779e3b.png

从数据结构现状来看:

28277721b6e689a0dbe8b84da36a584e.png

  • 同一类活动,在不同平台(端、后台)数据结构不一致。

  • 同一类活动,在不同活动来源场景下(自营销、招商、代运营、品牌),数据结构不一致。

  • 四类活动,活动规则数据结构不一致,创建需要case by case拼装,详情需要case by case渲染。

  • 差异化分支共有:自营销创建4 + 招商报名4 + 招商计划4 + 代运营1 + 品牌4 = 17

bba6deab74a8bae8e4593c08c58fdbfc.gif

整体思路

架构治理最重要的一环就是设计出一个统一的活动数据模型,涵盖所有平台和活动来源场景。

67cff1624fb4aa1263b95a07036d17cd.png

  • 抽象活动实体信息

  • 统一差异化配置

  1. 按活动信息维度拆分组织字段,而不是按业务维度拆分(收敛类型、来源)。

  2. 按通用字段概括优惠类型,而不是按业务概念枚举(收敛规则)。

  • 支持灵活拓展

fe6ab9894837482b39043764d8548b87.gif

项目成果

在抽象出活动配置模型后,为保证后续需求或者人员变更能够按照规范持续迭代,通过对应的配置模型的API文档,配套前端JSON Schema校验工具,约束后续拓展。

底层数据结构完成治理后,在新项目中,我们也对配置表单方案进行了优化,使得项目的数据流转更加清晰,确保数据的一致性和可靠性。

而在前后端交互层面,对接口字段进行了运行时校验,做到了接口安全约束,避免因数据缺陷而导致的前端错误。

934da6bab9adc7d3e22c023f72e37ef7.gif

数据结构对比

新版活动数据结构是一个面向对象的设计架构,采用组合式领域模型设计,通过策略模式实现业务规则的动态装配。

基础活动模型(ActInfoModel)可以被视为一个父类或者超类,定义了通用的属性和行为,而其子类(如自营销活动模型selfOpsModel)继承了基础特性,并可以实现或者重写一些特定的功能,以满足不同渠道的具体需求。

当出现新的渠道或者活动类型时,只需要创建新的子类,遵循现有的父类结构。而基础模型的修改也不会影响所有子类,只需要确保子类能够适应父类的接口变化即可。

bb9b8e6f23b81d998fe7ced944345bcf.png

07bb9ae91e5f0bcc9241d8b4dfc1cc55.gif

配置表单方案优化

在之前的项目里,表单间的组件通信,是传统多层组件的数据传递形式,通过父子组件层层传递。

d50236d151224f79dfacc516320a80cb.png

数据流:自上而下,每个组件都需要通过props接受和传递数据。

缺点:增加了代码复杂性,每个组件都需要显式传递数据,容易出现冗余代码和数据同步问题。

这种形式对于简单的表单场景来说,比较直观,但是对于商家营销活动配置场景来说,在过往需求迭代中出现了维护困难和数据同步异常的问题,在新项目里,我们使用了配置模型+依赖注入的表单方案。

3e6e565e1e840f2950321a888ed37218.png

数据流: 数据通过依赖注入在组件树的各层之间传递,子组件直接获取所需数据

优点: 降低了组件之间的耦合性,减少了多层传递的冗余性,数据更加集中且易于管理

数据流转对比

ca949fb9baec1ef25f85c238970be44b.png

使用配置模型 + 依赖注入的方式不仅可以简化数据流转,还能实现集中管理,减少代码冗余,提高数据一致性,更容易进行维护和调试,特别是在需要动态配置或复杂业务逻辑的场景下表现尤为突出。

84ab7ce00545421977ab6e4067b8e0ea.gif

接口安全保障

当前数据安全问题

为了避免接口数据异常,导致前端页面白屏,我们通常会在代码中加一些字段兜底逻辑,这样带来的问题:

  • 冗余的兜底逻辑:在组件中,使用“||“操作符、可选链和解构默认值等方式进行兜底处理,导致同样的逻辑在多个地方反复出现。

  • 复杂的数据结构处理:对于复杂的数据结构,通常为了某个字段兜底会出现一大坨繁琐的代码,影响代码可读性与代码效率。

  • 数据类型安全问题:常规兜底形式无法保证数据类型安全,可能造成不符合预期的类型错误,进而引发应用程序中的逻辑错误或页面崩溃。

在抽象出活动配置模型后,活动配置的定义是由标准的JSON Schema描述组成的,在这个基础上,我们定义一些校验及默认填充规则,并引入集中式的兜底机制,在接口数据返回时,调用一个校验工具函数,实现统一的兜底策略。校验工具函数是借助zod这个工具库去实现的。

招商活动配置描述示例

// 招商活动规则
export const SignUpActRuleSchema = ActRuleSchema.extend({selectNumRange: z.object({min: z.number().default(0),max: z.number().default(0),}).default({ min: 0, max: 0 }),actType: z.union([z.number(), z.string()]).default(0),rule: z.array(SignUpRuleSchema).default([]),
})
export type SignUpActRule = z.infer<typeof SignUpActRuleSchema>// 招商活动详情页接口信息
export const SignUpDetailSchema = z.object({actRule: SignUpActRuleSchema.default({}),actInfo: SignUpInfoSchema.default({}),shopJoinInfo: z.array(ShopJoinInfoSchema).default([]),
})

‍接口返回处理示例

// 招商活动详情接口
// useApiSchema是统一的返回数据校验工具函数
export async function getSignUpDetail(params: object = {}): Promise<SignUpDetail> {const response = await post(GET_SIGN_UP_DETAIL, params, { returnData: false })return useApiSchema<SignUpDetail>(SignUpDetailSchema, response.data, response.traceId)
}

useApiSchema函数功能包含:数据校验、兜底数据填充、埋点上报。

接口返回字段中若出现返回数据类型错误或者未返回的情况,将返回自定义的默认值从而保障页面正常展示,对于错误数据也做了埋点上报,当到达一定阈值时会进行报警。

adb9b15fda60921b770d3c3278956f60.gif

效率提升

日常迭代

活动配置模型通过字段的抽象和整合,大幅提升了字段扩展的效率。原本因各活动类型和场景的数据结构差异,需要在多处修改数据结构和组件逻辑的场景,现在只需在一处进行修改即可,大大提高了开发效率。

以前台项目活动规则相关迭代为例:

4858dd86d23322be33302e9329c463a3.png


开发实例

以近期需求为例,我们需要新增一种券活动类型,通过采用活动配置模型和集中式状态管理的开发形式,使得开发过程中对于数据相关的处理逻辑与状态管理要比之前简易很多,开发效率提升约40%

04d7fafaf3282e0b3783108acf8f7ee7.gif

后续规划

以上架构治理都是针对新的项目去做的实践,而对于国际化外卖商家营销前端的其他项目同样需要做架构升级改造,后续我们计划收敛运营后台的活动配置,将最为复杂的招商活动链路进行标准化,后台配置=>前台应用,引用同一套数据模型。

国际化外卖商家营销前端架构预期

a6c24bc92116ebd99be0d3fb39609f96.png

b10055791bb59e1e007aeb8aaf1e116b.gif

往期文章回顾

fe660ffc84f9eb75fefe6f055703fa93.png

ace4c42c6569082cb8cc5190b6141698.gif

致谢

核心开发:杜雨轩、闫莉

关键合作方:宋亚阁、陈珏、吴召学

项目指导:董亚杰

整体方案的产出到落地实践离不开以上同学的辛苦付出,借此机会表示由衷感谢!同时,也非常感谢能够耐心阅读到这里的读者,业务技术架构治理是一个持续的过程,需要持续的关注、投入与调整,也需要与业务深度融合,以实现业务与技术目标的双赢。

欢迎感兴趣的同学拍砖指导,一起交流讨论!小编将选取5位同学,送上20W无线充电器!

934d351de39d12cf0b6e8c4c40b448cd.jpeg

//  E N D //

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/18758.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Redis系列】Redis安装与使用

???欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学习,不断总结,共同进步,活到老学到老…

Spring Boot中如何自定义Starter

文章目录 Spring Boot中如何自定义Starter概念和作用1. 概念介绍2. 作用和优势2.1 简化依赖管理2.2 提供开箱即用的自动配置2.3 标准化和模块化开发2.4 提高开发效率2.5 提供灵活的配置覆盖3. 应用场景创建核心依赖1. 确定核心依赖的作用2. 创建 starter-core 模块2.1 依赖管理…

【触想智能】工业显示器和普通显示器的区别以及工业显示器的主要应用领域分析

在现代工业中&#xff0c;工业显示器被广泛应用于各种场景&#xff0c;从监控系统到生产控制&#xff0c;它们在实时数据显示、操作界面和信息传递方面发挥着重要作用。与普通显示器相比&#xff0c;工业显示器在耐用性、可靠性和适应特殊环境的能力上有着显著的差异。 触想工业…

Deepseek R1模型本地化部署+API接口调用详细教程:释放AI生产力

文章目录 前言一、deepseek R1模型与chatGPT o1系列模型对比二、本地部署步骤1.安装ollama2部署DeepSeek R1模型删除已存在模型&#xff0c;以7b模型为例 三、DeepSeek API接口调用Cline配置 前言 随着最近人工智能 DeepSeek 的爆火&#xff0c;越来越多的技术大佬们开始关注如…

ML.Net二元分类

ML.Net二元分类 文章目录 ML.Net二元分类前言项目的创建机器学习模型的创建添加模型选择方案训练环境的选择训练数据的添加训练数据的选择训练数据的格式要预测列的选择模型评估模型的使用总结前言 ‌ML.NET‌是由Microsoft为.NET开发者平台创建的免费、开源、跨平台的机器学习…

Seaweedfs(master volume filer) docker run参数帮助文档

文章目录 进入容器后执行获取weed -h英文中文 weed server -h英文中文 weed volume -h英文中文 关键点测试了一下&#xff0c;这个-volume.minFreeSpace string有点狠&#xff0c;比如设置值为10&#xff08;10%&#xff09;&#xff0c;它直接给系统只留下10%的空间&#xff0…

【系统架构设计师】虚拟机体系结构风格

目录 1. 说明2. 解释器体系结构风格3. 规则系统体系结构风格4. 例题4.1 例题1 1. 说明 1.p263。2.虚拟机体系结构风格的基本思想是人为构建一个运行环境&#xff0c;在这个环境之上&#xff0c;可以解析与运行自定义的一些语言&#xff0c;这样来增加架构的灵活性。3.虚拟机体…

ROS学习

1.ROS工作空间 存放项目开发相关文件的文件夹&#xff1b; src:代码空间&#xff08;Source Space&#xff09;install:安装空间&#xff08;Install Space&#xff09;build:编译空间&#xff08;Build Space&#xff09;log:日志空间&#xff08;Log Space&#xff09; 2.c…

【vue3】实现pdf在线预览的几种方式

今天一天对当前可用的pdf预览插件做了测试&#xff0c;主要需求是只能预览不能下载&#xff0c;但对于前端来说&#xff0c;没有绝对的禁止&#xff0c;这里只罗列实现方式。 目前采用vue3版本为&#xff1a;3.2.37 iframevue-officepdfjs-dist iframe 先说最简单的&#xf…

Springboot中使用Elasticsearch(部署+使用+讲解 最完整)

目录 引言 一、docker中安装Elasticsearch 1、创建es专有的网络 2、开放端口 3、在es-net网络上安装es和kibana 4、可能出现的问题 5、测试 6、安装IK分词器 7、测试IK分词器 二、结合业务实战 1、准备依赖 2、配置yml 3、读取yml配置 4、准备es配置类 5、编写测…

文件夹上传到github分支最后github上面还是没有文件和文件夹

环境&#xff1a; github 问题描述&#xff1a; 文件夹上传到github分支最后github上面还是没有文件和文件夹, 和这样一样 解决方案&#xff1a; 从 git ls-tree -r HEAD 的输出中可以看到&#xff0c;metahuman-stream 文件夹显示为如下内容&#xff1a; 160000 commi…

基于Go语言 XTA AI聊天界面实现

项目开源地址: XTA-AI-SDK 人工智能技术的迅速发展&#xff0c;AI聊天应用变得越来越流行。本文将介绍如何使用Go语言和LCL库&#xff08; Lazarus Component Library&#xff09;创建一个功能丰富的AI聊天界面。项目主要包含以下模块&#xff1a; 项目背景 本项目旨在为开发…

C++入门小清单

在上一篇文章中我向大家介绍了关于C的命名空间的用处以及一些&#xff0c;这篇内容主要是讲解有关C入门的一些小知识&#xff0c;大家可以通过此文章初步进行一个了解&#xff0c;这些东西在之后的C学习中都会有更多的妙用&#xff0c;如果有小伙伴感兴趣C的命名空间&#xff0…

【kafka系列】日志存储设计 消息写入、读取

目录 日志存储设计 1. 日志存储的目录结构 2. 日志内容格式设计 3. 日志索引设计 4. 设计优势 消息写入流程 示例 流程图 消息读取流程 示例 关键设计细节 流程图 日志存储设计 Kafka的日志存储是其高吞吐、持久化能力的核心设计&#xff0c;其结构包含目录组织、…

复杂电磁环境下无人机自主导航增强技术研究报告——地磁匹配与多源数据融合方法,附matlab代码

本文给出介绍和matlab程序&#xff0c;来实现地磁辅助惯性导航仿真验证&#xff0c;包含地磁基准图构建、飞行轨迹生成、INS误差建模、地磁匹配定位及多源数据融合等模块。通过对比分析验证地磁匹配修正惯性导航累积误差的有效性&#xff0c;可视化显示卫星拒止环境下的航迹修正…

springboot项目读取 resources 目录下的文件的9种方式

1. 使用 ClassLoader.getResourceAsStream() 方法 InputStream inputStream getClass().getClassLoader().getResourceAsStream(“file.txt”); 2.使用 Class.getResourceAsStream() 方法 InputStream inputStream getClass().getResourceAsStream(“/file.txt”); 3.使用 Re…

基于SSM+uniapp的鲜花销售小程序+LW示例参考

1.项目介绍 系统角色&#xff1a;管理员、商户功能模块&#xff1a;用户管理、商户管理、鲜花分类管理、鲜花管理、订单管理、收藏管理、购物车、充值、下单等技术选型&#xff1a;SSM&#xff0c;Vue&#xff08;后端管理web&#xff09;&#xff0c;uniapp等测试环境&#x…

硕成C语言22【一些算法和数组的概念】

1.求水仙花数 #include <stdio.h>int main() {//求水仙花数&#xff1a;1.三位数 2.个位的立方十位的立方百位的立方该数int unit, tens, hundreds;for (int i 100; i < 1000; i)//i表示该水仙花数{unit i / 1 % 10;tens i / 10 % 10;hundreds i / 100 % 10;if (…

游戏引擎学习第101天

回顾当前情况 昨天的进度基本上完成了所有内容&#xff0c;但我们还没有进行调试。虽然我们在运行时做的事情大致上是对的&#xff0c;但还是存在一些可能或者确定的bug。正如昨天最后提到的&#xff0c;既然现在时间晚了&#xff0c;就不太适合开始调试&#xff0c;所以今天我…

无人机航迹规划:互联银行系统优化(Connected Banking System Optimizer,CBSO)求解无人机路径规划MATLAB

一、互联银行系统优化算法 互联银行系统优化&#xff08;Connected Banking System Optimizer&#xff0c;CBSO&#xff09;算法是2024年由Mehrdad Nemati等人提出的一种智能优化算法&#xff0c;其灵感来源于银行系统之间的连接和交易过程。在银行系统中&#xff0c;核心银行…