前端工程化:体系设计与实践
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

1.3 前后端分离

从传统网站到SPA再到同构JavaScript,前端工程师的工作内容不断加重,客户端逻辑不断复杂化。原始的前后端耦合的串行开发流程已经不能满足Web产品快速的迭代需求,Web开发者们开始尝试在开发、测试和部署等各个环节寻求更高效的协作方式。前后端分离似乎就是解决这个问题的“银弹”。

顾名思义,所谓前后端分离指的是通过将前端工程师与后端工程师进行明确、合理的分工,改善前后端协作中拖慢开发进度的环节,提高工作效率。前后端分离的核心是解耦。从开发、测试以及部署3个角度看,前后端分离对工作效率的提升如下。

 

· 从开发角度来讲,前后端分离的宗旨是实现并行开发,缩短开发周期。

· 从测试角度来讲,前后端分离令前端工程师和后端工程师更快速、精准地对问题进行定位。

· 从部署角度来讲,前后端分离将静态文件和动态文件分离部署并结合回滚策略,简化了部署流程,增强了应用程序的健壮性。

1.3.1 原始的前后端开发模式

首先要说明此处“原始”一词背后的时代意义,那是在前端工程师这个岗位刚刚出现不久,前端工程师普遍地被称为“切图仔”或者“美工”的时代。前后端典型的协作模式是,前端工程师写demo,后端工程师写逻辑和套模板。在这种原始的分工模式下,前端工程师的主要工作是将UI设计稿使用HTML和CSS进行还原,对于JavaScript的开发顶多是实现一些动画效果,业务逻辑基本不涉及。然后,前端工程师将开发完成的demo交付给后端工程师,后端工程师做的第一件工作是将demo代码中的HTML和CSS套入服务器模板引擎中,俗称“套模板”,而后在此基础上编写客户端的JavaScript业务逻辑。

这种协同工作模式下的开发效率是非常低下的。请读者想象一下,如果在进行网站的UI测试时发现某个div的border颜色与设计稿不符,或者某个模块的显示完全错乱了,这时应该怎么办?测试人员将Bug反馈给开发团队后,前端工程师对Bug进行排查,发现测试环境中某个div的classname写错了,或者某个div标签没有闭合。你可能认为这些是后端工程师套模板过程中粗心大意导致的,但是这种问题是无法避免的,人不是机器,总会有粗心大意的时候。如果一个网站有成百上千个HTML节点,这种人为过失导致的问题会被无限放大且非常难以排查。即使我们假设后端工程师百分之百不会粗心大意,如果发现上线后的网站样式与UI设计稿有1像素的偏差,前端工程师修改CSS或者HTML后,仍然需要后端工程师再重复一次套模板工作,完成后再提交测试。我们会发现,这种1像素的Bug修复需要调动整个开发团队(包括前端工程师和后端工程师)资源。这种模式在前些年非常普遍,而且很不幸的是,至今国内仍然有相当一部分团队使用这种原始的协作模式。

这种原始的前后端协作模式之所以在前些年比较普遍,一是因为当时客户端的逻辑并不十分复杂,JavaScript逻辑交给后端工程师就可以了,不需要专业的前端工程师。事实上,当时有相当一部分写demo的工作是交给UI设计师负责的,当然需要一些专业工具辅助,比如微软的DreamWeaver;二是因为当时网站的迭代需求并不像如今这么快,没有频繁的更新也就不需要特别高效的生产流水线。但是在如今的市场环境下,一方面Web应用的迭代效率是争取用户的必要手段之一;另一方面,前端技术的快速发展已经超越了后端工程师的能力范畴,必须由专职的前端工程师负责。在这种环境下,原始的前后端开发模式的弊端被进一步地放大了,前后端分离便应时而生了。

1.3.2 前后端分离的基本模式

合理的分工是前后端分离的第一步,也是后续各种优化方案的基础。团队人员按职能分为前端工程师和后端工程师,按照1.1节总结出的前端工程师的定位,前端工程师负责的内容包括以下几方面。

 

· CSS以及相关的图片等媒体资源。

· JavaScript逻辑。

· HTML文档,包括产出HTML的源文件,比如HTML模板。

 

对于前端工程师来说,后端工程师的唯一产出就是数据,包括用于服务器渲染HTML模板的初始数据和客户端异步请求接口返回的数据。

明确了各自的分工后,我们分别从开发、测试和部署3个方面分析前后端分离要解决哪些问题。

1.开发

开发阶段前后端分离要解决的问题可以按照资源类型分为两种:静态资源的处理和动态资源的处理。

静态资源指的是JavaScript、CSS、图片等,这类资源在浏览器的呈现方式是静态的,不需要服务器做任何处理。动态资源指的是HTML模板,除非你的项目不需要任何服务器端渲染的SPA,否则我们仍然不可避免地要处理前后端最难解耦的HTML模板。

静态资源的处理相对简单,因为这类文件不依赖任何服务器环境,只要最终在浏览器里解析即可。HTML模板的处理方案可以按照项目类型分为以下几种。

1)SPA项目。这类项目中不存在HTML模板的概念,所有的HTML实体内容均由JavaScript在浏览器下生成。所以SPA项目中可以将html文件作为静态文件处理。

2)HTML模板由服务器端部署的项目。这类项目最终的HTML模板需要与服务器端代码一同打包部署。由于静态文件必须由HTML引入,为了避免“套模板”,开发阶段前端工程师直接编写HTML模板更有利于快速开发和问题定位。

3)大前端项目。这类项目中前端工程师负责与客户端相关的所有文件,包括静态文件与HTML模板,这是最理想的模式。

可以看出不论是SPA还是大前端,开发阶段的前后端分离都比较容易实施。但我们不得不面对的一个现实是,目前国内的Web产品绝大多数是第二种项目类型。这也是最难以实现完全前后端分离的项目。

小贴士:之所以称为“大前端”而不是“全栈工程师”是因为大前端通常不接触数据库操作。大前端负责的并不是真正的Web服务层,而是中间层。中间层的作用主要解决的就是HTML的渲染,这也是为了实现前后端分离而探索出的一个模式。

对于HTML模板由服务器端部署的项目,前后端分离要解决3个问题。

1)HTML模板引擎的支持。

2)HTML模板的初始数据。

3)各种异步数据接口的数据。

HTML模板引擎种类繁多,并且根据服务器端编程语言的不同,部署难度也不尽相同。易部署的如PHP、Node.js、Python等,稍难部署的如Java、.NET等。目前的市场情况较之前有了比较明显的改善,Node.js的不断改进已经令很多初创团队选择Node.js作为Web服务的编程语言。并且成熟的团队通常都有中间层,Java承载着大后端数据服务,中间层使用易部署的编程语言,比如PHP、Node.js和Python。

HTML模板的初始数据和异步接口的数据都可以用Mock服务解决。前后端开发人员在编写代码之前约定好接口的请求规范和数据结构。开发期间,前端工程师按照规范使用Mock服务提供的模拟数据进行开发。Mock服务处理HTML模板的初始数据和异步接口数据稍有不同,HTML模板数据需要在服务器端渲染使用,在MVC架构模型中,这类数据通常由Controller提供给HTML模板引擎。在非大前端模式下,前端工程师如果不想花费时间与精力编写模拟Controller代码,可以在构建工具上下点功夫。在渲染HTML模板时注入约定格式的数据即可,本书将在第4章详细讲解具体的实现方案。

2.测试

测试分为两个阶段,第一个阶段是前后端工程师的单元测试,这个阶段前后端工程师的测试是独立的,各自的测试流程和结果不会影响对方;第二个阶段是集成测试,这个阶段前后端的代码进行整合,在测试环境下由专业的测试工程师进行测试用例遍历。

前后端分离首先要解决的是集成测试阶段的问题及时定位,解决方案并不是通过技术或工具,而是通过明确责任承担角色。测试工程师等同于内测用户,站在用户的角度上对产品进行使用和评估,他们反馈的问题就等同于是用户的反馈。既然是用户的反馈,那么直接责任人就应该是前端工程师。前端工程师负责所有与用户直接接触的功能和逻辑,所以有责任在出现问题时站在第一线。后端工程师的产出并不与用户直接接触,前端工程师更容易定位用户层面的问题。理想情况下,服务器端单元测试覆盖率达标并且测试通过后,接口是不应该存在逻辑性错误的。如果客户端出现因数据引起的问题,通常是因为客户端的JavaScript逻辑存在问题,比如一些side effect(临界问题)没有处理好。即使服务器端的单元测试没有达到理想情况,前端工程师通过调试工具也更容易发现问题的症结。

小贴士:前后端分离不仅仅是通过技术手段解决问题,技术和工具只是辅助,其本质是分工和角色的细分。这恰恰是目前很多团队在进行前后端分离时容易忽略的问题。

除集成测试阶段外,前后端分离还必须兼顾产品在生产环境下的质量保障问题。目的仍然是对出现问题的及时预警和快速修复。这方面的通常做法如下:

制定客户端监控系统,收集客户端问题并及时通知开发人员。

小贴士:大多数团队并未将生产环境的客户端质量保障作为前后端分离的一部分。服务器端通常具备监控、预警以及应急策略,尽可能保证服务器问题的及时处理。同理,客户端也应该具备监控机制,并且由前端工程师负责。

3.部署

前后端分离在部署阶段要解决的问题是静态资源和动态资源的分离部署。

与开发阶段类似,不同的项目类型需要制定不同的部署方案。在3种项目类型中,大前端模式下的部署方案是最简单的,因为前端工程师能够掌控所接触的所有资源。具体部署方案如下。

 

·将JS、CSS、图片等静态资源部署到静态文件服务器。

· HTML模板文件与中间层的Node.js代码一同部署到Web服务器。

 

SPA项目的部署方案稍微复杂一些,由于SPA中的html文件不需要在服务器端渲染,因此其理论上可以与其他静态资源一同部署到静态文件服务器。但是需要注意的一个问题是,不能令浏览器将html文件强制缓存到本地。如果用户之前访问过此页面,html文件被浏览器强制缓存到本地,那么即使开发人员更新了html文件,也会由于浏览器的缓存策略而无法获取最新版本的资源。除非用户手动清除浏览器缓存,而这显然是不可行的。解决这个问题的办法有两种,分别如下。

1)分别为html文件与其他静态资源设置不同的缓存策略。html文件可以使用协商缓存策略(浏览器HTTP请求返回状态码304),其他静态资源使用强缓存策略(浏览器HTTP请求返回状态码“200(from cache)”。关于这两种缓存策略的详细内容本书会在第3章介绍。

2)使用一刀切的方案,所有静态资源均使用协商缓存策略。

第一种方案不论是从客户端性能、用户体验,还是从服务器端压力的角度来讲都优于第二种。具体实施也不是很麻烦,Apache、Nginx等专业服务器软件都可以针对文件扩展类型设置不同的缓存策略。

最麻烦的是第二种项目,也就是HTML模板由服务器端部署,并且前端工程师不负责中间层或者服务器端开发的项目。这类项目通常的部署方案如下。

 

·静态资源部署到静态文件服务器。

· HTML模板文件编写完成之后由前端工程师通过SVN、Git等版本管理工具同步到代码仓库,后端工程师拉取最新代码后,将模板文件与服务器端逻辑代码一同部署。

 

静态资源和动态资源分离部署的优点是:在集成测试阶段,对于只涉及一方(前端或者后端)的Bug,相关负责人修改代码后独立进行部署即可,不需要另一方再行部署。比如CSS样式出现问题,前端工程师修改css文件后部署到静态文件服务器,不需要后端工程师再部署一次服务器端文件即可在浏览器刷新后获取修复后的文件。当然,这个优点只是针对测试阶段,因为大部分公司供测试使用的静态文件服务器是不设置客户端缓存的,这样可以保证测试环境下每次访问网站都能拿到最新的资源。但是在生产环境下必须使用浏览器缓存,所以修复生产环境的问题必须按照上述部署策略进行重新部署。本书第5章将介绍具体的部署方案。

1.3.3 前后端分离与前端工程化

前后端分离策略是制定前端工程化解决方案的指导方针之一;前端工程化的最终目的之一便是实现更合理、更便利的前后端分离开发环境。两者相互依赖、紧密耦合在一起。如果将前后端分离策略比喻成建筑设计图,那么前端工程化方案就是按照这张设计图进行具体建设的。在前端工程化这栋建筑平台上,前端开发人员和服务器端开发人员可以更顺畅、更高效地进行开发工作。