各位同学晚上好,今天我给大家分享一下网易在前后端分离的一些工程实践
今天的内容我们主要从以下几个方面来介绍
- 背景介绍
- 解决方案
- 协作体系
- 案例展示
这是一个比较常见的WEB系统的高层级架构模型,包括网易的很多产品基本上也都是采用的这种模型,在这个模型中红色部分表示前端要做的事情,蓝色部分表示后端要做的事情,中间绿线分隔前端和后端可以解耦出来的内容,所以在这种模型下我们可以看到:
- 数据接口: 前后端基本没有太大耦合性
- 视图填充: 目前很多项目由前端负责的视图模板还是重度依赖于后端的模板环境
所以我们今天分享的议题就专注于寻求一种可以彻底分离绿线上下两部分的解决方案,并以此来提升项目过程的协作效率
在寻求解决方案之前我们还是先来分析一下目前这种模型下存在的一些问题,我们还是从数据接口和视图填充两部分展开
-
数据接口的问题
-
缺少可持续维护的接口规范,这个问题主要表现为:
- 没有规范
- Word/Doc 编写规范
- 随着项目的迭代规范与实际不一致
-
缺少对规范数据的充分利用,没有规范的就不说了,这里针对有规范的情况下,这个问题主要表现为:
- Word/Doc编写的规范利用率低,无法做自动化工作
- 使用接口管理平台管理的规范只用于mock数据,测试接口
-
缺乏规范覆盖范围的广度,没有使用工具或平台管理规范的就不说了,这里针对使用了这些平台管理规范的情况下,这个问题主要表现为:
- 平台只能定义异步请求的数据接口规范
-
-
视图填充的问题
-
紧耦合于后端模板环境
需要后端先给配置路由规则、模板环境、预填数据等才能查看页面效果
-
编译运行后端服务效率低
随着后端完成的功能越来越多本地编译启动后端服务的时间越来越长,严重影响到了前端的开发效率
-
缺少对视图模板的接口规范
从广义的接口定义看只要不同部分存在相互协作的约束规范即可视为接口进行管理,所以模板视图和模板环境之间也应该做为接口进行规范化管理
-
针对以上的问题,我们的解决方案也从数据接口和视图填充两个方面去考虑
-
数据接口解决方案分析
对于数据接口这部分比较常见的解决方案就是使用接口管理平台来管理接口,但是这个接口管理平台到底要管理哪些接口这个是我们要考虑的问题,接下来我们以WEB系统为例,来看一下哪一些东西可以以接口的形式用接口管理平台来做规范化管理
这是一个比较常见的带异步数据载入的页面从输入地址到整个页面绘制出来的过程,通过这个过程我们就可以抽取出前后端都需要关注的几个元素,这几个元素之间的关系我们可以用以下方式来标识
这里每个关系对应的前后端关注的内容主要包括:
- URL对应的页面逻辑由前端来完成,而这个页面需要用哪个模板来填充则需要后端来配置,所以在这个关系中我们需要定义个页面与模板之间映射关系的规范
- URL对应的页面需要发送哪几个异步请求加载数据的过程由前端完成,而异步接口的具体实现则由后端来完成,所以在这个关系中我们需要定义页面与使用的异步接口之间映射关系的规范
- 模板的里的结构和填充数据的过程由前端来完成,而填充的数据模型由后端来组装,所以在这个关系中我们需要定义每个模板与预填的数据模型之间对应关系的规范
- 异步接口的使用(输入输出)由前端来控制,而接口的具体实现由后端来完成,所以在这个关系中我们需要定义每个接口的地址、输入、输出的数据结构等的规范
这样我们就可以知道我们可以利用这个接口管理平台来管理哪些规范,主要包括:
- 页面规范:定义页面与模板和接口的关系
- 模板规范:定义模板与预填数据模型的关系
- 接口规范:定义接口与输入输出数据模型的关系
-
视图填充解决方案分析
对于视图填充这部分的前后端分离方案也有很多,我主要总结了目前市面上比较典型的几种方式
- SPA
- 代理转发
- 服务器中间层
- 本地模拟容器
-
SPA
首先我们来看一下单页面应用SPA(Single Page Application)的解决方案,前面我们也介绍了做前后端分离解决方案的主要思路就是在上面的层级架构模型中把红色的前端部分和蓝色的后端部分以中间绿色线为界隔离开来,既然数据接口容易隔离,服务端视图填充不容易隔离,那如果不用或者极少用服务端视图填充方式,改用前端视图填充不就可以解耦了么? 而SPA则正好是这种思路的一种主要实现,更类似于移动APP、桌面应用类型
在实践中我们确实发现SPA方式的项目在前后端分离协作这块要比重度依赖服务端模板的项目容易很多,以下是SPA解决方案的大致原理图示
所有的解决方案都有其适用性,这种解决方案也不例外,所以我们需要了解其短板所在,对于这种解决方案我们主要需要考量:
- SEO方面比较弱,需要采取更多其他解决方案来弥补这方面的缺陷
- 对前端专业技能要求高,更高要求的系统设计架构来满足如性能(载入、内存管理等)、模块化、前端内部协作等问题
-
代理转发
这是一种针对某种特定场景下的解决思路,我们先简单看一下大致原理
大家可以看到在这种方式下对原有的服务端架构模型并没有做调整,前端通过Node独立开发了一套中间代理层服务,这一层的一个主要任务就是处理原先的服务端视图填充任务,另外我们也可以看到原先本应该返回页面结构的视图层不再返回页面,而只返回视图的填充数据模型,所以这也是前面我们说的一个特定场景,需要原有服务支持多视图输出
这种解决方案更适合于后端模式比较固定的已有项目,是一种思路但是通用性不强,主要需要考量:
- 对后端的侵入性依赖于后端的多视图支持能力(如SpringMVC的ContentNegotiatingViewResolver)
- 代理层需重新定制视图模板
-
服务器中间层
比代理转发更进一步的解决思路是既然在代理转发方案下原有的视图层已形同虚设,那么索性就更进一步直接把视图填充的这部分职责归到前端不就行了么,确实是这样的,那么这种思路的整个分离过程就类似如下图所示
针对这种思路,我们实践过程也会有几种方式:
- 前端使用已有后端技术接管包括控制层及其之前的所有事务(需要前端学习原有后端语言如Java/PHP等,前端还是需要在本地运行后端环境)
- 利用Node开发一套独立的中间层(包括控制层和视图层)解决方案
在此方案下大多数实践过程中前端除了接管视图填充外同时也接管了数据接口,因此最终服务端更多的偏向于提供业务服务为主,而前端因为可以介入后端的一些业务逻辑,因此有更大的能力做一些前后端集成的解决方案
对于这种解决方案我们主要需要考量:
- 因为前端介入了服务器端,在提升了前端能力的同时也引入了新的风险
如果采用的是第二种方式,还需要额外考量:
- 已有服务器端的一些成熟解决方案需针对这种方案重新做相应的开发
- 老项目迁移成本和后期维护开销的权衡
-
本地模拟容器
因为视图填充解耦的关键问题在于视图模板和视图环境的紧密耦合,如果说有一个简易的容器可以模拟出视图环境的主要功能的话,那么我们是不是就可以做到解耦呢? 接下来我们来看一下这种方案的主要过程
这种方案下我们的主要思路是在开发阶段引入一个可以解析模板的容器,而产品上线发布的时候仍旧运行在已有的模板环境中,容器对模板的解析能力可按需进行扩展
对于这种解决方案我们主要需要考量:
- 需要有一套通用的模拟容器
- 模拟容器扩展出的部分模板解析能力仍旧需要依赖于特定的模板环境,如Freemarker仍旧需要前端具有Java环境
-
网易实践方案
有了前面我们对数据接口、视图填充解决方案的分析,接下来我们就可以结合各方案的特性做适用于实际企业环境的整合方案,网易针对目前的产品及项目环境在前后端分离实践过程中给出综合方案如下图所示
该方案是一套集规范、工具、平台于一体的工程化解决方案,主要目标在于帮助产品在已有的项目基础上以最小的成本实现规范化、工程化的高效开发协作体系,通过项目各个环节的密切配合实现一个闭环可验证的体系,以保证各个环节使用的规范的一致性
该方案具有以下特性:
- 低侵入性,对老项目可无侵入式引入并优化项目协作过程
- 高效率性,通过接口管理平台输出协作规范使得各端可以完全独立并行进行,提供丰富的效率工具支持使得各端可以高效生产,随后可进行无缝联调衔接
- 高通用性,可适应到各种后端环境的新老项目、接口管理平台的规范可以通过效率工具自动生成各种语言代码
- 高扩展性,模拟容器支持的模板可扩展、利用接口管理平台的数据可扩展出更多面向各端开发者的效率工具
- 可验证性,闭环可验证的一致性保证,通过测试环节对接接口管理平台自动化测试保证平台上数据的一致性
- 可操作性,具有从交互到上线完整的生产线支持,具有可具体实施的流程规范及操作步骤
接下来我会重点向大家介绍一下网易的这套实践方案
这一部分我们主要介绍一下网易的前后端分离实践方案下各角色的协作方式,在实践方案的指导下我们的项目协作流程就如下图所示
这里前后端的设计过程主要是系统设计过程而非视觉的设计过程,这个流程中我们可以看到在有了交互输出之后,各角色(包括视觉、前端、后端)就可以并行的开始展开各自的流程了,那么我们怎么来保证这其中各角色独立并行的流程顺利、有序、高效进行的呢? 下面我们以前后端流程为例来说明,如下图所示
在实践方案中我们可以看到接口规范是核心,是保证各端可以独立并行的先决条件,前面我们对解决方案的分析可以看到单纯只有接口规范还不足以让我们能够顺利高效的完成各端的分离,因此我们的实践方案又提供了多种工具来支持各端分离的过程,其从交互到测试过程之间的完整流程如下图所示
从上面的流程中可以看到在我们实践方案的整个体系中涉及的平台、工具包括:
- 接口管理平台: 该平台主要用来管理接口规范数据,是整个解决方案的核心,后续各效率工具均可以从该平台获取到规范信息
- 工程构建工具: 根据接口管理平台的规范定义,配合项目已有的工程规范,自动生成项目工程、工具配置、页面代码、模拟数据、测试代码、用例数据等等
- 本地模拟容器: 提供给前端开发过程用于本地运行调试页面的环境,具备WEB服务、模板解析、请求代理等功能
- 接口测试工具: 提供给后端开发、测试过程用于模拟浏览器发起异步请求,工具对接接口管理平台直接导入规范信息、管理测试人员的用例数据、支持直接导出自动化测试代码和用例数据
有了上面对我们实践方案的认识后,我们再来看看在此方案下各角色是如何独立开展各自的流程
-
前端
这是前端本地开发的整个过程
前端借助于接口管理平台和本地模拟容器从后端独立出来,通过接口管理平台获取到页面预填、异步接口的mock数据(这个过程也可以脱离接口管理平台在本地mock),通过本地模拟容器隔离真实服务环境完成WEB服务、模板解析和请求代理功能
-
后端
这是后端本地开发的整个过程
后端(或者测试)借助于接口测试工具从接口管理平台导入规范信息模拟浏览器发起请求进行接口测试,支持缓存历次测试用例数据,帮助导出自动测试代码和用例数据
-
移动
这是移动端本地开发的整个过程
移动端我们主要借助第三方代理工具或者本地模拟容器来做接口代理,通过工程构建工具直接对接接口管理平台导出所有接口的mock数据,同时根据使用的代理工具的差异导出不同工具的离线或在线配置文件(目前支持Fiddler、Charles)
-
测试
测试是保证接口管理平台规范一致性的重要环节,项目提测之后首先要做的是一次规范验证,如果规范验证被认为是失败的,那么此次提测会被打回重新检查
这个过程我们主要借助工程构建工具对接接口管理平台导出测试代码和用例数据工程,这个工程可以整个到自动测试集成平台上自动运行,在规范验证失败的时候会通知到相应开发和测试重新检查接口平台定义的规范与实际提测的规范的一致性
为了给大家有个直观的感知,我们接下来用一个简单的案例来讲解一下这里从交互到联调流程的具体操作,我们以如下图的交互稿为例
-
系统设计阶段
系统设计阶段主要是各端开发工程师针对产品需求说明、交互设计稿开始设计系统架构、拆分子系统、划分子系统模块、协调端与端之间的接口规范,这个阶段各端根据实际情况输出若干系统设计说明书等文档,除此之外更重要的是输出端与端之间协作的接口规范,而这个规范则可以借助接口管理平台来完成,如下图所示
我们实践方案中的接口管理平台主要以页面为主线来组织整理每个系统,每个页面会使用若干的模板进行填充,可以发送若干的异步接口来操作数据,所有这些页面、模板、接口可以用统一的数据模型进行抽象
接下来我们简单了解一下我们的接口管理平台
页面在接口管理平台上定义就可以如下图所示
根据前面的介绍我们需要定义的规范包括:
- 模板
- 接口
- 页面
-
定义模板规范
模板规范的定义主要包含两部分:模板文件路径、模板预填数据,在接口管理平台的模板定义如下图所示
模板预填的数据模型由两部分组成:通用数据(所有页面都需要预填)和特有数据(某个页面特有的数据),在接口管理平台我们可以先定义一个这样的通用数据类型
在每个页面可以先导入这个通用数据,然后再定义页面特有数据,这样我们针对所有页面预填数据后期只需要维护一个通用的数据即可
-
定义接口规范
同模板规范类似,针对接口规范我们也可以先预定义一些通用的数据,如下图所示,我们可以定义一个通用的响应的数据结构
或者定义一个通用的分页请求和响应的数据结构
所有这些通用的数据接口中根据不同接口可变的字段使用可变类型标记,然后我们从交互稿中抽取出页面用到的接口,如下图所示
根据交互稿抽取接口使用的数据结构
最后完成接口规范的定义
-
定义页面规范
在接口管理平台定义页面规范的过程如下图所示
-
编码阶段
编码阶段主要是开发工程师根据系统设计阶段的输出,用代码来实现系统,包括技术方案的选型、项目框架的搭建、工具及环境的配置等,而在这个阶段我们则可以借助构建工具来对接接口管理平台帮我们做很多自动化的工作,进而提升我们的开发效率
以下是我们利用构建工具结合项目规范通过对接接口管理平台自动生成项目工程的过程
根据我们的默认规范生成的项目结构中几个主要内容如下图所示
-
自测阶段
自测阶段主要是各端的工程师验证自己编写的代码的正确性,按角色不同,测试方式也有所有不同,比如对于前端和移动端工程师来说,主要是需要测试各种可能的值会不会影响界面展示;对于后端工程师来说,主要是测试提供给客户端工程师使用的接口的正确性,对不同的输入参数是否返回了预期的结果
-
联调阶段
联调阶段主要是在各端完成各自的业务逻辑后进行对接测试
这个阶段相对比较简单,只要各端按照系统设计阶段约定的规范进行,这个阶段只要回归一下即可,下图是本地模拟容器的路由配置文件,这个文件由构建工具自动生成
这个阶段我们只需要调整一下路由配置即可实现单个接口、多个接口、全部接口的联调过程,如下图所示
以上是我这次分享的全部内容,希望能对大家有所帮助