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

news2025/2/18 18:11:18

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.coloradmin.cn/o/2299043.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SQL Query美化

推荐一个可以美化Query的网站&#xff01; 名称&#xff1a;SQL formatter | Online free SQL Beautifier 地址&#xff1a;https://sqlformatter.org/# 在处理 SQL 查询语句时&#xff0c;可读性是至关重要的。 杂乱无章的 SQL代码不仅难以理解&#xff0c;还会给后续的维…

2025 docker可视化管理面板DPanel的安装

1.什么是 DPanel &#xff1f; DPanel 是一款 Docker 可视化管理面板&#xff0c;旨在简化 Docker 容器、镜像和文件的管理。它提供了一系列功能&#xff0c;使用户能够更轻松地管理和部署 Docker 环境。 软件特点&#xff1a; 可视化管理&#xff1a;提供直观的用户界面&#…

mapbox V3 新特性,添加下雪效果

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;mapbox 从入门到精通 文章目录 一、&#x1f340;前言1.1 ☘️mapboxgl.Map 地图对象…

【STM32】H743的以太网MAC控制器的一个特殊功能

调试743的MAC&#xff0c;翻阅手册的时候&#xff0c;发现了一个有意思的功能 混杂模式 H743的MAC控制器&#xff0c;可以设置为混杂模式&#xff0c;这就意味着它可以做一些网络监控的应用&#xff0c;譬如连接具备端口镜像功能的交换机&#xff0c;然后直接代替PC实现网络数据…

WEB攻防-第60天:PHP反序列化POP链构造魔术方法流程漏洞触发条件属性修改

目录 一、序列化与反序列化基础 1.1 什么是序列化与反序列化 二、魔术方法的生命周期 2.1 常见的魔术方法 2.2 模式方法的生命周期触发调用 2.2.1 __construct() 2.2.2 __destruct() 2.2.3 __sleep() 2.2.4 __wakeup() 2.2.5 __invoke() 2.2.6 __toS…

二、交换机的vlan子设备接入

一、交换机的vlan设置-CSDN博客 二、交换机的vlan子设备接入-CSDN博客 接上篇的文章&#xff0c;本文接入了子设备 网络结构如下&#xff1a; 用路由器A和POE交换机B代替第一篇中的笔记本电脑&#xff0c;路由器A和交换机B都关闭DHCP服务&#xff0c;并分别接入一个IPC&#…

Spring IoC的实现机制是什么?

大家好&#xff0c;我是锋哥。今天分享关于【Spring IoC的实现机制是什么&#xff1f;】面试题。希望对大家有帮助&#xff1b; Spring IoC的实现机制是什么&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Spring IoC&#xff08;Inversion of Control…

配置mysql8.0使用PXC实现高可用。

准备好下面三台服务器 cat >> /etc/hosts << EOF 192.168.1.11 pxc1 192.168.1.12 pxc2 192.168.1.13 pxc3 EOF 三台服务器同时进行&#xff0c;下载安装包 [rootlocalhost ~]#yum module disable mysql [rootlocalhost ~]#yum ins…

对openharmony HDF驱动框架的C/S设计模式和单例类的说明

在分析openharmony的HDF驱动框架时我们会发现用了很多面向对象的思想&#xff0c;例如类继承、接口、单例类等&#xff0c;本来应该是好事情&#xff0c;**但使用时对象之间的关系交错复杂&#xff0c;不太符合linux内核分层分模块的思路&#xff0c;导致整体理解起来比较困难&…

vue学习10

1.GPT和Copilot Copilot Tab接受 删除键&#xff0c;不接受 ctrlenter更多方案 更适合的是修改方向 const submitForm async () > {//等待校验结果await formRef.value.validate()//提交修改await userUpdateInfoService(form.value)//通知user模块&#xff0c;进行数据更…

如何正确安装Stable Diffusion Web UI以及对应的xFormers

本文是我总结的步骤&#xff0c;验证了几次保证是对的。因为正确的安装 Stable Diffusion Web UI 以及对应的 xFormers 实在是太麻烦了&#xff0c;官方和网上的步骤都是残缺和分散的&#xff0c;加上国内网络速度不理想&#xff0c;所以需要一些额外步骤&#xff0c;之前研究出…

DeepSeek正重构具身大模型和人形机器人赛道!

中国人工智能公司DeepSeek&#xff08;深度求索&#xff09;以“低成本、高效率、强开放”的研发范式横空出世&#xff0c;火遍并震撼全球科技圈&#xff1b;DeepSeek展现出来的核心竞争力&#xff0c;除了低成本及推理能力&#xff0c;更重要的是开源模型能力追赶上了最新的闭…

Linux库制作与原理:【静态库】【动态库】【目标文件】【ELF文件】【ELF从形成到假造轮廓】【理解链接和加载】

目录 一.什么是库 二.静态库 2.1创建静态库 我们在之前的路径下新建lib使用我们自己的库 2.2 使用makefile生成静态库 三.动态库 3.1动态库生成 3.2动态库使用 3.3库运行搜索路径 四.目标文件 五.ELF文件 六.ELF从形成到加载轮廓 6.1ELF形成可执行 6.2 ELF可执行文…

【ubuntu24.04】 强制重启导致大模型的磁盘挂载出错

挂载NTFS文件系统出错 各种模型放在了这个机械硬盘上&#xff0c;虽然速度慢&#xff0c;但是好在容量大。大模型在工作&#xff0c;但是程序看起来有问题&#xff0c;导致系统卡死了&#xff0c;然后我重启了&#xff0c;然后报错&#xff1a;wrong fs type bad option &…

Spring Boot(8)深入理解 @Autowired 注解:使用场景与实战示例

搞个引言 在 Spring 框架的开发中&#xff0c;依赖注入&#xff08;Dependency Injection&#xff0c;简称 DI&#xff09;是它的一个核心特性&#xff0c;它能够让代码更加模块化、可测试&#xff0c;并且易于维护。而 Autowired 注解作为 Spring 实现依赖注入的关键工具&…

【linux】在 Linux 服务器上部署 DeepSeek-r1:70b 并通过 Windows 远程可视化使用

【linux】在 Linux 服务器上部署 DeepSeek-r1:70b 并通过 Windows 远程可视化使用 【承接商业广告,如需商业合作请+v17740568442】 文章目录 【linux】在 Linux 服务器上部署 DeepSeek-r1:70b 并通过 Windows 远程可视化使用个人配置详情一、安装ollama二、下载deepseek版本…

【AI大模型】Ollama部署本地大模型DeepSeek-R1,交互界面Open-WebUI,RagFlow构建私有知识库

文章目录 DeepSeek介绍公司背景核心技术产品与服务应用场景优势与特点访问与体验各个DeepSeek-R系列模型的硬件需求和适用场景 Ollama主要特点优势应用场景安装和使用配置环境变量总结 安装open-webui下载和安装docker desktop配置镜像源安装open-webui运行和使用 RagFlow介绍主…

Unity 命令行设置运行在指定的显卡上

设置运行在指定的显卡上 -force-device-index

Visual Studio 使用 “Ctrl + /”键设置注释和取消注释

问题&#xff1a;在默认的Visual Studio中&#xff0c;选择单行代码后&#xff0c;按下Ctrl /键会将代码注释掉&#xff0c;但再次按下Ctrl /键时&#xff0c;会进行双重注释&#xff0c;这不是我们想要的。 实现效果&#xff1a;当按下Ctrl /键会将代码注释掉&#xff0c;…

教程:使用 Vue 3 和 arco 实现表格合并

1. 功能概述 本教程将介绍如何使用 Vue 3 和 arco 组件库实现表格合并功能。具体来说&#xff0c;我们会根据表格数据中的某个字段&#xff08;如 type&#xff09;对表格的某一列&#xff08;如入库类型列&#xff09;进行合并&#xff0c;同时将质检说明列合并为一列。 2. …