为什么要引入 BFF

上周六,也就是 2019 年 3 月 23 日,我们组织了一次主题为《重新定义前端——基于 Node 的 BFF》前端技术沙龙,我给大家分享了《为什么要引入 BFF》。以下就是这次分享的主要内容。

BS 架构发展的历史

在 BS 架构发展之处,典型的技术包括 PHP,JSP 等,那时候最常见的就是:一个人负责一个网站,一个页面一个文件。一个人承担了现在一个团队的角色,产品经理,开发,测试,运维统统一个人干,一个文件完成一个页面,包括处理请求参数,连接数据库,修改数据,查询数据,展示数据等等,可以说是一个蛮荒时代,这时候基本没有什么架构,代码质量基本全靠程序员自身素质。

很快地上述开发模式遭到普遍的摒弃,MVC 架构渐渐成为主流。值得注意的是 MVC 最早在 1978 年就被提出,那时候还都是 CS 架构的应用程序。在 MVC 架构里,Model(M)负责访问数据,View(V)负责显示数据,Control(C)负责处理消息,调用 Model(M)访问数据,并通过 View(V)显示数据。

到目前为止,BS 架构的应用体验还是非常差的,和服务器端交互也仅限于表单提交,并且会有较常时间的白屏。有了问题迟早就会有解决方案,后来出现了 AJAX 技术,我们可以通过 AJAX 技术做出非常酷的应用,当时最杰出的代表就是谷歌的 GMail 邮箱应用。以 AJAX 技术为代表的前端技术给用户体验带来了极大提升,使得前端技术在软件开发中逐步变得主流,前端技术和后端技术差别较大,抛开前端后端编程思想上的差异不谈,让一个写惯了 Java 代码的程序员去写简单的 JavaScript 还行,但是遇到富客户端应用场景就吃不消了。这就促使了一部分后端程序员去专职负责前端技术,就产生了专职前端程序员。我在 2007 年毕业后也做了 2 年多 J2EE 的,后来因为项目的机缘我才转做前端的。跟我类似,国内最初的前端基本都是从后端转来的。

那时候前端后端的协作方式有两种,第一种是前端写静态页面,后端将静态页面转成视图层模板,前端再复查后端转换的效果对不对。前端后端这么协作确实能够做出复杂的富客户端应用了,但是缺点也是相当地明显,后端必须要等前端完成以后才能开始视图层开发工作,如果前端能够一次性高质量完成工作还好,如果因为需求变动或代码质量能原因要返工,后端也要跟着一起来。第二种就是前端负责视图层,后端提供数据。这种方式解决了一部分问题,但是仍要前端后端密切配合,同事负责一块代码,要求前端熟悉后端语言,甚至了解后端架构。这两种模式都存在前端后端高度耦合的问题,沟通频繁,维护复杂,无法快速响应变化,代码的腐烂是迟早的事。

2009 年 Node 出现之初并没有引起什么轰动,但是它却带来了前端生态圈的空前繁荣。Node 让我们使用 JavaScript 的语法编写脚本和服务器端应用程序,让前端生态圈能够能够形成一个闭环。以前要做 JavaScript 的代码的合并压缩就要使用 Java 等语言编写的压缩的工具,因为编程思想和语法等因素导致前端很难了解和涉足后端的开发,有了 Node 这一切都有了可能。以 React, Angular, Vue 为代表的前端开发框架或工具给我们带来一种全新的开发模式:后端提供数据,前端渲染界面,前端后端通过 HTTP 请求传输数据。前端第一次这么独立,前端第一次这么拥有强大的能力,一切看起来那么完美,我们欢呼雀跃,前后端终于分离了。

从以上介绍来看,BS 架构的发展历史是关注点分离的演进过程。

美好外衣下的问题

但是我们还是会遇到很多问题。

  1. 前几天我们 App 上突然遇到不能登录的问题,经过排查发展可能跟企业微信版的一个修改本有关,并且有一些还不能解释的问题。
  2. 一些批量操作非常耗时,用户傻傻等待会感到非常焦虑,还在想着系统在处理吗?还是挂掉了?在性能难以提升以后,我们想通过告诉用户我们系统的处理进度来减少用户焦虑。我们想到的技术是 BigPipe,但是我怎么跟后端解释他们似乎都不懂,如果我会写后端代码,我就直接帮他们修改了,就不用这么啰嗦了。
  3. 为什么前端没有 bug,也需要陪着后端一起加班?虽然前端后端的代码可以分别独立开发,运行环境也是独立,但是毕竟需要一起部署,一起上线。
  4. 在组织人事的页面,用户期望看到排班和考勤等信息,而排班和考勤分别属于其他产品线,这时候只能通过 iframe 来加载其他产品线的页面。
  5. 我们经常听到前端抱怨后端对需求响应的太慢了,前端完成了以后还要等后端。后端抱怨前端又修改接口了,又要加字段了。

那么,怎么解决呢?那就是引入 BFF。

重新定义前端,引入 BFF

什么是 BFF? BFF 这个词是 2015 年 11 月 Sam Newman 在他的一篇博客中提出的。BFF 是 Backends for Frontends 的简写,为了前端的后端。Sam Newman 的博客还有一个副标题:Single-purpose Edge Services for UIs and external parties,为了用户界面或外部方的单一目的的边缘服务。用户界面比如我们常见的网页,或 App,外部方比如第三方 App,客户 App,企业微信,小程序等。其实这中模式更早一点就出现了,淘宝在更早一点的时候就设立中途岛项目,其主要内容就是 BFF。既然是为了前端的后端,所以跟前端更加密切,适合前端同事来负责;既然是后端,所以要部署在服务器。

BFF 负责哪些事情呢?

BFF 主要负责以下几件事情:

  1. 聚合 将后端多个请求合并成一个请求,以减少网络传输时间。这些请求可能来自一个服务,也可能来自多个服务。
  2. 适配 因为遵守的接口规范不同,多个微服务和外部服务的接口可能有很多不同,在 BFF 层可以做一些适配,给前端代码提供同一个的数据格式和接口格式。
  3. 裁剪 同样的信息在不同的客户端有着不同的展现,比如手机屏幕尺寸较小,内存较小,CPU 性能较差,只能展示部分非常重要的信息,如果和电脑上使用同一个接口,势必导致手机上页面渲染变慢,还会浪费手机电量和网络流量。

哪些公司在使用 BFF

我们最为熟知的,也是这个领域最早发力的当然是淘宝网了,同是阿里巴巴集团下的蚂蚁金服也在使用。有很多公司都在使用,只是相关信息披露的较少。

BFF 给我们带来什么

解放后端

  1. 后端仅仅关注核心业务,不再关心用户界面。不管最终产品形式是 Web 网页,App,还是公众号,还是小程序,核心逻辑都不变,都一样,都不需要后端关心。
  2. 后端仅仅提供通用业务接口,不再关心数据怎么展示,比如不管是导出 PDF,导出 Excel,还是在表格里展示,都是数据的一种显示形式,和核心业务无关,因此交给前端更加合适。

赋能前端

  1. 前端开始独立负责一个网站,有能力和机会做各种优化,想通过 BigPipe 进行优化时,也不再需要后端参与,减少沟通成本,提高研发效率。
  2. 前端基于已有通用接口,可以快速开发新产品。天下武功,唯快不破;快速开发已经成为一个企业的核心竞争力。公众号,小程序,企业微信,钉钉,快应用等层出不穷,如果我们还像以前那样用一个庞大的团队负责一个端就太笨重了,成本很大,动作很慢。
  3. 前端基于已有通用接口,可以快速客制化。如果我们把客制化当成一个新的产品形式的话,那么这个论点实际上是上个论点的推论。
  4. 前端基于已有通用接口,产品可以行业化。我们的客户很群很杂,有制造业,有零售业等等,每个行业都有不同的特点,也因为此我们公司已经根据不同的行业对顾问团队进行了划分,分成不同的行业群。在行业群成立之初,很多顾问非常兴奋,就问到对于不同行业群的客户,会不会提供不同的产品?当然他们得到了一个让他们失望的答案。如果我们引入 BFF,后端将通用逻辑封装在接口中,前端基于不同的行业特征做出不同的产品出来更有可行性。
  5. 承担更多责任,获得更多发展机会。在职业发展中,后端因为接触了比较核心的业务逻辑,所以他们在晋升中更有优势。项目负责人或技术总监岗位一般也都是后端出身,如果有了 BFF 以后,前端又了更多发挥的空间,可以承担更多的责任,可以获得更多发展机会。

扩展业务

开放通用接口给合作伙伴,多了一种合作的可能,以接口的形式提供服务,以接口的调用次数等收费。
开放通用接口给客户:我们的很多客户都比较大,有开发团队的,对于一些用户特殊的需求,我们客制化的成本也很高,得不偿失,这时候可以让客户基于我们的通过接口来实现特殊的业务逻辑。

产品质量

更加彻底的前后端分离模式,让前端后端架构更加清晰,让接口更加趋于稳定,促进自动化测试落地,从而提高产品质量

BFF 又有哪些问题

  1. 对前端开发的能力要求更高,比如至少要掌握 Node,以及后端开发思想。
  2. 对前端开发的人力需求更大,这个是很明显的,前端多了 BFF 层的开发工作。
  3. 对后端开发的能力要求更高。以前后端值对应一个前端,只需要提供前端需要的接口就行了,使用 BFF 以后,后端就显得更加抽象一些,后端开发的时候可能跟不知道产品形态,也只能通过单元测试或 PostMan 等工具来测试。如果一个接口设计的不好,或者产品需要发生变化,可能需要同时维护多个版本。
  4. 站点数量增加,部署更复杂。
  5. 多了一些内网请求,性能怎么破?一般情况下后端提供 HTTP 协议的接口,对于性能有瓶颈的,也可以采用 RPC 方式。相信通过合理拆分接口,合理使用缓存这个问题影响不大。

那么多或大或小的公司都在使用这中开发模式,相信这些问题都得到了解决,至少得到了控制。因此不需要有太多担心。网站架构是不断演化来的,不是凭空设计的。果断开始,逢山开路,雨水搭桥,相应我们会走出一条更有特色的道路来。

参考资料

  1. Pattern: Backends For Frontends
  2. 微服务下使用 GraphQL 构建 BFF
  3. 干货 | 携程机票 Node.js 开发实践
  4. 架构的本质是管理复杂性,微服务本身也是架构演化的结果
  5. 微服务架构~BFF 和网关是如何演化出来的