为什么我们需要前后端分离 - TechlentWongchisum/blog GitHub Wiki

为什么我们需要前后端分离?

1.背景:

2021年三月底辞职,下家是一个小规模公司。

公司官网是使用服务端渲染(SSR)的方式去开发的,主要用Flask做Web开发。

在我就职之前,前后端是不分离的,后端工程师既要开发数据接口,还需要写前端页面。

接手之后,我感觉比较棘手。因为项目的体积比较庞大,且没有考虑性能优化问题。

前端帮忙写交互或样式时,重新编译一下项目所需要的时间约有五分钟。

入职一周时间,熟悉项目的需求和业务逻辑之后,决心给老板提出前后端分离。

2.写在前后端分离之前:

在聊前后端分离的工作之前,不妨了解一下前后端配合的一些历史。

1.MVC结构:

​ 这个就是我就职之前的前后端结构。项目的主导者是后端。后端的主要职责是负责Model(数据维护)和Controller(获取请求,进行业务处理),而前端的职责则是负责View层(视图层面)的开发,主要是开发前端静态页面的书写。而后后端开发人员获取数据并把数据写入前端页面。

​ 这个结构的优点是什么?

​ 1.这个结构的好处是前后端职责划分明确,前端负责样式交互,后端处理业务逻辑/数据存取等业务相关

​ 2.如果是小规模的项目,且前后端开发人员规模小,很容易可以上手开发,成效也明显。甚至可以不需要前端人员也可以完成一个产品的开发。如果我是老板,我有个小项目需要上线,可能我招一个会写样式的后端开发人员,就可以完成了。

​ 这个结构有没有缺陷?也有。

​ 1.项目体积过大,如果我今天需要写一个前端页面,调试过程中会需要重新编译,这段等待项目编译的过程是视项目体积来决定的。随着项目体积增大,编译所浪费的时间也会增多。所以在开发环节,效率上会有限制。

​ 2.前端方面职能有限,仅仅开发静态页面对前端来说,是轻松却缺陷的工作。样式如何抽取?页面耦合内容如何抽取?性能如何优化?职能有限的情况下,前端很难去独立处理这些问题。

​ 结论:如果需要“小而轻”的产品和研发人员,MVC结构的开发还有它的意义。但是如果需要做“大而全”,个人感觉沿用MVC结构可能不太合适,不妨考虑下面提到的前端分离的方案。

2.前后端分离:

​ 这就是目前我在做的工作内容。我认为目前的产品体积和前后端的配合情况适合这种前后端分离的结构。因为原有的结构(MVC结构)并不能处理上面提到的缺陷。所以我和老板说:“如果进度允许,产品研发的速度先放缓吧,我们先做前后端分离,把地基打好,趁着项目的体积不算过大,分离前后端的职能”。

​ 让后端专注于数据维护和业务逻辑的处理,前端做好页面/组件开发,前端维护(测试/公共抽取/接口联调/性能优化)。

​ 相较于MVC结构,其实这样的前后端分离方案,能够摆脱一些开发上的耦合。

​ 1.前后端的主要交互是通过数据接口(API)来实现。前端接入数据,写出页面。也可以前后端约定数据,前端在后端接口完成之前,利用约定的数据去写mock。在流程上就不存在“我需要等后端接口写好,再去调用”的阻塞了。

​ 2.职责明确,就像上面说的,前端做什么,后端做什么,都可以划分清楚。一个页面的接口挂了,找后端。一个页面的样式错了,找前端。

​ 前后端分离有缺陷吗?同样也有。我认为前后端分离有一些缺陷的部分:

​ 1.增加沟通成本。原先的静态页到带数据的页面,这个过程是由后端书写完成的。前端不需要关心数据方面的问题。而现在通过数据接口的形式进行前后端数据上的交互,就需要约定数据接口的格式/类型。这部分在初期前后端合作不熟练的情况下,可能需要花费的时间比较多。

​ 2.前后端分离,重构的主要工作量在后端开发人员身上。如果原先一个请求的响应,是一个服务端渲染的html字符串。后端可能需要改造成JSON字符串返回给前端。而且返回的格式可能会需要做相应调整。所以,如果需要做前后端分离的尝试,需要后端开发人员多些思考,思考“怎么调改动量比较小,且不影响原有的业务逻辑,且能满足前端的数据需求”。通常来说,是一个大的工作量。

3.其他结构

​ 还有其他的前后端配合的结构。比如前端方面用Node搭建服务,对后端接口进行适配,用于处理多端多场景请求。

​ 或者大热的Serverless等。

​ 不过这些结构我都还没有在实际项目开发过程中尝试,希望有机会可能做尝试。

3.怎么做前后端分离?

​ 前后端怎么做前后分离?我想,这个问题的关键在于“数据接口”的方面。这方面解决下来了,前后端分离的问题也能迎刃而解。

1.确定数据接口的格式:

​ 前端需要请求的接口,用什么方式去请求?请求的地址是什么?需要什么参数?后端返回的响应是什么?

​ 目前在项目开发中,我和前后端大致的约定是这样的:

// 前端的get请求,前端把查询条件放在queryString的查询条件里面
// 假设后端的一个接口是根据id查找用户的接口(getUserInfo)

// 前端的请求:
get: /getUserInfo?id=1

// post请求,把查询条件放在请求的body里面,以JSON形式传给后端
// 假设后端的某个接口是一个提交表单的请求(submitForm),

// 前端的请求:
post: /submitForm
body: {"address":"NewYork","title":"DataBase"}

// 后端的响应
// 约定code字段判断请求的业务处理是否成功('0':失败,'1':成功)
// message可以返回后端业务处理的提示,失败时可以给出异常原因,方便调试
// data可以返回处理的数据
{"code":"1","message":"Success","data":null}

其实实际开发中约定的比这些还要多,比如:后续我希望后端可以把接口改造成Restful服务的形式。

或者有些接口需要做登录鉴权,判断用户是否有权限去请求等。

再或者列表的数据返回应该什么格式。

2.技术规范和流程的制定:

​ 数据接口的问题已经处理好了,再者是流程和规范的制定。一般前后端的相应规范是由各自的开发人员来制定的,但是作为补充,前后端人员相互了解技术规范也是不错的选择。二者可以相互学习相互补充,减少一些实际开发过程中的冲突。

​ 前端人员需要哪些流程?我的理解是:

技术选型-项目创建-编码-测试-优化-部署准备

​ 技术选型:其实技术选型可以考虑的点还是比较多的,这个完全可以单独写一篇文章来讨论。

​ 创建:最初始的创建可能依赖于框架的脚手架工具(React的CRA/Vite的工具/Vue的CLI等)。如果项目数量比较少,再次创建可以通过CV(复制粘贴)去实现复用。但是如果项目的技术选型或者配置有所变动,建议前端方面自研一个项目的脚手架(比如利用CLI的方式收集开发者的技术需求,拉取git模板代码,修改配置)。

​ 编码:编码方面主要是需要做语法规范(如:eslint)和格式规范(如:prettier)等。但是也建议前端做好项目结构的划分,方便检索和开发。在我的前端项目中,大致的项目结构如下:

config // 项目的工程配置,如编译配置,前端代理配置,前端路由配置等
mock // mock数据管理
src // 前端的主要源文件目录
	assets // 前端的静态资源目录
	components // 前端的组件划分
	config // 项目的通用配置
	hocs // 项目的高阶函数
	hooks // 项目通用的hooks
	models // 前端的数据源管理
	pages // 前端页面
	services // 前端请求管理
	utils // 前端通用的工具方法
README.md // 项目概述文件

​ 测试:可以根据技术选型,选择合适的框架来进行测试。

​ 优化:优化的方向很多,比如项目的代码优化(hooks把视图和逻辑做分离),结构优化(我发现有个组件在多个页面中使用,我可以抽取为一个通用组件),工程优化(提升编译和打包的速度,简化流程),工作流程优化(比如快速部署,快速实现项目初始化等),性能优化等。

​ 部署准备:如果一个团队没有固定的运维人员,前端可能需要稍微学习如何参与部署工作(比如我i)。目前前后端决定使用Docker-compose进行部署工作。这样,前后端分别维护自己的Docker镜像,前端就需要学习怎么使用Docker(概念),学习怎么写Docker进行,怎么用Nginx等。希望能用积极愉快的心态去面对。

4.结语:

上述的言论只是一个小团队目前的前置工作。没有最好的前后端配合流程,每一种配合方式都有各自的优点和局限。

可以根据实际情况来制定和调整。还需要针对局限来做出解决。