美团外卖前端容器化演进实践

提单页是美团外卖交易链路中非常关键的一个页面。外卖下单的所有入口,包括首页商家列表、订单列表页再来一单、二级频道页的今日推荐等,最终都会进入提单页,在确认各项信息之后,点击提交订单按钮,完成最终下单操作。

虽然提单页的代码统一放在外卖代码仓库中,但根据业务发展的需要,提单页上的模块分别由不同的业务部门去负责维护。主要包括以下业务方:

外卖侧业务

闪购侧业务

其他业务

随着业务的不断迭代,提单页的模块也越来越多,逻辑的耦合也越来越重。现在提单页的UI展示模块已经超过30个,这些模块的展示与否基本上通过服务端的下发数据来决定。在不同的订单类型下,提单页所展示元素的差异越来越大,很多模块的代码已经不适合统一放在一起维护,代码拆分的需求十分强烈。此外,客户端包体积是衡量客户端性能的重要指标,为了解决业务发展带来的提单页代码量急剧增长的问题,同时实现页面元素的动态配置,我们希望能够实现提单页的动态化,而动态化需要基于容器来实现,所以我们提出了提单页的容器方案。

提单页的容器化与外卖首页的动态化有以下几点不同:

容器化后的提单页,需要实现模块之间的互相无感知,根据服务端的下发数据,客户端可以将闪购代码仓库内的模块和外卖代码仓库内的模块拼接起来组成完整的提单页展示给用户。当用户在提单页完成一系列操作时,各模块可以提供必要的参数给服务端。要想实现这一点,我们需要考虑以下几个问题:

容器化是我们在外卖平台化之后对多方业务能力的支持和扩展,在不改变API数据源等前提下,我们保证其具有动态可配置化的能力。为了更好地支撑业务,我们在业务层面抽离出来容器化框架层,其所提供三个部分的核心功能:1.功能节点扩展及通信功能;2.可配置化功能;3.数据分发功能。在最上层业务容器中,目前所支持外卖提单页面模块、闪购提单页模块、提单页Mach(外卖动态化模板)模块、提单页MRN(RN页面)模块四种不同的业务。

在容器化框架设计过程中,我们引入了一些新的定义,比如在Android端引入了Block的概念,这里的Block是一个功能模块的简称。在提单页页面中,我们可以理解为一个Block对应一个功能条目。在iOS端有与之对应的概念Element(由于两者没有差异,下文陈述中用Block代指两者)。

Block有两种类型:其一是普通的Block,其包含BlockView(视图层)和BlockViewModel(数据层)。BlockView(视图层)用来展示具体的视图以及内部的业务逻辑;BlockViewModel(数据层),用来数据解析。其二是LogicBlock,是没有视图的Block,单纯地用来做数据业务处理。

在容器化之前,我们的业务大多是模块化的结构,模块化宿主类是承载所有模块化的管理类,各个模块之间通过宿主类或者控制器进行数据交互。但在容器化改造中,我们将之前宿主类中管理的模块进行拆解,并重新定义了宿主类的职责。在容器化宿主类中,我们将不再持有各个功能模块的引用,而只要持有RootBlock这一个实例,就可以完成对所有功能模块的管理。而RootBlockContext则用来处理父Block与子Block之间的通信以及子Block之间的通信。

第一部分功能节点扩展及通信功能。主要是目前页面的集成和通信关系,其中RootBlock是BlockTree的根节点,下面会挂载一些SubBlock子节点,RootBlock会控制整体的数据流的分发以及整体样式;RootBlockContext可以理解为上下文环境或通信的总线。每个模块都有自己的Context,来维护自己向外部提供数据以及业务逻辑的能力,这些子Context会统一注册到RootContext中进行管理维护。

第二部分可配置化功能。在发起数据请求成功之后,客户端根据注册的Key以及接收到的数据,动态创建Block的容器化能力。遍历解析数据以及配置文件,先动态创建viewModel,将创建好的viewModel绑定到生成的Block模块上,动态添加到RootBlock中。多业务方在完全不用相互感知的情况下,完成对新增模块的开发。

第三部分数据分发。既将解析之后的数据,由RootBlock节点进行数据分发到各个子Block,各子Block的BlockViewModel在更新数据之后并回传到Block中,Block用更新后的数据更新View的展示。其中,数据可以自动完成分发,也可以手动的接管数据流进行相应的处理。

Android是在编译时期,通过APT(注解处理器)的方式,将在指定模块上的注解信息和Block类关联起来,生成Block类对应的工厂类,然后将这些工厂类存在全局的Map集合中,并在运行时进行初始化操作。

@DynamicBinder(nativeId="block_key_d",viewModel=blockDViewModel.class,modelType=blockDInfo.class)NativeID是用来标识Block块的唯一Key,viewModel是用来绑定View视图的数据层,modelType对应着API的数据Model。

iOS使用Kylin注册,Kylin是美团平台开发的基建库,利用Clang提供的section()函数,在编译时Kylin将{kylin_Key,kylin_Data}格式的数据写入到可执行文件的特定数据段中,运行期就可以通过读取指定的Key值获取相应的数据。使用这种方式,注册代码分散在每个组件内部。注册内容:组件native_id、Element名称、viewModel,其含义同上。

注册宏:

#definePGA_ELEMENT_REGISTER(NATIVE_ID,PGA_ELEMENT,PGA_VIEW_MODEL)\KLN_STRING_EXPORT("AppKey_"#NATIVE_ID"","{\""#PGA_VIEW_MODEL"\":\""#PGA_ELEMENT"\"}");3.API数据结构化由于API下发数据的不规范性,需要将数据按照data_key这种数据模式的方式进行整理,然后在获取数据之后,按照规则进行数据解析并创建相应的功能Block。

目前API数据返回的格式:

需要我们将一个模块的数据统一在一个JSON对象中,整理之后API数据返回的格式如下:

布局及位置信息会对应相应的模块视图层,这由另外的layoutInfo字段给出。数组中的每条元素对应每一个Block模块,其中native_id的值是唯一的且与上面Block在注册时候的Key保持一致,data_key的值映射上面整理之后的API数据的Key,这样在编译时期生成Block的时候,就可以动态地关联相应的ViewModel以及数据模型。

{"layout_info":[{"native_id":"order_pay_by_friend","data_key":"pay_by_friend"},{"native_id":"block_container_default",//容器组"children":[{"native_id":"order_flower_cake","data_key":"flower_cake"}]}]}当然,这里可以以组为维度将一些功能相似的模块聚合在一起,native_id的含义同上,Children是子Block结点的数组。

由于之前模块化的时候,我们通过中间类的方式承载各个业务模块的通信逻辑。以Android为例,我们将多个子模块之间需要通信的逻辑,用接口的方式抛到Activity层,由Activity层进行业务逻辑的实现,但是由于子模块众多,最终导致该类的膨胀和模块的高耦合性,难以进行扩展和维护。

在容器化设计的时候,为了更好地使各个业务之间进行通信,降低耦合性,我们引入了BlockContext,同上所述,理解为通信总线。

每个Block都有自己的BlockContext,各个BlockContext汇总到RootBlockContext中去实现,最终,各个Block就可以通过BlockContext进行数据传递。

整体的通信分发图如下:

将所需要的数据包装成事件,在指定的位置驱动事件的执行进而拿到需要的数据。

RootBlock在接收数据的之后,会按照Block结点进行数据的分发。父Block将数据逐次的分发给子Block。

Block创建的顺序由API结构化数据中的layoutInfo数组来决定,layoutInfo数组的具体格式如第三节API数据结构化中内容所示。容器化后的提单页会根据layoutInfo数组的顺序,依次创建对应native_id的Block模块。因此,对于一些基础公共模块(比如wm_confirm_order_logical对应的Block),我们可以将其放在layoutInfo数组的最前面让其提前加载,保证负责UI展示的Block创建时数据可用。

由于提单页的模块比较多,在页面曝光、页面刷新或提交请求时,需要从指定的模块获取相应的数据,作为请求的入参,那么如何做成在不感知其他业务方模块的情况下,完成数据的组装呢?

如上面的通信设计思路,我们利用Event数据交互方式,从各个模块中将需要的数据取出来,完成数据的拼装。其中不同业务场景提取数据需要的校验工作,也分散在各个模块中进行处理。最终,即使在物理层面上隔离了对Block的感知,但是依然可以完成对请求所需数据的获取。

在实际的开发中,有些Block的页面View大致上相似,但是逻辑上有些细微的差异,为了快速开发,我们在设计上复用了其视图。Block、BlockView以及ViewModel的关系:一个Block对应一个ViewModel和一个BlockView,一个ViewModel和一个BlockView可以对应多个Block。

容器化之后的提单页完全由各模块组成,这些模块可以负责UI展示,也可以不展示任何UI模块,单纯地处理业务逻辑。模块内部的开发方案也可以根据业务形态自由选择,相互之间做到了完全无感知。这些优点为后续提单页的业务迭代和技术优化都提供了很大的空间。

容器化之前的提单页,页面各部分共享同一个数据模型,服务端接口数据返回后,在提单页控制器内进行数据的更新、过滤和二次加工之后,再分发给页面上的各模块。当不同的RD同时开发提单页的需求时,这些放置在一起的业务逻辑会提高RD的开发成本,另外很容易出现代码层面的冲突,在需要RD手动解决的同时,也很容易因为开发流程的不规范出现Bug。

容器化之后的提单页,开发模式也相应发生了改变,RD在开发过程中,不会感知到别的模块内业务需求的改动,各业务可以在各自的容器内进行有效的推进迭代,而不用担心会影响到其他业务,从而让多人协作开发效率得到一定的提升。

在客户端业务开发的层面,MVC架构得到了广泛应用。容器化重构之前的提单页,虽然也以模块化思想为基础做过多次重构,但是依然深受MVC思想的影响,在提单页控制器内保留了大量业务逻辑的代码。这些业务逻辑的代码最终会在业务迭代过程中逐渐变得臃肿和不可控,最终成为下一次代码重构计划中的业务背景。

提单页承载着美团的外卖业务和闪购业务,在未进行容器化之前,两个业务方需要同时向订单库提交代码,在订单库整体“瘦身”的过程中,我们发现这种开发模式让包大小优化的工作多次出现反复,并且统计指标也难以统一和对齐。对提单页进行容器化改造之后,外卖和闪购分别维护各自模块内的代码,相互之间无依赖,闪购侧可以直接在自己的代码仓库内完成提单页模块的新增和修改,不需要再给外卖代码仓库提PR,也就不会对外卖侧的包大小统计产生影响。

动态化是整个外卖业务的发展方向。提单页的动态化建立在容器化的基础之上,在完成容器化之后,就具备了动态化的基础。当前提单页的动态化,所指的主要是模块层级的动态化,提单页的各模块展示顺序、展示与否,都可以完全由根据服务端下发的数据决定,各模块可以自由地进行组合、拼装,实现提单页的动态配置。

之前因为历史原因,提单页很多的功能模块,Android和iOS在实现上大相径庭,完全不一样的实现让两端在新业务需求到来时,在与服务端接口对接、开发工时和开发方案上都存在很大的差异,这些差异点对产品需求的排期、开发和测试上线上都产生了很多负面的影响。

提单页在容器化后的另外一项收益,就是Android和iOS在模块层级的代码实现,完成了统一。借助于PGA框架和Element注册机制,Android和iOS具有大致相同的模块结构,相同native_id的模块获取的API接口返回字段完全一致;在页面请求接口数据时,相同ID的模块也提供同样的数据字段。在后续的开发过程中,两端对API接口字段的请求趋于一致,可以最大程度地减少因为两端不一致带来的合作方开发成本,也可以在一定程度上减轻下游的测试压力。

外卖客户端一直在推动核心页面的标准化,同时一直在探索尝试让核心页面也具备动态化能力。提单页作为下单路径上的核心页面,在PGA框架的基础上完成了容器化重构。至此,外卖首页、点菜页和提单页在页面这一层级都统一使用PGA框架实现。统一化和标准化之后,可以让编程风格趋于一致,代码结构在不同平台保持统一,在后续的需求开发中,可以有效减少因为两端实现不一致出现的隐性开发成本。

提单页在容器化之后,让区域动态化的技术演进更容易推进。模块之间的解耦让不同模块可以自由选择模块内使用的技术栈而不会对其他模块产生影响。对于提单页的部分模块,完全可以通过Mach或者RN等动态化方案来实现,通过区域动态化来进一步减少开发成本,提高业务需求的开发效率。

在提单页之后,客户端会继续推进订单状态页使用PGA框架实现容器化,让标准化框架对用户下单路径上的核心页面实现100%覆盖。同时积极在提单页的商家商品信息展示、放心吃、准时保等模块探索页面的部分区域动态化,进一步缩减包大小,提高开发效率。

1.Mach(马赫)是外卖终端组自研的多终端跨平台级的局部动态化技术。

2.MRN是美团基于React-native0.54.3进行的二次封装,抹平了两端上的差异,并且提供了一些基础库和组件库供业务开发同学使用。

3.Metrics是美团平台团队和外卖团队,开发的新一代App性能采集、监控、统计平台。

李肖、廷瑞、彦平、同同均为美团外卖团队工程师。

美团外卖长期招聘Android、iOS、FE高级/资深工程师和技术专家,Base北京、上海、成都,欢迎有兴趣的同学投递简历到tech@meituan.com。

THE END
1.网页布局完全指南从入门到实践网页布局是指安排和组织网页上各个元素的位置和展示方式,包括导航栏、页头、内容区、侧边栏和页脚等部分。一个好的网页布局能让网站内容清晰易读,用户体验良好。 1.2 布局之前的准备 在开始布局之前,我们需要: 确定网页的整体结构 划分主要区域 选择合适的布局方式 https://htmlpage.cn/about-html/complete-guide-to-web-layout-from-getting-started-to-practice.html
2.购物网站部署架构图mob649e8165596b的技术博客购物网站的部署架构图实现指南 引言 在当今互联网时代,电商网站已经成为商业运营的重要组成部分。作为一个刚入行的小白,理解购物网站的部署架构是迈向开发领域的重要一步。本文将带你一步一步实现一个购物网站的部署架构图,并介绍每一步所需的操作与代码。 https://blog.51cto.com/u_16175504/12853510
3.在线免费制作架构图腾讯云开发者社区Freedgo Design 是一in款在线绘制专业图形的网站。Freedgo Design可以绘制各种类型的图形,针对业务逻辑的流程图,软件设计ER模板,工作流,各种云平台的系统部署架构图包括阿里云、AWS云、腾讯云、Oracle、Asure云、IBM云平台等。 使用 用户通过浏览器访问网址:https://www.freedgo.com点击在线制图,进入图形设计工具页面即可https://cloud.tencent.com/developer/article/1429471
4.PPT组织结构图PPT树形图PPT架构图下载20套蓝黑配色组织架构图PPT图表整套下载 组织结构 18套红色版组织结构图PPT图表 组织结构 18张蓝色组织结构图PPT图表 组织结构 14张企业公司组织结构图PPT图表 组织结构 18张常用PPT组织结构图 组织结构 两张蓝色团队成员组织结构图PPT图表 9张蓝色公司组织结构图PPT图表 https://www.1ppt.com/tubiao/jiegoutu/
5.网站系统架构设计框架图和思维导图的区别说到网站结构和系统软件,大家一定会想起网站排版布局等有关提升实际操作。的确,做SEO提升的网站站长常常会触碰到网址的组织体系和构架,而这种网站结构的优劣也是决策网址将来能不能提升的主要要素。那麼网站站长们是怎样看待网址组织体系和构架的呢? 一般的网址组织结构会出现精准系统软件和模糊不清系统软件。使我们了解https://www.dkewl.com/course/detail7123.html
6.知名互联网公司网站架构图近段时间以来,通过接触有关海量数据处理和搜索引擎的诸多技术,常常见识到不少精妙绝伦的架构图。除了每每感叹于每幅图表面上的绘制的精细之外,更为架构图背后所隐藏的设计思想所叹服。个人这两天一直在搜集各大型网站的架构设计图,一为了一饱眼福,领略各类大型网站架构设计的精彩之外,二来也可供闲时反复琢磨体会,何乐https://www.jianshu.com/p/99d7a87f4d0b
7.网站设计架构 风格 信息排布 视觉顺序 8如何突破 1基础定义编辑 简单来说,网站设计的目的就是产生网站。简单的信息如文字,图片(GIFs, JPEGs,PNGs)和表格,都可以通过使超言、可扩展超文本标记语言等标示语言放置到网站页面上。而更复杂的信息如矢量图形、动画、视频、声频等多媒体档案则需要插件程序来运行,同样地它们亦需要https://baike.sogou.com/v297911.htm
8.从原型图架构到设计开发的网站制作步骤建站沙龙好的网站需要从原型图架构开始的,到后面设计开发结束经过很多细节的步骤,下面我们简单了解一下这些网站制作步骤。 好的网站需要从原型图架构开始的,到后面设计开发结束经过很多细节的步骤,下面我们简单了解一下这些网站制作步骤。 网站制作1:首先要明确网站的定位,公司网站就要弄清楚公司的产品优势以及访问的目标群体。要https://www.zhaoge.net/info/view/1209.html
9.顶层架构设计素材网站图片免费下载顶层架构设计 企业顶层架构设计 公司运营顶层架构设计 一体化智慧教育小脑顶层架构设计 2 沈先笙 杭州智慧文旅顶层架构设计构思 2 沈先笙 个人分享---b端导航架构设计专题 1 zero0304 眼镜品牌-shopify独立站设计 172 popo_333 "security eidolon"安防精灵—远程智能家居控制app 2 lucyxlu 荒漠基站的清晨 18 体验https://www.zcool.com.cn/tag/ZNTM2MzAzMg==.html
10.网络营销策划方案(精选15篇)一、组织架构图 公司总经理 部门经理 程序员 设计师 硬件维护 资深推广 信息发布 信息收集 资深业务 普通业务 二、各部门职责 网络营销部门内设三个分部,即技术部、推广部、业务部。网络营销部门设部门经理一职,下属三个分部,设主管一职。 (1)技术部主要职能 https://www.wenshubang.com/fangan/2453691.html
11.ProcessOn思维导图流程图在线画思维导图流程图提供多种预置主题风格,也可以自由设计你喜爱的风格样式。 团队协作 共同成长 团队成员共创,打造团队知识地图,实现数字化资产沉淀,让团队协作更高效、数据更安全ProcessOn 绘制网络拓扑图:精准呈现网络架构的利器 ProcessOn 绘制韦恩图:精准呈现集合关系的利器 《钢铁是怎样炼成的》思维导图 含高清人物关系图 如何https://www.processon.com/
12.网络营销的策划方案一、组织架构图 公司总经理 部门经理 程序员 设计师 硬件维护 资深推广 信息发布 信息收集 资深业务 普通业务 二、各部门职责 网络营销部门内设三个分部,即技术部、推广部、业务部。网络营销部门设部门经理一职,下属三个分部,设主管一职。 (1)技术部主要职能 https://www.oh100.com/a/202305/6744003.html
13.GitMind·思乎GitMind(思乎)是一款全平台 在线思维导图脑图架构图制作软件工具,支持手机手机思维导图,Windows/Mac/L多平台操作及内容同步。它提供有海量的架构图,流程图、思维导图模板可供用户直接使用,支持在线制作流程图、思维导图、组织结构图、类图、用例图、ER图、网络拓扑图https://gitmind.cn/
14.组织架构图组织架构图在线制作AI生成组织架构图Canva可画组织架构图制作工具简单易用,在线操作,同时有丰富的组织架构图模板可供选择,更有智能AI工具助你轻松完成组织架构图制作。https://www.canva.cn/graphs/organization-charts/
15.实施方案(2023—2025年)的通知豫政办图1“河南链”总体架构图 (二)“河南链”公共基础平台架构。“河南链”公共基础平台由管理、服务2个中台及标准规范、运维管理、安全保障等3个支撑体系组成。 管理中台。对区块链基础支撑资源进行统一动态调配,负责区块链系统的全生命周期管理,形成资源编排、合约管理、用户与权限、运行管控、API(应用程序接口)网关、基https://www.henan.gov.cn/2023/03-28/2715211.html
16.odoo17官方版本发布白皮书,全部功能及重要更新ReleaseNote更全面的网站服务预约 条码操作增加声音提醒,更方便的序列号处理 文档管理增强,如批量上传,拖放操作等 电商增强,如可使用图像作为属性规格,直接显示优惠券 人力资源增强,增加多层级组强架构图 会展管理/门票管理,可实现二维码签到等 前台访客管理,出勤管理 https://www.odooapp.cn/blog/odoo-install-deploy-6/odoo17-official-release-all-functions-and-important-updates-315
17.领君科技系统可实现省、市、县级一张图数据资源与日常管理应用相结合的管理模式,提供可供推广的数据编码标准、软件规范和实现技术,全程服务于土地批、供、用、补、查的各个环节,最终实现便捷、规范的土地综合电子监管,和科学的、准确的数据分析决策支持。 技术架构设计http://www.linjon.cn/Gtyzt.html
18.品牌元器件设备供应商实时大数据;电气报价设计数据系统图、平面布置图、原理图均按照标准图幅格式绘制,设计方案及元件符号统一从公司共享库中调用。项目图纸完成后将本项目设计新增方案增加到公司设计库。 项目采用数字母排设计方案,项目中母排三维设计使用利驰SuperPanel数字母排软件绘制。 项目中母排设计部分:箱变产品的三维设计覆盖率达到95%,中压产品覆盖率达到98%,https://www.dq123.com/
19.新成立公司人力资源工作计划(精选12篇)3、20xx年三月底前完成公司组织架构图及各部门组织架构图、公司人员编制方案。公司各部门配合公司组织架构对本部门职位说明书、工作流程在去年基础上进行改造。人力资源部负责整理成册归档。 三、实施目标注意事项: 1、组织架构的设计应本着简洁、科学、务实的方针。组织的过于简化会导致责权不分,工作负荷繁重,中高层管https://www.ruiwen.com/gongzuojihua/4564187.html