随着美团点评金融业务的高速发展,前端研发数量从 2015 年的 1 个人,扩张到了现在横跨北上两地 8 个事业部的将近 150 人。业务新,团队新,前端领域框架技术又层出不穷,各个业务的研发团队在技术选择上没有明确的指导意见,致使业务与业务之间的技术差异越来越大,在技术工具研发上无法共建,在资源调度上成本也很高。
2017年下半年,金融平台发起了技术栈统一行动,行动分为后端、iOS、Android及前端等四个方向,在前端方向我作为组织者和参与者与金融平台 8 个事业部的前端技术代表进行讨论。 通过对各方意见进行归纳整理,结合各团队的情况,金融平台对于技术栈的选型达成了共识。本文将介绍美团点评金融平台前端的技术选型以及背后的思考。先从一些基本原则讲起。
招构建技术体系的基本原则
金融业务的移动端项目占比超过 70%,尤其是 Hybrid 项目,团队在整个移动端生态的设计上投入了大量的精力,例如 Vue 的选择、EH 的设计、组件库 Vix 的设计等。
同时由于业务的金融属性,对于可用性的要求非常高。在可用性保障上我们还会有一些侧重,例如 TypeScript 的使用,自动化流程测试框架 Freekite 的使用等。
金融大多数团队都处于初创时期,因此团队历史包袱相对较少,接受新鲜事物的能力强,但快速搭建团队中也会对技术栈有上手成本的要求。在整个技术体系的搭建当中,我们会优先考虑那些新的、上手成本低的技术。
我们主张使用简单的技术手段解决复杂的问题,而不是用复杂的技术手段解决简单的问题,例如 Hybrid 体验问题的解决,常规的有 RN、Weex 等方案,在业界有丰富的实践,但我们也会设计实现更简单的解决方案 EH,让问题的解决变得更聚焦于问题的本质。在首屏渲染速度优化方案上的选择也是一样,业界有很好的 SSR 技术,但我们也会实践研发构建时预渲染技术,让 TTFB(首字节时间)更快,让系统流量负载更高,同时减少关键环节,让整个系统可用性更强。
标准化指的就是尽可能让上下游衔接形成标准,并在标准下构建效率和质量工具。
例如在组件库 Vix 的研发上,我们与 UED 形成一致的、强同步的标准,从而大大减少界面搭建的时间消耗。后面会详细介绍。
用技术去连接技术,用技术去简化步骤,解决某个工具到使用者的“最后一公里”问题。
例如我们使用的自动化流程测试工具 Freekite,不用一行代码即可以完成复杂的分支逻辑自动化测试与持续集成。我们使用的联调平台 Portm 可以将接口设计和前端 Mock 、后端单测、接口文档有机的结合起来,将前后端的研发进度解耦,从而大大提升研发效率。
顾名思义就是选型上尽量使用公司已有的系统和工具,从而更好的与团队、业务结合。
例如全平台监控工具 CAT,业务埋点工具灵犀等等。
下面来看看我们技术体系的细节。
金融平台Web前端技术体系
我们将从开发阶段开始介绍,从视图层、语言层、协作层,再到质量保障工具、体验优化工具、安全技术等。接下来过渡到编译部署阶段,讲一讲编译部署和上线工具。然后是线上监控和埋点工具。最后介绍一些各个团队正在探索和实践当中的技术。
在移动端使用 Vue 生态,在桌面版上我们使用 React 生态 或者 Vue 生态。
Vue 的使用主要考虑以下几点:
React 的使用主要考虑以下原因:
组件库是前端领域一个重要的技术单元,为效率、质量、体验服务。
效率是为了能够抽象业务研发中业务组件的共同点去避免重复劳动;质量是如果一个组件经过了测试和质量迭代,那么正确的使用不应该出现质量问题;体验方面组件库可以去统一交互的体验,让组件的表现更一致。
上述三点中,组件库贡献最大的是效率。
谈到组件库如何对效率做贡献,首先想到的是什么样的组件库才能够尽可能的提升我们的研发效率,我认为这里我们需要注意的一点是“控制变量”,因为变化产生了额外的工作量和时间成本,如果这个产品和上个产品完全一样,我们直接复制一份就好了,没必要开发。在我们的前端业务研发当中,变量是什么?是交互和视觉设计,每个产品之间有不同,也有相同。我们控制变量就应该去控制设计。因此我们与金融 UED(设计部门) 沟通制定了一个视觉组件标准,共同创建了视觉组件库:Vix。
Vix 是一个移动端组件库,其特点是完全遵守与金融 UED 制定的视觉组件标准并保持同步,在 UED 侧有完善的新组件设计提审及审核流程,在业务前端研发侧有强同步的约束。
Vix 的结构分为基础组件、复杂组件和业务组件三层,基础组件例如输入框、按钮等;复杂组件包括组合搜索、日期选择等;业务组件例如支付密码输入框、账单、账单详情等。
再上升一层则是一些包含后端服务的前后端组件,我们称为“微服务”,是一种更高层次的业务服务抽象,在更高的维度优化效率和服务体验一致性,例如支付密码验证服务,找回支付密码服务等。Vix 包含的是前三层,其结构如下图:
在以往的实践过程当中,C端业务使用开源组件库会和设计有很大差异,需要做大量的改造工作才能使用,然而可能还要为各种各样改造过程中所产生的问题负责,同时开源组件库的业务不相关性限制了业务产品的设计或实现。在 Vix 中,由于标准统一,我们的研发效率大大提升,同时质量也更加可控。
大多数移动端产品研发过程中至少 40% 以上的精力是在做界面的绘制。有了 Vix 后我们达到了:
PC 端面向用户和商户的大多都是较为独立的产品,标准化的意义并不大,前端在 PC 端的研发精力主要投入在内部系统上,在内部系统前端研发上有四个特点:
因此在内部系统的研发上有四点要求:
PC 端组件库由于设计没有要求,不存在来自设计的“变量”,所以选择很多。
React Cells 也是美团点评内部的一个组件库,金融在使用 React 生态的后台系统研发中使用 React Cells 作为组件库,其具有如下几个特点可以满足我们的需求:
在 Vue 生态实现的 PC 端内部系统中,我们使用 Element-UI 作为组件库,组件数量很多,质量也很高,在 Vue 生态中是排名靠前的开源组件库,这里不多赘述。
针对ES6,本文不再进行过多阐述。对于 TypeScript 的使用是从2015年底开始,当时我们的移动端 Web 版收银台要做质量和可用性保障(详情参考之前的文章《前端可用性保障实践》),在 JS 层面我们遇到的最多的运行时问题就是 something is undefined,也就是空指针问题。另外就是由于银行卡支付过程的业务逻辑非常复杂,代码层面可控性差,扩展性也很差。这时候想到的就是使用强类型语言来管理我们的项目,强类型语言可以帮助我们做两个事情:
当时我们面临两个选择,一个是微软的 TypeScript ,一个是 Facebook 的 Flow。选择 TypeScript 是因为以下几点:
而不选择 Flow 的原因主要包括以下几点:
TypeScript 包括 类型守护、联合类型、类型推导、严格非空检查等功能。
举个例子如图所示:
参数 s 是可能为空的,在 TypeScript 里,如果不做非空检查就会报错,做了非空检查通过 TypeScript 的类型推导就能够通过。
通过使用 TypeScript 我们可以找出前端项目中 99% 的引用问题,由于我们的整个前端框架全部支持 TypeScript,有效的避免了空指针这种运行时低级错误的存在。
在 TypeScript 的使用上金融支付也是公司第一个在线上使用 TypeScript 的业务线,2015年底我们还制定了 TypeScript 代码规范。
在日常开发当中,前后端联调经常遇到一些环境问题或者接口设计的问题,导致前后端当中一方等待另外一方,这种情况在效率上影响非常大。协作解耦指的就是让前后端的研发工作不互相依赖,从而优化研发效率。
上图表示的就是协作耦合所造成的效率问题,字母 A 代表项目 A,在前后端研发过程中,前端可能因为后端问题而无法继续开发,反之亦然。
2015年的时候我还在技术工程部,那个时候组内同学一起想到了一个方法去解决这个问题。最初的想法就是“我们能不能通过接口设计一方面生成提供给前端研发使用的假数据,另一方面生成后端的单测。”
这个想法最终落地就是 Vane 这个工具,现在叫 Portm。
它可以在一个项目的接口设计时切入,前后端使用这个平台进行接口设计,同时写入各种逻辑 Case 的输入输出,它可以直接生成三个东西:
在项目研发过程中,前端面向假数据开发不必担心遇到后端环境问题;后端面向单测开发不必担心自己跑通了前端跑不通。当双方都能跑通的时候进行集成联调,这个时候前后端集成度会非常高,先完成的一方可以直接进入下一个项目,从部门角度来讲,大大优化了产品迭代研发的效率。
下图表示的是优化后的效果,可以看到前后端已经无需互相等待了。
针对自动化测试,美团点评开发了一款工具叫 Freekite ,它的作用是从用户使用角度验证界面业务流程的正确性,解决了为实现模拟用户点击而带来的诸多问题及 Case 管理的复杂度问题。
Web自动化流程测试除了可以验证 Case 的正确性以外,最重要的功能就是要有一个异常强大的 Case 管理模块。业界目前并没有理想的工具能够支撑我们的场景。“Freekite” 在 Case 验证功能的基础上,有一个强大的可视化 Case 管理模块,支持复杂的 Case 细分。除了界面操作的细分外,可以全量 Mock 或部分 Mock 后端的数据响应,根据响应拆分出不同的 Case 分支。除此之外,还包含智能自动化断言功能,断言基本不需要人工参与。
Case 录完以后遇到界面改版的情况不好处理,Freekite 还支持单独节点的重新录制,也就完美的解决了 Case 的维护问题,大幅度减少工作量优化效率。紧接着我们会在项目中增加 Freekite 的持续集成,在项目的每一个阶段进行流程上的自动化回归验证,业务逻辑覆盖率的问题就基本解决了。下图为 Freekite 可视化 Case 管理的一个应用示例。
不同的角度对用户体验有不同的分拆方法,从前端角度讲,我把用户体验分为以下两个方向:
前端主要在“交互体验” 中的功能体验和界面体验上寻求优化。
Titans 是美团点评解决 Hybrid 功能体验的一个集团范围的解决方案,它为 Hybrid 模式的产品封装 Native 的能力供 Web 调用,其能力包括几个大的方向:
业务可以在 Titans 的基础上构建丰富的 Hybrid 应用,既能享受无需发版即可更新迭代的优势,又可以使用 Native 的大多数功能。
在解决了功能体验后,接下来我们再说界面体验的问题。
谈到界面体验我们不得不重新讲起 Hybrid,个人认为在解决功能体验的前提下 Hybrid 存在以下主要的优势和劣势:
针对 Hybrid 的劣势,行业内现有的解决方案有很多,典型的有 Facebook 的 React Native 和阿里的 Weex,除去其它因素,只讲技术本身,它们有几个共同点:
由此可见行业内解决此类问题的关键套路就是使用 Native 来呈现。
那么回到问题本身,为什么 Native 不存在此类问题而网页存在,经过研究我们发现有以下两个主要区别:
关于第一个区别大家可能存在一些困惑,这里我们举个例子,下图就是 Native 为什么没有白屏的根本原因:
如图所示,Native 从视图 A 跳转到视图 B,当用户点击 A 中的按钮触发跳转到 B 的动作时,B 的代码会开始执行,只有当 B 已经加载完成后,系统才会让 A 跳转到 B,在 iOS 中的生命周期是 viewWillAppear,在此之前 viewDidLoad 已经执行完毕,Android 也是相似的生命周期。再加上 Native APP 的资源是本地化的,Native APP 有更多的运算资源和系统级别优化,它可以把这个加载过程时间缩短到接近瞬间。而把界面绘制和加载代码写到 viewWillAppear 之前是这些厂商指导我们去这样做的,并且提供了相应的系统级别支持。这时候我们思考一个问题,如果 Native 代码将界面绘制的代码写到 viewDidAppear 中会发生什么?答案是也会出现白屏。
由此可见,并不是纯 Native 一定体验好,如果你不按照厂商的指导要求做,体验一样不好。
当我们想清楚原因后我们就开始做了一个界面体验技术,名字叫 Enhanced Hybrid (增强混合),简称 EH。
EH 的核心是“解决 Hybrid 与 Native 体验差异的技术瓶颈”。它包括两个部分,第一个部分是一个 Native SDK,有目前我们积累的所有解决体验差异技术瓶颈的功能,第二个部分是界面体验指南,也就是如何让我们的 Web 页面变的界面体验更好。
举个例子,在刚刚的白屏例子中,我们可以看到一个重要的信息,A 跳转到 B 的时候,当 A 中点击执行跳转动作时第二个界面就已经开始执行了,在 B 执行完渲染部分之前系统不会执行 A 到 B 的实际界面跳转动作。这个操作在 Web 中是不可行的,我们无法在 Web 中让 B 在跳转前执行完渲染部分的代码。
那么无白屏的前提条件是什么?
无白屏的前提条件是渲染完成,或者至少渲染到一个用户跳转过来有东西,不会给人突兀的感觉。
我们思考这个里面的技术瓶颈是什么?
当我们想清楚这个技术瓶颈以后动手解决了这两个问题。首先,B 的渲染完成并不是一个绝对的状态,而是由研发自己知道自己控制的,研发可以在到达这个状态的时候把状态主动通知出去。第二我们费了一些周折,在两个平台中可以通过一些技术去控制 A 等待一个通知,再让 B 展示出来,最终结合起来的方案如下图所示:
单独使用此技术会遇到在 A 等待时间长的问题,再辅以“离线化技术”便可以完美解决。(离线化技术会在后面详细讲)
EH 目前所有的功能包含:
目前还有更多黑科技功能在逐渐增加中,上述技术当中前三个已经成功申请专利。
很多人会存有疑问,为什么我们不使用 React Native 或者 Weex,而是自己做一个体验技术?
使用此类技术存在这么几个问题:
EH 本身不捆绑任何技术,即使你不使用任何的框架也可以完整使用 EH 的功能。
体验 EH 功能可以在应用商店中下载 “美团钱包”,在首页中点击手机充值、生活缴费或“优惠” Tab 中的内容。
SSR(Server Side Rendering) 这里就不多赘述了,大家都了解。构建时预渲染技术是我们特殊研发的一个技术。它的特点是从首帧速度优化角度来讲,理论上比 SSR 更快更稳定。
构建时预渲染技术主要实现方式是:在编译完成后,启动一个 Web Server 来运行整个网站,再开启多个无头浏览器(Headless Chrome,PhantomJS 等无头浏览器技术)去请求所有项目的路由,当被请求的网页渲染到第一个有意义的渲染时(FMP 参考 Google 的衡量体系)主动抛出一个事件,该事件由无头浏览器截获,无头浏览器截获后将此时的页面 HTML 内容保存下来生成一个 HTML。最终发布这个 HTML。此 HTML 中包含 FMP 所需要的所有 CSS 及 DOM 结构。
事实上 SSR 和构建时预渲染技术都是为首帧速度优化服务的,首帧速度优化的核心有两点:
为什么说构建时预渲染会比 SSR 快呢?
SSR 目前前端领域主流实现方式是使用 Node 作为中间层,负责数据的获取和界面的拼装,其 Node 层可能后面对接着一个或多个数据来源(业务系统),它的响应速度受限于最慢的那个数据来源。而构建时预渲染劣势是不包含数据,但优势是其首帧事件完全不依赖任何数据来源,从 Nginx 层直接返回,响应速度更快,同时流量负载更高。
为什么说构建时预渲染会比 SSR 更稳定?
SSR 在 Nginx 层后面还需要一层 Node(典型架构)做支撑 ,而构建时预渲染从 Nginx 层直接返回,其关键链路上少了一环需要保障稳定性的服务,所以稳定性更强。
金融服务平台在 SSR 和构建时预渲染上都有很多项目在运行,在 SSR 的优化上也有丰富的经验去保障速度和稳定性,在选型上的考量主要是首帧对数据的依赖程度。
离线化技术可以将网页的网络加载时间变为 0,在离线化的选型上美团点评内部有很多选择,我们也在不同的方向进行尝试。其中我们的选择包括:
留下来的只剩下两个自有技术,这两个技术的最大区别是,是否解决了首次加载问题?离线化方案的首次加载问题是一个很难的技术领域,我认为其最核心的问题是何时加载,提前加载会不会用户在很长一段时间内都不会用到导致浪费流量?使用包含首次加载优化的离线化技术的项目多了会不会造成加载拥塞?是不是需要分析用户行为数据去更精准的进行离线包的提前加载?这当中存在太多不确定性,不过我相信我们的技术团队一定能够想出优美的解决方案去解决这个问题。
另外基于 Native 能力的离线化技术还存在一些来自平台的限制,如 iOS 的 WKWebView 不支持请求拦截,而请求拦截是离线化的关键技术,这个原因导致在 WKWebView 上无法实现离线化。
WKWebView 的优势是:运行和渲染速度更快,与 Safari 内核一致 Apple 重点迭代跟进问题;劣势是:启动速度慢,无法拦截请求进而使用自有的离线化技术。
权衡离线化所带来的巨大优势和 WKWebView 的速度优势,我们选择继续使用 UIWebView。(曾经在 iOS 11 发布前业界一度认为 Apple 会在 iOS 11 中支持 WKWebView 的请求拦截)
字符级增量更新方案是一个前端领域研究了很久的课题,智能支付团队近期在这一领域有了突破性进展,这个技术方案可以通过字符级增量更新减少文件传输大小,节省流量、提高页面成功率和加载速度。其中增量计算能力由美团平台的静态资源托管方案 Build Service 支持。主要应用在扫码付项目上。
扫码付项目是美团金融智能支付团队面向 C 端消费者推出的一款 H5 融合支付类的产品,消费者在商家消费之后,可使用多种 App 进行扫码支付,同时可对商家进行评价,支持美团、大众点评、微信、支付宝、美团钱包等多种 App,目前业务日均 PV 千万级。
字符级增量更新方案的详细介绍,请参考之前的文章美团金融扫码付静态资源加载优化实践。
美团点评内部前端监控系统包括:
在技术栈统一前,我们团队这三个监控工具在同时使用,然而监控系统上前端和后端不同的是前端对代码尺寸有要求,接入的监控系统多会对项目的加载速度有影响。综合多方面因素,我们在本次技术栈统一中选择了CAT来作为我们主要的监控系统。主要是它包含前两者的功能。
CAT(详情可以参考《深度剖析开源分布式监控CAT》 一文)是一个美团点评的全端基础监控组件,在后端为各业务线提供全面的监控服务和决策支持,提供系统的性能指标、健康状况、基础告警等功能。在前端覆盖美团点评所有APP,提供近实时的多维数据分析、立体式监控、告警等功能。提供了近实时的多维数据分析,立体式监控功能。
CAT很大的优势是它是一个实时系统,从数据生成到服务端处理结束是秒级别,秒级定义是 48 分钟 40 秒时基本上能看到 48 分钟 38 秒的数据,整体报表的统计粒度是分钟级;第二个优势,数据是接近全量统计,目前大约5%的高QPS 项目是采样统计。
目前我们使用的协议均为 HTTP/2,支付是金融最早使用 HTTP/2 的部门,由于支付业务的特殊性,在一开始我们就是使用的 HTTPS ,进而很早就使用上了 SPDY。
在15年 HTTP/2 标准化的时候我们直接更新集群使用上了 HTTP/2,在 SPDY 和 HTTP/2 这种具有多路复用功能的协议上我们的前端架构全部做的都是按需加载的方式,大大减小了由“减少请求数” 所带来的流量冗余。最大化利用了 HTTP 本身的缓存机制,通过减小客户端大小的方式大大提升了网络加载性能。
安全方面在前端我们使用:
同时在核心接口上我们有一个自研的网页请求签名方案,来在一定程度上保障请求是从我们的客户端中正常发出的。
总结
以上是对金融平台前端技术体系的介绍和个人的一些思考,最后说一下采用此技术体系所达到的一些效果。
使用这几项技术的一个直接感受是人效大幅提升,一个前端同学可以并行 2~4 个项目,同时对接 4~10 个后端研发。
在使用 Titans 解决功能体验,使用 EH 解决界面体验的情况下,加上构建时预渲染和离线化技术的加持,我们可以做出专业前端都看不出来是 Hybrid 的高体验 Hybrid 应用。
在质量方面我们有:
在整个质量体系架构的演进过程中,其实不只是这些工具来保障质量和可用性,还会有很多流程规范去保障,在可用性保障上感兴趣可以参考这篇文章:《前端可用性保障实践》。
在这些实践中我们很好的保障了产品的稳定运行。同时也欢迎大家在前端可用性保障上多探讨。