滴滴跨端渲染平台的建设方案及落地 - 滴滴技术
导读
由于网约车业务本身的复杂性以及我们垂直式的领域化架构约束,网约车服务端技术团队在对端渲染业务需求的迭代过程中,碰到了一系列的问题,影响了研发效率。本文从这些具体问题入手,分析产生的原因,介绍我们的解决思路和方案,以及方案的建设落地过程。
1. 服务端架构演进回顾
过去几年,滴滴网约车为了满足不同用户的个性化出行需求,逐步推出了越来越丰富的品类和功能。随着品类功能的不断增加,我们系统的复杂度也越来越高,为了应对这一挑战,网约车服务端技术团队构建了一个「出行平台」,内部又称湾流平台。湾流平台的演进主要经过了以下几个阶段。
湾流平台1.0(2017-2018)
在1.0阶段,滴滴网约车的主要业务重心是丰富品类,为用户提供更多选择,其中包括专车、豪华车、优享等。在这个阶段,湾流平台还是一个单体服务,主要面临的挑战是如何快速新增品类并支持多品类之间的差异化开发。
为了应对这些挑战,我们引入了配置化和插件化。配置化使得新增品类可以快速上线并进行复用,提高开发效率。插件化则能够隔离不同品类之间的差异逻辑,确保各品类的独立性和灵活性
湾流平台2.0(2018-2020)
在2.0阶段,随着品类的不断丰富和个性化功能的增加,开发团队也不断壮大,系统规模逐渐庞大,但日常的迭代效率和稳定性出现了明显下降。为了解决这些问题,我们从两个方向对湾流平台进行了改造。
首先,按照领域驱动设计(DDD)的思路,对单体服务进行了拆分,降低整体系统的复杂度,同时也解决了团队成员并行开发导致的上线冲突和排队的问题,提高了开发效率。
其次,在领域服务内部,我们进行了功能的聚合和抽象,通过将具有相似功能的业务进行聚合,并对其进行抽象,可以避免功能的重复开发,进一步提高了开发效率和代码的可维护性。
湾流平台3.0(2020-至今)
在3.0阶段,我们开发了一套名为DuKang的业务框架,它将API的业务逻辑分为两个层次。首先是流程层,用于串接状态流转,提供了通用的流程实现,不同的品类可以根据自身需求定制自己的流程,以满足差异化的业务要求。
其次是能力组件层,负责完成各个垂类功能。组件内使用策略模式实现不同的行为,例如播单组件内部提供了延迟播单、实时播单等不同方式,不同的品类可以根据自己的需求选择适合自己的方式。同时,组件也支持插件机制,可以让品类注入独有的模式。
通过Dukang框架,我们能够有效约束各服务系统的实现,保持统一的规范,让不同的领域服务可以复用能力组件,提高开发效率和代码的复用性。
湾流平台详细的建设思路,可以参考之前的文章「滴滴出行平台业务架构演进」,系统的架构简单示例如下:
2. 新问题和挑战
在讨论新问题挑战之前,我们先统一一些基本概念。
- 页面:指用户在终端上看到的整体区域,包含各种UI控件,例如打开app看到的乘客首页、司机接单后赶来的等待接驾页等。
- 组件:页面中独立展示的功能区块,通常具有特定的业务属性,例如下图的小助手组件,主要用于展示当前场景下的一些重要业务提示和部分营销活动。
- 模板:组件内的不同UI展示样式,依赖于组件的定义和存在。
- 功能:表示一些具体的业务场景,例如保障车队功能、自选车功能等。
- 数据源:提供组件渲染数据的后端服务接口。
在湾流平台的持续建设过程中,渲染类需求的迭代效率始终上不去,经过进一步的深入分析,我们发现虽然领域服务能够通过能力层实现功能逻辑的复用,但在做对端的渲染逻辑时出现了一些问题。不同位置的组件是由不同领域服务负责的,而这些领域服务各自有自己的渲染规范,因此,同一个功能想要在不同组件上进行展示时,就需要按照这些组件的渲染规范进行适配,例如有的组件要求直接通过接口返回渲染数据,而有些则要求在平台上进行数据配置,这就导致一个功能在渲染对接上需要花费大量成本。同时,除了服务端系统内部的问题外,还有一些外部沟通协作、数据开发等挑战。
下图是当前系统内渲染处理现状,具体的问题可以结合下图进行讨论。
多端问题
滴滴涵盖了多个终端,包括Android、iOS和小程序等。由于我们划分了不同的领域服务,每个领域服务都需要直接向终端提供相关展示数据,例如,售卖领域服务提供首页相关数据,交易撮合领域服务提供等待应答页的相关数据等。然而,这就导致了所有领域服务需要同时与所有终端进行对接,增加了沟通和协作的成本,影响迭代效率。
同时,网约车产品在大多数情况下要求多终端的体验保持一致,然而,由于各端独立开发和实现,又没有地方统一进行管控,导致不一致的问题经常出现。例如,相同的标签展示内容在长度超过限制时,iOS会截断展示,而Android则采用跑马灯展示等。多端实现不一致同样也会影响我们的迭代效率,例如当产品希望对线上展示内容进行动态更换时,由于各端实现不同,导致动态化能力参差不齐,产品不得不针对各端进行差异化实现;还有同一个功能上线后,由于各端埋点实现不一致,收集的数据差异很大,每次都需要排查原因,甚至需要为不同端制定不同的数据分析策略。总之多端一致有利于产品体验的提升,也能提升效率。
渲染逻辑管理困难
端上的组件位置是有限的,但是功能却是不断累积的,这导致在一个组件上需要根据不同的业务场景,展示不同的内容。经过统计,一些热点组件上,拥有四五十种展示形式,上百种展示场景,面对如此复杂的情况,流量分发、优先级排序等管理十分复杂,而且所有的领域服务都需要重复实现这些复杂的逻辑,存在大量的重复工作。
功能跨流程接入难
有很多功能需要在全流程进行透出感知,比如拼车权益卡,在冒泡、等待应答、行程结束等很多阶段都需要进行感知透出,这些阶段的页面由不同的领域服务处理,这些服务又归属于不同的团队,在渲染接入上都有自己独立的一套规范,导致拼车权益这样一个功能接入跨流程的展示时,需要和不同的领域服务进行对接,而且需要进行逐一适配,接入成本很高。
数据看清难
各个组件的前后端埋点都是由不同团队的开发同学进行自定义实现,缺乏统一的规范,下图以拼车权益示例,可以看到,虽然各个位置都有埋点,但是大家的规范都不一样,想要把这些数据串起来非常的困难,每次要看数据时,都需要数据产品单独提需求进行开发实现,周期长,成本也很高。
以上就是我们在渲染上遇到的一系列问题,从上面的问题中可以看到,当前架构中最核心的问题,是系统各个层级间缺乏统一的渲染标准和规范,导致出现了很多的重复工作以及相互间信息打不通,主要可以归纳为这三个方面:
- 前端 & 后端 :如何构建统一的组件认知,如何保证多端一致,如何减少多终端的协作成本。
- 后端 :如何管理组件内复杂的功能展示逻辑,如何保证单一功能在全流程进行感知时,可以快速接入。
- 数据 & 前端 & 后端:如何建设统一的前后端数据规范,如何快速看清数据
3. 解决思路
解决这几个问题的核心思路是进行标准化,通过不同层次的标准化配合,形成一套统一的跨端渲染平台,详细的方案思路如下所示。
组件标准化
组件标准化的思路是将我们页面按功能模块划分成不同的组件,然后对这些组件进行UI规范和数据交互协议的统一,各端再根据统一的UI规范和交互协议进行组件的开发,同时在研发流程和研发模式上进行管控,让各终端架构层面保持统一,尽可能地实现各端体验的一致。针对多端实现一致的问题,Android和IOS也在探索跨端技术等方式,本文不对此展开。
有了这些多端统一的标准化组件之后,为了实现组件的复用以及减少终端和后端的沟通协作成本,我们建设了组件管理平台和渲染网关。终端研发在管理平台上对页面进行配置,配置页面上有哪些组件,这些组件通过什么样的形式进行布局,组件的数据从哪来等等。有了这些配置之后,终端进行页面渲染时,不再和各个组件下游服务交互,而是和渲染网关进行交互,渲染网关会根据终端传入的页面标识,在配置后台拿到对应页面的配置,代理请求下游服务,拿到各组件的数据统一进行下发。通过这样的形式,可以有效地减少终端和各后端的沟通协作成本,同时这种标准化构建的组件,可以很方便地进行跨页面的复用,提升迭代效率。
组件标准化除了对开发的收益之外,对产品业务同样有很大的帮助,之前的产品迭代过程缺乏集中的沉淀,导致每次新功能需要做展示时,即使展示样式跟之前的功能很类似,但由于没有地方查阅,依然会找UI重新设计,研发重新开发实现。这也是导致一个组件上展示样式爆炸式增长的主要原因。进行标准化之后,产品业务能够在平台上看到组件上当前所有的展示样式,新功能可以选择复用之前的模板,提升研发效率,同时也能集中对组件和模板进行管控,保持体验的统一。
通过组件的标准化,整体的需求开发模式变成了如下的形式:
组件标准化建设过程,主要是渲染网关和组件管理平台的建设,下面重点展开介绍下这两部分的详细方案:
渲染网关
渲染网关主要提供了两个接口,layout接口和data接口,layout接口负责下发页面的布局信息,包括页面的一些静态配置以及有哪些组件等信息,data接口则负责获取组件渲染所需的数据。在实际运行过程中,考虑到性能和体验的问题,在layout接口,会将核心组件的数据也进行返回,端上拿到layout的数据之后就能够进行页面的渲染,对于页面上一些非核心可异步加载的组件,端上在拿到layout数据后,会再请求data接口获取这些组件的数据。详细的交互如下所示。
组件管理平台
组件管理平台主要是提供一个配置后台,管理组件相关的内容,主要功能包括:
- 页面管理,管理页面标识和页面组件关系等,可以在页面管理里配置对应页面包含哪些组件,并且可以进行一些组件实验和灰度的配置,页面也提供了版本管理的能力。
- 组件管理,对组件进行定义,并且对组件的模板进行管理,包括模板的UI规范、IDL交互协议等。
- 数据源管理,对下游数据源进行注册、参数映射转换等,组件在注册到页面时会配置对应的数据源,这样网关就能根据配置直接代理请求拿到组件数据。
- 组件全景图,为产品业务打造的组件视图,业务和产品可以在上面追踪到当前app有哪些页面,每个页面上是由哪些组件组成,每个组件上支持哪些展示样式,也能看到有哪些功能会在这个组件下进行展示,这些功能的流量是如何分配的。
除了上面提到的核心管理能力外,管理平台在开发体验上也提供了一些能力,比如多版本功能,可以实现类似git的多分支并行配置开发测试;网关接口文档和mock能力,由于所有组件交互协议是托管在平台上的,平台会基于此实现接口文档和下游组件数据的mock功能,提高开发联调效率。
功能接入标准化
功能接入标准化的主要思路是统一一套标准的渲染处理逻辑,不同领域服务进行接入使用,这样不仅能够减少领域服务间的重复建设,也能够让功能接入方式统一,不再需要进行适配。为了统一渲染处理逻辑,我们在Dukang框架基础上扩充了渲染框架能力,将渲染流程固化为上下文构建->功能过滤->功能决策→功能渲染。其中上下文构建是组装渲染所需的必要上下文数据,功能过滤是根据地域、时间、品类等规则过滤掉当前场景下不展示的功能,功能决策是对剩余的功能进行优先级排序,选择最终展示的功能,功能渲染则是选中的功能进行数据的填充。除了渲染框架以外,我们还沉淀了一些标准可复用的能力,比如开城、白名单、物料管理等等,这些能力的相关配置我们统一建设了功能管理平台进行集中管理。
下面介绍下渲染框架和功能管理平台的详细建设方案。
渲染框架
渲染框架主要思路是通过一套统一的功能执行流程,对功能进行标准化约束,框架限定了功能的执行流程依据上下文构建->功能过滤->功能决策->功能渲染,框架约束的只是执行流程,具体逻辑依然是相关功能闭环实现。比如功能过滤,如果只是简单的开城过滤,业务方可以直接使用标准的开城能力;如果有一些不能抽象的复杂策略,业务方可以在自己的包中编码实现。这样既能保持功能的标准化定义,也能保持业务的灵活性。
功能管理平台
功能管理平台主要提供功能管理能力,平台的主要功能如下:
- 功能展示策略配置,结合沉淀的城市、品类、场景等展示规则,配置不同功能对应的展示策略
- 功能优先级配置,配置组件下功能间的优先级,优先级支持多个分组,比如不同城市,优先级可能是不一样
- 功能文案物料配置,配置对应功能展示所需的文案以及相关物料,这部分由于不同功能的配置方式差别很大,我们结合了内部的一个通用配置平台实现,在通用配置平台上,rd先根据实际需求,进行功能的文案和物料的配置模板开发,功能管理平台和该通用配置平台打通,将对应的配置页面集成进来,形成统一的配置平台。
- 功能全链路视图,该视图主要提供给产品业务使用,之前由于缺少统一的规范和沉淀,一个功能在哪些地方进行了透出,各个地方的效果转化如何,很难在一个集中的地方看到。通过我们的标准化之后,我们可以提供功能的全链路视图,方便的看到每个功能在哪些组件上进行了透出,对应的流量分布是怎样的,转化漏斗如何等等。
数据标准化
对组件和功能接入进行标准化之后,数据标准化就水到渠成了,我们只需要在每个阶段的日志中,记录前面定义的页面、组件、模板、功能等唯一标识,同时打通数据链路,按照统一的规范进行数据上报、采集、清洗和聚合,就能够形成一套标准的数据方案,在后面的功能开发过程,不需要再进行额外的数据开发,根据组件或功能的标识就能够看到需要的数据。
埋点协议统一
埋点协议统一的核心就是让不同服务的埋点信息能够聚合起来,只要大家采用一套固定协议,约定好聚合的字段,通过数据采集清洗等步骤进行聚合,就可以实现数据的统一。我们制定了前端上报、网关下发日志、数据源服务日志等一系列的协议,统一了页面、组件、模板和功能等标识。整体的思路如下所示,通过平台统一管控埋点统一配置,各个服务利用sdk的方式对上报埋点进行统一。
数据链路打通
打通从终端到后端服务的数据链路,通过标准的协议,将数据聚合到统一的数仓中,进而形成统一的数据看板。主要数据链路示意如下所示:
总结
综上所述,我们通过组件、功能接入和数据的标准化,完成了整个跨端统一渲染平台的建设,目前该平台还在持续建设推广中,渲染网关、组件管理平台、渲染框架、埋点规范等已经建设完成,功能管理平台、数据链路还在建设中。当前该统一渲染平台已经接入了20+页面,未来将继续覆盖到所有的渲染场景。
平台的整体的系统架构图如下所示:
END
作者及部门介绍
本篇文章作者吴俊,来自滴滴网约车出行技术团队,出行技术作为网约车业务研发团队,通过建设终端用户体验平台、C端用户产品生态、B端运力供给生态、出行安全生态、服务治理生态、核心保障体系,打造安全可靠、高效便捷、用户可信赖的出行平台。