BFF(Backends for frontends)避坑指南
BFF —— Backends for frontends(服务于前端的后端),是为了让后端API满足不同的前端使用场景,而演进出来的一种模式。BFF在改善前端用户体验上起到了非常大的作用,但因为介于前端和后端之间,在落地实施过程中很容易踩坑,在这篇文章中,我们看看在实施BFF的过程中可能遇到哪些“坑”。为了帮助快速理解后面讲到的问题,我们先来简单回顾下BFF的由来和应用场景。
BFF的由来
随着移动设备的快速发展以及产品对用户交互体验的关注度增强,前后端分离的架构模式也逐渐被大多数企业所采用。在这种模式下,统一的后端API很难满足在不同场景下对用户体验的不同需求。
BFF模式应运而生,一方面BFF隔离了前端UI展示对后端API的需求,企业可以专注在后端构建核心业务能力,另一方面,BFF根据已有的后端API,快速满足前端在UI展示上的需求,来不断提升用户体验;
从知识管理的角度,BFF模式让知识边界定义得更清晰,后端专注于构建业务能力,不需要考虑前端各种场景适配的问题;而前端更关注用户体验,可以随时独立发布更新。
BFF的应用场景
面向前端
BFF为前端而生,随着前端技术(iOS、Android、小程序、Web等)的不断发展,不同前端对后端要求有很大差异,后端服务很难提供满足多个前端的统一接口,BFF则可以针对前端的特定需求,作出适配:
- 针对前端UI展示逻辑的不同,对后端API返回的数据进行裁剪和重新组织,提供面向前端的定制化格式的数据
- 根据前端业务需求,对后端多个API返回的数据进行聚合
- 对一些特定场景的数据进行缓存,提高性能,进而提升用户体验
面向后端
BFF隔离了前端UI展示对后端API的定制化需求,可以很好地支持后端服务的演进:
- 从单体应用迁移到微服务架构,后端架构的演进可以通过BFF来进行隔离,参见《 前后端分离演进:不能微服务,那就 BFF 隔离 》。
- 微服务架构内部的演进,微服务的拆分,也可以借助BFF来减少对前端的影响,参见我的另外一篇文章《迭代开发中的微服务拆分》。
BFF实现中的坑
BFF模式在前后端分离的架构模式下的确有很多好处,完美隔离了前后端,貌似从此以后前端干前端的,后端干后端的,大大降低前后端之间的冲突和依赖。然而事实并非如此,在实施BFF的过程中,大家仍然会遇到各种问题,我总结了实施落地BFF的三大常见问题如下:
重复代码
通常情况下我们会为每个不同的前端构建一个BFF,还可能会为一些特定的场景建立BFF(如对第三方系统提供API),不可避免地,多个BFF之间会出现大量的重复代码,比如可能会存在相同的数据转换逻辑,相同的API数据聚合逻辑等等。
重复代码通常被认为是一种坏味道,但在BFF这个场景下,这些重复的代码是为了某一个特定的前端服务的,因此处理这个重复要相对谨慎,如果一味粗暴地去掉这些重复,很有可能引发某一个前端需求变化会影响到其他前端应用的情况。
如果确实有些代码重复且相对稳定,可以尝试采取下面的方法来消除重复:
- 共享库,将重复的代码抽取出来放到共享库中,不同的BFF通过依赖共享库来达到代码复用,但要考虑哪些代码能够抽取到共享库中,可以参考我之前的文章 《消灭微服务的坏味道 之 共享库 》。
- 将重复的代码放到后端服务中,这种方法适用于重复的代码实际承载了真实的业务逻辑,而不只是在做简单的数据聚合和数据格式转换,那么应该把这些重复的代码下沉到指定的后端服务中。
趋向于ESB
除了大量的重复代码,在微服务架构下,另外一个问题通常会出现在业务演进过程中。当新的业务需求产生时,具体要在哪个后端服务中实现有时候不是一个很容易回答的问题,特别是不同的服务有不同的团队归属时,如果每个服务的归属团队都认为新的业务需求不是自己服务的业务范畴,最可能的结果就是让BFF负责帮忙组合各个服务的功能,完成这个新的业务需求。渐渐地,BFF朝着ESB的方向发展,变成了集成各个微服务,对外提供新能力的中间件。
这种趋势某种程度上违背了BFF设计的初衷,BFF为了适配前端而生,更关注解决前端的用户体验问题,而真实的业务能力应该由后端服务来承接,而不是BFF。
要解决这个问题,首先要清晰地定义每个服务的业务职责,为了避免服务过多很难划分清晰边界,最开始服务尽量不要拆得太小;另外要建立规则来处理新的需求,哪些需求属于BFF的范畴,哪些属于业务能力,业务能力应该下沉到后端服务中,如果现有服务无法承载这种能力,可以考虑新增服务,而不是写在BFF中。
性能问题
第三个比较常见的问题就是性能问题,相信你一定遇到过下面的场景,既然有了BFF,前端的设计开始放飞自我,可以把想展示的信息一股脑都放在一起展示,极端情况下BFF可以获取到任意服务的数据进行组合,我曾见过在一个BFF接口中调用了后端服务几十次来拼凑前端需要的数据,可想而知这个接口的性能一定很差。
为了解决这种情况带来的性能问题,通常会采用并发获取数据然后拼装的方式,这明显增加了代码实现和维护的复杂度,往往会引发新的问题。
因此,在实际开发过程中要非常警惕这种问题的发生,如果一个BFF接口调用了3个以上接口,那就要警惕了,需要分析下后端服务拆分得合不合理,前端UI展示的数据是否有必要放在一起,否则性能问题会逐渐成为一个不可避免的问题。
小结
架构设计是通过合理的组件拆分以及定义组件之间的关系,将系统整体的复杂性分散到不同的组件中,在更低的维度上解决问题,分而治之。BFF在前后端分离的架构模式下隔离了前端和后端的关注点,特别是在多个前端或第三方的情况下,BFF都是非常好的选择。然而,在实施过程中,仍然要时刻警惕,明确BFF设计的初衷,避免因引入BFF而带来了更多的问题。
参考资料
- [Sam Newman] Pattern: Backends For Frontends
- [Lukasz Plotnicki] BFF @ SoundCloud
- Frontend Architectural Patterns: Backends-For-Frontends