解码数字化之路,56 个深度转型案例正式上线,立即查看>> 了解详情
写点什么

从分层复用到自动化测试,看美团客户端架构的演变

  • 2018-01-24
  • 本文字数:5644 字

    阅读完需:约 19 分钟

前言

伴随着业务的飞速发展,美团点评的客户端研发团队的规模从初期的 20 余人的发展为数百人,且分散在不同的业务团队。拥有如此大规模的研发团队,他们是如何保证高效的内外部协同效率?美团与大众点评原本是两家独立运营的大型互联网公司,分别有着不同的积累和储备。两家的合并为业务带来巨大的好处的同时也为技术团队带来了巨大的挑战——如何能够同时高效地在美团和大众点评两个 App 上实施业务开发?

在突破了这些难题之后,美团希望继续提高自身的研发效率,经过系统性地分析,他们的解决方案是实施自动化测试。那么他们是如何在大规模业务开发团队中高效实施自动化测试,进一步提升研发效率和质量的?

本文就带你揭晓美团点评技术团队背后的故事,分享一些美团点评客户端团队的技术架构及其设计思路,帮助团队技术负责人设计有利于提升研发效率的业务架构。以下全文来自美团技术研究员梁士兴在 2017 北京 ArchSummit 全球架构师峰会上的演讲。

1 为什么要建设客户端架构?

客户端架构与客户端或 APP 的发展经历是相关的。早些年 APP 通常是由个人开发者或者小团队来实施,那时候它往往是作为一个业务创新或某一个实践去做的。

APP 从小型变成了巨无霸,代码动辄上百万行,美团移动支付的占比也早就超过 90%,开发团队也从小变大,美团点评现已有数百人专门从事 APP 开发。迭代周期主要和业务的重要性相关,如果是核心的业务载体,迭代周期就需要做得越来越频繁、越来越迅速。

美团点评使客户端架构统一是希望得到这方面的收益,通过标准化,就可以实现三个统一:统一的基础设施、统一的逻辑分层、统一的开发范式。然后会带来四个明确的好处:

  1. 让一线开发人员聚焦在业务开发上;
  2. 可以实施灵活的人力调配;
  3. 可以用标准化的方式介入一个新的业务以支持其快速启动;,
  4. 一旦实现了标准化,必然可以基于它做一些自动化的实现,可以把一些相对机械重复的事通过自动化去取代人工。

最终带来的好处是:可以更好地服务业务。

2 美团客户端的演变历程

上图是针对美团客户端整理的技术研发体系。纵向是按时间和阶段划分的,横向按业务逻辑、开发范式、技术栈整理出来的。从技术体系图来看,进行业务开发的技术挑战其实是蛮大的,需要了解数据采集、监控、质量保证等方方面面。设计业务架构的目的是让业务研发人员把精力集中在业务开发上。

美团客户端架构发展分为三个阶段:

  1. 蛮荒阶段:这个阶段并没有什么体系化的架构设计;
  2. 标准化的阶段:内部细分了三个小阶段,实现了业务隔离、基础设施复用、开发范式等。
  3. 自动化是正在建设中的阶段,希望通过使用工程自动化的手段去持续提升效率。

3 蛮荒阶段

蛮荒阶段也就是最初的APP 形态,众所周知,美团是做团购起家的,万物都是团购,在这个阶段美团并没有针对性地设计任何架构相关的东西。但是团购有一个好处就是可以以很低的成本把业务触达到各个领域,在这个阶段中,美团实现了业务遍地开花,很轻松地触达到不同的品类,比如酒店、电影等。于此同时,美团也让移动APP 成为了核心业务载体,移动支付的占比超过了90%。

面临的挑战

那这个阶段能继续下去吗?挑战很快就接踵而至。挑战主要来源于两个方面:业务差异化和业务间的协同效率,从业务层面上来讲,虽然美团实现了业务的遍地开花,用团购方式触达到各个业务领域,但还不足以把业务做深。例如:团购这种形式并不适用于所有的领域,如酒店一定要预定,它和美食的团购行为是不一样的,这个时候要有诉求地去深耕业务,把不同业务特点的东西做出来,就是所谓的垂直化。因为业务这边已经有了不错的发展,换句话说就是赚到钱了,所以团队的规模在极速扩张,同时美团的研发团队被拆分到各个业务去,这也是为了更好地服务业务。

4 标准化阶段

针对第一阶段,美团主要通过分层和隔离的方式来解决问题,首先把跟各个业务都无关的和与各个业务都相关的公共基础设施定义为平台的基础设施。我们把一个平台做强,同时在这个平台的基础之上去构建各个业务,而且在业务里面进行有特色的垂直化建设,这个阶段会带来很明显的收益。

通过这样的平台设施,在一定程度上实现了复用和业务的积累,解决了业务之间的耦合,各个业务在物理上会隔离开,放到不同的代码仓库里面,只是在构建的时候把他们集成在一起,这种模式还有一个好处,就是为新业务的接入保持开放,任何一个新业务都可以按照规范轻松地接进来。

具体步骤

如果想要达成这样的目的,首先应该开发一套标准的业务模板,所有的新业务都按照这个模板去开发,根据模板的内容去进行业务的定制,并且通过统一的方法来实现接入,谁做比较合适?显然是新业务,让新业务去做小白鼠,在这个阶段里,短期内是可以接受代码拷贝的,通过解耦拷一份代码,将其分到一个独立的仓库里。为什么说短期可以接受这种行为?客户端有一个特点,哪怕不动弹,过一段时间页面也会被产品改得面目全非。

那么在这个过程中美团的收益是什么?总结起来有三点:

  1. 首先是在业务层面实现了业务间的隔离,解除了业务间的干扰,再也不会看到改电影模块导致酒店模块出现故障的现象,也不会把外卖的东西展示到美食区;
  2. 在工程层面上实现了工程标准化,使得新业务接入的方式是标准化的;
  3. 在技术层面上实现了独立的编译和二进制的集成,一旦实现了业务间的独立编译,就可以利用分布式的系统进行多机构建,这样就可以极大地缩短应用的构建时间。

但梁士兴认为这个阶段并不完美,还有很大的改进空间。因为一线开发者的研发效率并没有因为这次重构得到任何提高,这是为什么呢?因为开发层面没有标准化,代码复用是非常困难的一件事,所以需要实现开发范式,通过定制开发范式,将开发过程统一化,开发产物也是标准化的,可以被更好地复用起来。

统一开发范式

从上图来看,茴字有五种写法,而USB 接口的实现方式更多。也就是说客户端开发的实现方式有很多种,这就使得复用变得非常困难,因为大家做事的方式都不一样,业务模块接口也是不统一的,想用统一的方式把所有模块调度起来就会非常困难。

这个问题让开发范式的目标明确了起来,开发范式实现的是书同文、车同轨,即开发方式统一化,业务接口标准化。

在这里以一个实际页面为例,这是一个复杂的页面,这个页面天然地划分成若干块,从这几个角度上来讲,页面本身并不存在什么东西,所有东西都被放到模块里,经过这样的抽象,我们把页面上的每一块定义为一个模块,同时页面会退化成模块容器的概念。

进一步来说,模块之间通常存在着通信的需要,这种通讯包括UI 上的联动、数据的共享等,模块之间如果需要强依赖去获取数据,则模块之间也存在着依赖,这个是不能接受的,我们设计的目标是希望能实现模块级别的复用。

为此,梁士兴说他们团队引入了一个消息总线的概念,可以允许模块在上面订阅或发布消息,通过这种方式也能实现模块之间的耦合。他们还进一步对模块的内部也进行了约束,要求模块统一,按照这样的方式去组织,能够更好地实现自动化测试。经过这样的设计,美团主要页面的实现方式得到了统一,最直接的好处就是模块可以跨业务复用了。

按梁士兴的说法,他们在设计统一开发范式的时候就设定了目标,他们希望对高级工程师的依赖能够降低,以及开发效率能够得到提升,提升的逻辑在于代码可以复用。对此他给出了以下案例:将2014 年7 月、2016 年12 月以及2017 年夏天开发独立APP 时做的需求进行对比,前两者比较,发现2016 年效率提升了33%,而2017 年独立APP 只用了2 倍的人力实现了8 倍工作量,效率提升了400%,这种提升是非常值得开发人员自豪的。同时他们团队参与这些项目的高级工程师的比例也在持续降低,到最后做独立APP 时,一个高工带着一群小弟就能把事情搞定了。

想实现统一开发范式也会存在一些困难,这里的困难和上文是一样的,主要有两点,第一,整体重构一遍成本极高,第二,业务永远不会等着技术,所以开发的同时要进行重构。他们只对新需求涉及的页面进行重构,客户端的代码总是很快地迭代到,借着产品迭代这样的时机把对应的架构重构做完。

做到这个程度,梁士兴认为他们已经进入了相对理想的状态,但有些事情是不受他们控制的。由于公司战略的原因,美团和点评进行了合并,众所周知,这两家公司一直以来是独立运营的,各自都有不一样的积累,合并会带来大量的不统一:两边的APP 技术栈不统一,后端服务不统一,交互样式也不统一。对产品经理来说相当于多了一个APP,再加上大量的基础设施不统一,想把某功能整体从美团迁移到点评,这几乎比登天还难。但是技术人员就是解决问题的,所以针对这三个不统一,他们做了两层抽象。

首先,针对基础服务层的差异,他们做了一层抽象接口,这个接口不做具体功能的实现,它的具体实现是由两个平台真正的基础设施来实施的。第二个方案是针对差异进行了设计,在一套代码仓库里利用构建过程,把一些差异化的地方让它产生不同的构建产物。

通过这样的方式,可以在APP 里写不一样的代码,同时去支持美团和点评两个APP 的业务开发,这套方案其实是一个通用的方案,它并不仅限于对这两个APP 的支持。美团在开发独立APP 的时候,也是直接利用这样一套模式,就把美团的东西复用到美团独立的APP 中,在三端之间实现了代码复用,而且这套模式本身对自动化测试也是极好的,可以直接利用二进制构建的结果接入到自动化测试的工程,这样自动化测试的构建效率是非常高的。

解决了多应用复用的问题,带来的收益更加明显。统一架构优化之后迁移成本整体控制在30% 以下,其实平均是低于20% 的,在这个阶段下,美团多应用同时支持需求迭代的情况就变得可行了,而且是一个常态化的过程,代码复用率也从一开始不复用,到后面整体复用率在95% 以上。

5 自动化阶段

经过了这样几轮架构方面的迭代,还有没有办法进一步提升研发效率呢?在这里,美团用了一个方法论:既然已经实现了标准化,是否可以进行自动化了呢?因为有了自动化的工具做保障,反过来可以促成标准化的达成,杀掉非标准化的行为。

那我们应该针对什么事情做自动化?梁士兴表示,根据一个迭代周期的各个环节的实际人力投入,可以发现测试的成本很高,测试和开发的时间比例是4:5,同时把测试和开发的若干个环节再去做拆解,会发现测试里面有一个很可怕的东西叫做回归测试,占的比重非常大,而且回归测试还有一个特点:回归测试的规模只与APP 的规模有关,并不与迭代的新功能有关,这也是一件很可怕的事情。某个版本做了很小的需求想快速上线,同时还要为了保证线上的质量进行完整的回归,回归的规模并不因为需求小而变小,应该优化回归测试的过程,从这个角度上来说,自动化测试就是解决回归测试最有效的手段。

从开发阶段上来讲,美团在这几个环节中的投入基本相当,他们希望通过代码脚手架的方式减少开发阶段的成本,如涉及网络的开发与后端进行API 联调的工作,如果使用联合脚手架的话就会变得非常轻松。

如何进行自动化测试?

在自动化测试上,美团的思路是从业务特点出发,对美团的业务形态进行了分析,他们发现几乎所有业务线都可以落到一个套路中来:首先业务有它的入口,通过入口可以进入到业务线的主流程,如列表、详情、购买、售后等。配合主流程的各个环节会有大量的信息增值服务,比如攻略、地图、相册等增值服务。

通过这样的业务流程对各个页面进行分析,可以得到一个结论:现在只有两种类型的页面,信息展示页面和交互逻辑型页面,前者占比超过了80%,如果对这类页面进行测试,只关注它的展示行为,会发现它并没有很复杂的逻辑;后者的情况正好相反,它的占比很少,但是它的交互逻辑会变得非常复杂,同时它内部的各种细节都会对质量有至关重要的影响,对它的测试要做得比较重,而且它的测试更多关注的是程序逻辑的实现。

然后再针对这些页面去做测试技术的选型,上图中的三角是通用的模型,涉及测试的各个场景,中间是分界线,分成黑盒和白盒两种方式,美团选择了靠近分界线的这一块,从UI 自动化测试和集成测试里选取一个子集,一个子集是UI 的截屏测试,应用在信息展示型页面,一个子集是面向UI 接口应用于交互逻辑型页面。

首先是UI 截屏测试方案,一份截屏测试需要参考图、实际效果图、Diff 分析,还包括后端返回的数据,即数据桩,还有模拟登录层出、设置时间等,同时需要把上下文的所有信息都设置成可控的,展示结果也是可控的。

面向UI 接口的集成测试模拟了视图该有的结果,可以供开发者执行测试,套用到三部曲里,第一步,设置上下文环境,设置测试数据;第二步模拟用户操作,就是用测试用例调用VM 上的命令;第三步校验结果,即监测VM 上的数据状态。有些测试用例数据一直在端上,我们要把最终发起的请求拦截住,在请求那一层检查,比如选择了下单信息,最终去发出请求看这些是否正确。

自动化测试的挑战

实施自动化测试也有很大的挑战,主要有两点:一是实施测试的成本,二是自动化测试的执行效率。成本方面主要体现在开发测试用例的人力投入和测试用例本身失效带来的额外成本(也可以说是维护的成本)。

在执行效率方面,前面介绍过通过复用二进制构建方式,把构建+ 执行时间从30 分钟优化到6 分钟,然后另一个是执行成功率,因为有15% 的概率会失败,所以需要引入重试的机制,把失败率降低到5% 以下。

自动化测试的收益

自动化测试带来的收益,首先最明显是线上质量的提升。另一个是对研发效率有很大的提升,这主要体现在对迭代频率的影响,因为一旦对应的模块实施了自动化测试,就只需要抽查2% 的测试用例。

6 未来之路

对于未来,梁士兴表示他们希望把前面测试用例通过平台化的方式统一管理起来,同时会在这些场景里面对日常开发有很大的效率提升。另一个是代码脚手架,从上文迭代周期可以看到这块也是值得去做的。

演讲嘉宾简介

梁士兴,2009 年毕业于北京航空航天大学,毕业后在 IBM 中国研发中心工作了 5 年,2014 年 7 月份加入到美团点评,现任职为技术研究员。从个人贡献者转变成为小团队的负责人,进而成长成为三端的基础服务负责人,其间经历了美团客户端业务架构演变的全部过程,因而对客户端的业务架构有了进一步的理解和思考,愿意与大家进行分享。

感谢覃云对本文的审校。

2018-01-24 16:514604

评论

发布
暂无评论
发现更多内容

Lean UX 教你设计如何驱动产品

Yanel 说敏捷产品

产品 敏捷 设计

基于mysqldump聊一聊MySQL的备份和恢复

麦洛

MySQL

给学妹的 Java 学习路线

武培轩

Java 学习 程序员 程序媛

2020年2月北京BGP机房网络质量评测报告

博睿数据

APM 机房 评测 世纪互联

Zabbix实战指南

橙子冰

技术 运维 监控 运维自动化 zabbix

python实现·十大排序算法之希尔排序(Shell Sort)

南风以南

Python 排序算法 希尔排序

有价值的产品=设计思维+精益创业+敏捷方法

老彦

Scrum 敏捷开发 Agile 设计思维 精益创业

2020年2月北京BGP机房网络质量评测报告

博睿数据

孩子,我们在睡前一起来阅读 15 分钟的好书,让彼此都带着好的故事入眠。

叶小鍵

正确阅读 托马斯·奥本 Doug Antin 蒂·泰德罗克

学计算机你后悔了吗?

陈辰

学习 技术 大前端

[Git] Git 可以这么学

猴哥一一 cium

git

「开放」对协作效率的影响

Tony Wu

产品 产品设计

有点干货 | Jdk1.8新特性实战篇(41个案例)

小傅哥

函数式接口 Lambda 小傅哥 jdk8 编码

内容比形式更重要

Winann

内容 生活 工作 形式主义

ARTS - Week One

shepherd

js algorithm

Golang热更新原理

我心依然

nginx Linux 信号 Go 语言

面试官问你MyBatis SQL是如何执行的?把这篇文章甩给他

cxuan

mybatis

实用贴丨正确的「递归」打开方式:让计算机像计算机一样去计算

博文视点Broadview

Python 递归

Elasticsearch 实战

代码诗人

[GitHub] 跟我一起白嫖 GitHub Pages 做个人站点 ?

猴哥一一 cium

git GitHub GitHub Pages

一文带你彻底厘清 Kubernetes 中的证书工作机制

首富手记

Kubernetes

关于问题的问题 —— 读《你的灯亮着吗?》

YoungZY

读书笔记 读书

软件开发生产率改进之我见(一)

清水

团队管理 软件工程 技术管理

Flutter的staggered GridView详细使用

潘珉

flutter

工厂模式 (一)简单的工厂模式概念以及示例代码

LSJ

翻译敏捷行业专业外文,不只是谷歌翻译

老彦

翻译 Scrum 敏捷开发 Agile

数仓系列 | Flink 窗口的应用与实现

Apache Flink

大数据 flink 流计算 实时计算

五个“为什么” —— 读《精益创业》

YoungZY

读书笔记

游戏夜读 | 如何避免乏味?两则

game1night

李想解读《高效能人士的七个习惯》

我心依然

习惯 高效能人士的七个习惯 李想 汽车之家

Kubectl exec 的工作原理解读

米开朗基杨

Kubernetes kubelet

从分层复用到自动化测试,看美团客户端架构的演变_架构_梁士兴_InfoQ精选文章