这篇文章是当前发布的上一年,2022年写的,文中对 rsc 吹得有点过,但我懒得改了这并不是该文的重点
因为我发现很多人搞不清楚,前后端不分离具体被批评的核心矛盾点,大家众说纷纭,公说公有理婆说婆有理,所以我希望能用一种对比的方式给讲清楚,顺便也讲给思想固执的后端工程师看
这里我加上了文章末尾的总结,如果你有不认同我的观点也欢迎评论区指责,我诚恳的接受大家所有的反对意见
背景
由于工作的原因最近和服务端渲染(SSR)接触的比较多,这里并不只是单纯的使用某个 SSR 框架进行业务开发,所以为了更好的利用这项技术,我调研了市面上几乎所有常用的,有些名气的 SSR 框架的特点,同时呢,公司内也有位老 java 程序员,受他的影响我对于前后端不分离的技术也有了一定程度的了解和认知
所以我想聊聊这个老生常谈的话题,因为我意识到当下时期所谓的前后端不分离和曾经的不分离是有区别的。看完或许你会对前后端分离有新的看法
尝试站在后端看分离和不分离
和老后端多番交谈和比划后,于是我就开始思考,所谓的服务端渲染和后端的不分离使用模版渲染页面,其实本质上来说可能就没什么大 的区别。抛开那些上层的差异来谈,大的方向是一模一样,而细节会有众多不同,这些应用的做的最本质的事情就是:在用户的页面响应完成后,能够立即返回带有内容以及数据的页面。或者在这之前能够在服务端提前为前端做点什么事情
分离的情况下
以当下前端的 SSR 技术的特点和实现过程来说,还反而把这一过程变得复杂了不少
拿 remixjs
对于数据处理的方式来举例子,官方推荐所有的接口请求都尽量放到服务端来请求,然后通过 loader
动态注入到页面,然后在组件即可直接通过 hook
等来直接取值来消费应用数据,而应对接口请求则是使用 action
的服务函数做处理
那数据哪里来呢?还是后端。
除非自己用前端搞全栈,不然前端操作数据库会很危险,各方各面的问题也有许多,具体内容网上一搜一大把。如果不用前端技术做全栈那现在流行的 ssr
框架搞得后端能力,要么鸡肋,要么繁琐。总结:要么不能用(remixjs
这种就是给自己多找麻烦,不能用),要么不好用
以前端的角度来审视工足量,因为请求放在了服务端,同时也做了 SSR,所以 SEO 和页面初始化的用户体验确实是上了个档次,但换来的是服务端的麻烦性。因为前端只是消费数据的一方,数据也不会凭空出现,让前端去查库也不合适,因为数据库方面等等也不是前端的业务范围,所以这种做法实际上是把一部分前端的工作内容提前到了,服务端接收页面请求那一刻开始
所以,虽然优化了用户体验,但是复杂度却一点都没少,因人而异可能复杂度还增加许多,因为需要多学一个框架的语法和使用,以及少许 node 方面的知识
接着我们来看看,假如换做是不分离的情况是什么样的
如果是不分离的情况,后端可以开个静态资源服务,对于 java 来说,分离时提供的是接口,不分离就是直接提供数据给模板去注入和渲染,也就是 controller
层提供的逻辑变化了而已
得利于不分离的特点,数据和视图层的结合会变得更加容易和紧密,像是前端对于资源的处理和数据的处理,都会有响应程度的简化甚至是省略,整体来说不分离的性能和复杂度反而降低了许多
目前的结论:但就对于数据和资源的处理上来说,不分离是要比前端 SSR 要强,甚至是强许多的。服务器要比浏览器处理的更快,语言上后端语言对于计算性能会更优
不分离的不足 & 新的想法
说完了优势再来聊聊缺点和弱势,不然这么好的东西也不至于被时代所淘汰了
不分离最致命的点莫过于,前后端的工作重合了,前端排完了页面但是没数据,就没法继续写了。而后端给页面绑定完数据但是发现样式崩了还得喊前端来改,这样的工作的效率是极其低下的,所以前后分离才会被真正的大力提倡。并且分开后,前端有多了更多的自由和自主控制权,待形成圈子和生态后,还可以自主发展更多的特性,在不被后端牵制的情况下去做更多复杂的页面效果和处理逻辑
到这里好像已经有结论了,以技术层面来看分离和不分离都有各自的好,以项目和工作层面来看,只要是上了些规模肯定是分离强于不分离
但是这里我又有了一个新的想法,因为后端能够轻松解决当下卡前端脖子的事情(SPA 初始性能不足,SEO 等),所以能不能在兼顾前端自主的情况来,来绕开工作重合这个致命伤呢
就比如说,有没有可能让前端学会一点点后端方面的东西,只需要懂得怎么自己绑定数据以及基本的文件操作即可,这样做相当于把接口调用的行为换成了,如何使用后端的语法来给页面注入数据而已,原先的接口请求源变成了后端提供的函数,连接口封装的事都省了,而代价可能并没有想想中那么大
假如行得通的话,前端就依然可以继续保持自由灵活,自主发展生态圈,同时还能解决初始化的性能问题了,解了争论前后端分不分离的核心点
可能你会有这样的疑问,并不是所有的后端都是 java,比如 c# python 等都是有可能的,总不能说做个前端把每个后端语言的特性都浅尝辄耻的学一遍吧
确实是不现实,所以这里最好的办法应该是约定俗成一套业界规范,亦或者是出个中间对接层,只要符合了这些要求,那么不光是前端学起来轻松,可能一些类库都能变得跨语言互相调用了
新的结论:不分离是有希望在保持现有双方优势的情况下,还能绕开工作重合的限制,保证性能的同时各玩各的
这就解了曾经的时代面临的核心矛盾
峰回路转
感觉这个结论所幻想的现实已经算是比较理想的了,假如这个结论真的成立,那么不分离的技术至少在我看来确实是要优于前端的服务端技术的
还有一点得提下,对于前端来说的 SSR,其实并不能算单纯的 SSR,它有个词叫 BFF,专门为前端服务的服务端,SSR 只是其中所包含的一部分,有人可能会拿这点来抨击以上的观点,但是我想强强调下,这其实不冲突,无非是细节更换了而已
我的阐述绝大部分都是站在后端的不分离的角度来思考问题的,因为我本身是一名前端,如果我总是站在自己的前端的立场上说话就没法去讨论了
在非常理想的情况下,我从后端出发给可能遇到的问题都给予了一个解决方案,并且在尽量不干涉现有前端生态组织的情况下,去让不分离变得合理化,变成可行的,可最终思考下来发现还得反转
因为实际上现实可能并非如此,前后相交的那块是最大的不稳定因素,靠业界约定俗成即意味着,可能大框架相同而细节却截然不同的情况,这玩意就没法搞了,谁搞谁恶心
所以会发现,如果架构上需要搞前后端的中间层,来给前端提供服务,重点是给前端提供服务,那么其选择只能是 nodejs,那这和现在用 nodejs 做全栈相关的有什么区别
站在前端看服务端
其实让两个不同道路上的东西,强行要它们如同同个事物那样工作本身就是有问题的,再加上前端的生态已经建立,技术也已经成熟,即便存在某些站在非前端立场上觉得不合适,甚至是不理解的情况,但从长远、全局、可持续发展的角度来看待问题,当前前端技术,可能不是最完美的,但确无疑是最合适的
这就是我建立在对于双方技术的认知上,以对方的情况为出发点,从开始觉得认同,再到自我驳倒的思考过程
如果为了追求效率和自己爽就选不分离,怎么舒服怎来
可如果是为了团队和规模则必须分离
这里说的分离是指,前后端的职责分离,而不是前端就应该只能局限于浏览器内写页面。千万不要因为很多后端的虎狼之词觉得,这种看似合理的协作模式才是理所应当的,比如如果你听到以下的言语你是什么想法,会进行怎样的反驳?
"你们前端都开始操作服务端了,那还要我这个后端干什么,nodejs 那么垃圾那么不好用还不来杯咖啡,来杯 java,java 不行就 golang"
如今的前端亦菲彼时的前端,因为前端操作服务端的好处其核心并不应该是和后端强饭碗
大家需要分清楚,用 nodejs
写中间件,写网关写 xx 就是前端干涉后端了,这是不对的。这些内容就不属于前端的业务范畴,只不过恰好前端的某些技术栈适合做,他们拿来做了而已
而 ssr/bff
则是为了前端服务的一个层,它是能真正帮衬到前端解决问题的,这才是前端的工作范畴
前端的同学众所周知,前端的首屏压力是很大的,spa 的 seo
也是很需要解决的问题之一,这都是可以通过服务端能力解一定程度
其他的能通过服务端解决的问题,比如 react
团队推出的 rsc
- 对于前端来说极致的数据加载能力
- 超强的用户体验
- 特定情况下能提高前端客户端的性能------比如减少依赖项,减少打包体积,减少首屏的请求等等
至于前端操作能写接口之类都是顺道的能力,是锦上添花的辅助,毕竟哪个正常人会指望用 ssr
框架当 api
框架使用啊喂,你们的架构师不会 k 你吗?
总结
- 如今的前后端不分离的概念已经不同于往日了
- 前端操作后端不等同于传统意义上的全栈工程师,它依然是前端工程师 only(这个很重要,因为很多前后端想不明白这个理)
- 前端操作服务端能够有效解决前端的某些问题(seo 只是比较人尽皆知的一个),之所以相关的讨论很少,是因为没有一个成熟的方案让前端铺开来做很多事,这不是个人的问题,但未来我认为迟早会出现相关的产品