首先介绍一下业务的背景,这里主要从3个维度展开。第一个维度是组织维度,在立项之初,恰逢美团的多个事业群合并,因前端规模比较大,横向的流动协同比较多(需要跨部门支持需求,进行跨系统协作等等)。此外,美团到店事业群新人比例比较高,校招和新员工比例很高,我们会帮助新同学快速融入团队,需要完成一些较为基础的开发工作。
第二维度是业务维度,美团到店业务迭代频次比较高,基础工程框架不仅要保证交付速度快,同时还对质量有很高的要求。
第三个维度是系统维度,因业务周期比较长,到店还存在大量的存量系统,需要考虑迁移升级和重构等问题,同时会有频繁的系统交接。
在Rome整体立项时,我们已经准备好了相关的基础设施,包括发布系统的收敛、基础架构,统一为基于S3(美团内部存储服务)加动静分离的技术架构,但是上层开发框架、组件类库种类繁多且开发方式不统一。存在问题包括:整个团队中人数比较多,学习交接、建设维护成本相对较高,而整体开发的效率比较低,跨团队之间的工程能力也很难进行复用等等。
建设之初,我们基于纯静态S3(美团内部存储服务)架构进行前端框架的建设,这源于我们早期大量基于Node.js的前后端一体架构存在一些问题:首先,事业群早期以中后台场景业务为主,对页面的秒开、SEO的诉求比较低;其次,当时Node.js生态基建还没有那么完善,前端同学需要做动态扩缩容、峰值流量处理等操作,整体的业务风险比较高。同时还存在机器成本高、开发人员能力要求高、招聘难度大等问题。
因此,在整体的建设思路和路径上,我们不会建设类Egg.js这样的前后端一体的框架;同时因为我们的框架层要解决研发流程不规范、交付质量不高等问题,也需要联动上下游的设计研发、CI/CD等系统形成一体的开发工程平台,而不只是做CLI工具。
框架约束
根据前文所述,我们一开始要解决的核心问题是学习成本,因此我们会做框架约束。
Rome在这一侧的解法:
跨技术栈开发认知一致
在实际迭代的时候,到店内部一开始整体收敛到Vue技术栈,后来因团队合并,又有了React技术栈。我们采取的第一个策略是把Vue和React整体目录保持大家认知的一致,如下图所示。而在真正开发的时候,比如配置子目录SRC下,当一个同学一开始是偏Vue,但开发React需求的时候,即使团队和业务有一些变动,TA也可以准确拿到项目快速启动,接下来摆在TA面前的可能就是特定技术栈下,对于对应的API理解是否深入的问题,这部分同学自己就可以解决。
第二是我们会保证使用Rome开发框架的整体开发调试流程和体验一致。如下图,在Vue或React框架中同学专注业务开发就行,基本上可以不用关注工程框架的相关事情。比如Vite在Vue或在React指令和表现是一致的,同学可以通过一行命令直接开始调试对应项目并进行开发。
第三,我们的整体工程能力会进行高度对齐,如上图所示。我们生态下80%的插件在Vue和React下,用法和表现完全一致,大家基本上不用关心这部分,当真正用到某部分能力,详细看对应的文档就行。
基础基建对接
工程能力:一行代码引入公司基建(CDN容灾)
当前端同学处理如CDN厂商故障等问题时,需要自行查找、学习和使用公司/开源的基建能力,解决成本较高,但在Rome开发过程中可以通过开闭式的配置一键CDN容灾生效,如下图,接入后会自动进行静态资源的降级重试,当业务出现故障时(即下图峰值部分),它会有一个明显的资源加载重试,这就是降级CDN在生效;对业务同学来说只需配置框架需要哪个能力就行,其详细配置如何注入大家并不需要太关注。
工程能力:一行代码引入公司基建(告警监控)
业务开发以外的像告警监控,对同学来说,可能也要理解很多东西。但是在企业内开发,我们希望同学可以专注业务开发,像线上告警、日志链路等出现问题,可以不用配置对应平台,我们用对应的项目Key就可以查到对应的错误总量、错误调用链路等。
工程能力:一行代码引入公司基建(水印)
我们也可以一键完成对应的水印接入,同时开发配置时有对应的配置项智能提示。各种开闭能力的属性命名语义可能没那么清晰,可以通过如VSCode中的智能提示一键跳转到对应能力的文档地址,查看它的实现原理以及使用方法。
之前组织下建设的很多能力是偏小蘑菇的形式,“小蘑菇”的语义是整体工程能力的生命周期比较短,会进行频繁的重复建设。但我们希望以一个大树的形式建设,“大树”的语义是我们可以通过跨团队、横向方式进行高质量的设计和建设,通过评审委员会把控整体的方案建设,把方案拆分到几个阶段,横向团队共建,共同完成核心能力,比如Serverless、SSR等。
工程能力生态
如果大家对工程框架的建设能力感兴趣,可以参考我们内部的效率、质量、体验和领域实践进行对应分类的建设。我们通过一线调研、能力盘点的方式建设了31个,在企业内进行建设时,有很多能力一开始可能本身成本就很高,比如统一基建接入等,大概需要 30人力/个,而实际业务需求开发一共只有几天时间,很难说服产品运营单独抽出大量人力开发前端基建能力,这部分我们就以共建+横向评审的方式,保证业务团队可以摊平整体的建设成本。
典型共建案例
Serverless SSR能力,在休娱频道的密室和优选团长端的订单管理流量分别是百万级别和千万级别,整体秒开可以做到90%左右。
整个过程是Rome + Arche团队共建并形成到店标准,业务统一落地,过程中有超过3个业务团队参与了部分能力建设。
这里简要介绍下Serverless的方案流程:
首先是访问自动降级,用户通过负载均衡命中对应的网关,命中对应的Serverless的Node Runtime,这里会有对应页面粒度的SSR渲染函数,当用户访问服务器返回 5.x.x 状态码或超时时会自动降级到CSR资源(SPA页面);即使出现了极端情况,比如 SSR 服务异常,我们也可以保证整体页面可用,差别主要在 SSR场景秒开~90%,CSR场景秒开~30%,兼顾了性能和稳定性的优势。
其次是支持页面粒度接入,在大型MPA项目开发中,可以把某个页面单独设置为SSR,不必要求整个项目都是SSR工程,构建时默认会上传CSR端构建资源,而针对SSR页面会额外进行另外一份资源的构建,在部署SSR端、CSR端资源时分别部署,用户访问页面链接时,对应命中Server端或者CDN资源。
支持自动扩缩容和流失渲染,对接公司Nest基建,支持业务无感知的峰值流量自动扩缩容;同时长列表页面也可以通过流式渲染来降低TTFB时间。
编译提速主要分两个方向进行业务落地,分别是Webpack体系和Vite体系。
编译提速 - Webpack体系优化
首先是Webpack体系,因为我们整体的技术栈分Vue和React两部分,我们会抽一部分基础的跨技术栈的Webpack配置,上层有不同团队分别维护Vue技术栈和React技术栈的特有配置,中间我们会进行专项优化,包括像Webpack5的开发优化、编译压缩器、SWC和esbuild等。
另外,我们做工具时,不仅要考虑我们本身构建工具比如Webpack,也要考虑如何和我们的CI/CD平台结合,如缓存复用结合依赖安装、构建工具做,在很多需求场景下,可以获得耗时的10倍提升,CI/CD侧我们也支持分粒度的构建,比如大型MPA做页面粒度的构建等。
编译提速- 开发时⼀键Vite
Vite主要是我们在开发时使用的,Webpack是构建时使用,除了少部分增量项目的开发和构建都走Vite,大多数存量项目都是开发使用Vite保证效果,构建阶段使用Webpack。
整体流程:首先是启动,通过Vite,比如createServer拉起页面,抹平Webpack差异;环境变量的抹平,保证客户端Webpack存量项目,将Webpack客户端的环境变量注入到Vite端;对配置文件,大家原本在rome.config.js中的Webpack配置也可以一键转换为对应的Vite配置;在下层我们会做内置的技术栈插件,包括Vue2/Vue3 SFC+JSX,包括react的内置插件等;比较繁琐的是生态兼容,在公司内这部分的工作量比较大,像我们的一些SaaS的静态资源的一些路径等,包括之前我们存量Webpack这么多年积累下来的公司基建,我们如何保证它能被注入到Vite端,包括组件库按需引入,当一些模块比如common.js的模块如何指向对应的esmodule目录等,最后我们会屏蔽一些认知成本,把Vue、React和公司依赖包内置到Vite预编译内容中。
依赖提速
主要分两部分,分别是开发阶段和部署阶段。
首先会做工程框架自身Node.js依赖的预构建,这部分核心解决的是Node.js端公司内外包资源的体积和递归依赖数量庞大的问题。依赖安装的一个核心耗时其实是递归依赖庞杂,需要逐个安装带来的耗时,比如需要安装A,其实A依赖了B、C、D、E、F、G,整体安装耗时就会非常久,同时研发同学对Node.js包体积、依赖数量一般不如面向浏览器端投放的NPM包那么敏感,这个时候预编译就很关键。
其次是把整体的依赖环节包管理工具切换到Pnpm。这部分经过调研(Pnpm、Yarn Berry、Yarn Berry with PNP等),判断Pnpm是未来几年的核心趋势,同时可以稳定发展。内部建设了对应的包管理迁移工具,来服务企业内几百个、上千个项目。
在部署阶段定制了Rome依赖安装Docker镜像,锁Pnpm版本和内置常用依赖、缓存复用,它的整体逻辑是上一次需求迭代和下一次需求迭代可能依赖包的变化没有那么多。我们在第二次发布的时候,如果能够尝试命中上一次的node_modules里的一些包,那第二次安装耗时就会有一个比较大的提升。
第一阶段的时候是强依赖Webpack和Vue技术栈的。直到2020年-2021年,像社区UI框架有Solid.js、Svelte、Vue3,构建工具有Esbuild、Rspack、Vite等且发展势头也比较好,面向这个大趋势,我们希望研发框架能够分层过渡,不再和具体的UI框架、构建工具绑定:
示例如下图右侧,大多数情况下,我们有一个新的研发框架出来,只需要开发我们对应的语言特色的插件集合就行,底层插件机制+构建工具大家其实可以保持一致的。
框架价值=覆盖范围 * 功能价值。我们的共识是建设的能力需要落地才能产生价值,核心是帮助大家业务低成本地享受好用的能力。
如下图所示,是某个业务的升级成本图,可以看到有100多个项目(成本均值~5pd/项目),业务面临几百天的成本。对团队Tech Lead很难说服业务产品运营业务阶段投入升级。对一线同学来说,虽然能力很多、很棒,但是升级风险怎么处理:编译提升10s,线上问题定位消耗一周。
这部分的我们给两个解决方案。
首先是提供迁移工具(非Rome到Rome项目):
另一个是做框架生态的大版本升级,假如一个季度推出来一个大版本,实际业务开发升级难度、成本就会比较大,业务可能也不敢升级,这时大版本升级就要提供关键流程自动迁移支持:
公司内部的一些标杆团队都是由我们Rome团队升级+写报告,标杆业务由基建团队升级的话,ROI可能会比较高,我们升级通过工具将我们的二次调整,整体成本可能会非常低,2~4h就可以完成一个中等存量项目,再由核心业务同学验收、线上灰度跟进等。
我们Rome的工程开发辅助工具是基于IDE的。一般业界的开发辅助工具两种形式,下图是Vue UI和VSCode的拓展图示:
理解:对于Web形式,业界以Umi UI(更先进)和Vue CLI为主,虽然它们都是基于Web实现,但出发点不太一样,Vue UI核心是做体验提升,支持工程创建CLI可视化,工程配置分析等;但是UMI UI要服务公司内部,更多的是做提效,支持一些组的资产插入、执行工程任务比如build/lint等。
基于Web做开发辅助工具
好处:跨IDE的成本比较低,前端同学覆盖会比较全,也可以解决IDE内功能交互UI受限问题。
问题:VSCode不开放这部分的UI侵入能力,一方面心智认知类Umi UI的趋势其实把开发时的用户心智切换到Web端。但我们研发时,其实要在IDE看代码、理解代码、写代码,当我们热更新起来以后,像构建、物料插入、Link等其实比较低频,就会带来一个问题,我们研发时的心智很难切到对应的浏览器端。另一方面研发链路,长期来看,不管是业界还是美团内部的研发趋势中就一部分场景,后续肯定是用Cloud IDE,但是我们工程框架的Web端这种开发辅助工具,如果通过Web形式实现,就很难融入到我们的研发链路中。
IDE侧方案确实存在UI交互受限、视窗面积、跨IDE开发成本等问题,因为同学在开发时,VSCode的面积就这么大,每弹出一个Webview就会侵占用户的开发视窗,会比较难受。
选型原因:
提效率的一个例子是“一分钟内部署”,这里主要解决我们高频的测试环境部署流程冗长问题。2021年我们Rome⾮线上环境发布⼤概10W次/年,核⼼流程369s/次,如下图所示:
通过我们的开发辅助工具,可以做到页面粒度的CSR/SSR发布,同学不需要关注跨平台之间有哪些工作量,我们会在背后同步并且流转DevOps节点,把原本我们要在研发流程中,企业内要做质量分析、规范卡控等部分做异步,然后异步进行触发,整体的链路就可以保证一分钟内完成部署。
IDE可以做开发时质量检测,开发时会有历史的线上故障提醒。
哪些问题我们之前已经出过很多次线上故障了,在开发时就会实时检测代码并提示这部分应该进行修复,否则后续可能会出现线上故障。
它和ESLint的区别:
我们内部研发时不仅要开发,还有设计稿,包括DevOps平台的流转等,也会上下游联动,保证设计可以快速到DevOps平台,DevOps平台可以一键打开本地VS Code,记忆历史的仓库和分支并快速打开,也可以快速流转到设计平台,开发完返回剩余流程。
开发时也会给到大家文档提示,只要研发人员托管到到店内部的知识库,就可以在开发时,自动进行相关文档的匹配和跳转提示。
得益于业界IDE标准的高度统一,一般CloudIDE仅需一次开发,即可本地、云端IDE自动安装开发辅助,能力完全一致。
上文中从接入公司基建、编译提速、框架大版本升级等方面提到了很多工程能力,过程中也建设了升级、迁移工具,而作为企业内框架,也有一些问题和指标需要考虑。
问题和指标
在业务规模不断扩大、能力落地覆盖范围及用户数量都在不断增加的背景下,框架现状衡量、框架如何发展等问题逐渐显现:
Rome的用户群体从纯B端业务到覆盖B&C端业务,业务节点已覆盖4个事业群、15个事业部;对比2020年,项目规模已经扩大了11倍,公司内共落地1000+项目。
框架价值=覆盖范围 * 功能价值。能力开发完我们需要尽可能清晰化并提升落地覆盖,在统计运营上可以通过CI/CD平台发布过程数据、Git仓库扫描数据、框架运行时数据打点、IDE使用数据来做框架能力和用户规模数据采集;同时结合标杆团队、标杆业务以组织维度框架生态能力最大提效数据,并对能力验证和优化有正反馈,促进能力高质量、更大规模落地
面对已建设的生态能力,如果纯从能力开发视角出发、缺少有效的衡量体系,会导致有限的人力会被分摊到非常庞大的工程体系内:(1)已有的好能力因为没有度量数据,感知弱,在人员变动等客观背景下没有得到持续足够的推广导致好能力没有获得足够的落地,导致收益低于预期。(2)初期能力建设完后产生持续的维护成本,对部分使用率低的能力无法感知,未及时做出关键判断,产生一部分人力浪费。(3)对存在优化空间的能力,由于未及时拿到使用数据,不了解落地问题,能力未得到持续验证和优化而导致收益不达预期。
从人力节省、质量、缩短交付周期等方面建立有效的产品价值衡量体系,对齐框架年度输出指标并持续运营。
不变的是要深入结合业务架构重点支撑阶段核心业务场景,紧跟社区做一些先进能力,同时需要通过数据来辅助判断阶段重心是提升框架核心能力覆盖率,还是要建设新能力。
收集客服数据,沉淀高质量的FAQ,保证增量问题不被重复客服,引入AIGC智能客服等方式降低增量能力客服成本。
解决思路
统一定义并梳理指标来源,结合上下游平台提取数据、对缺失数据采集并持久化,通过快照等形式完成数据层聚合和差异抹平;中间层会按照定义的大盘指标对数据进行统计拟合校准,包括项目覆盖率、核心能力使用率、接入率、研发环节效率等等;上层会按不同的业务部门、时间区段等提供可切换的覆盖、效能、质量等数据看板。
数据来源层:
数据统计层:
大盘指标层:
交付(各模块的数据看板):
运营模块:
整体Rome业务实践如下图所示:截止2022年,落地了1400多个工程项目,资产库的数量有100多个,到店多数Web项目是用Rome开发,大家打开美团App,可以看到到店业务H5页面都是通过Rome进行开发的,有B端系统、C端的H5,还有我们美团内部的React Native。
工程框架不止于CLI。要从需求交付的视角做框架,整个工程链路可能涉及到应用创建、应用认证、开发基建配置、依赖安装、编码、Mock、调试,包括提交Lint、还有Git、Install、Int、Build、Upload、灰度、Publish等等。
我们要核心关注高频的、规模化、价值比较高的环节:
未来趋势(个人阶段视角):