BFF (Backend for frontend)避坑指南

避坑指南.jpeg

BFF —— Backend for frontend(服務(wù)于前端的后端),是為了讓后端API滿足不同的前端使用場景而演進(jìn)出來的一種模式。這篇文章我們主要來看看在BFF的實施過程中可能遇到哪些”坑“,為了能夠快速理解后面講到的問題,我們先來簡單回顧下BFF的由來和應(yīng)用場景。

BFF的由來

隨著移動設(shè)備的快速發(fā)展以及產(chǎn)品對用戶交互體驗的關(guān)注度增強,前后端分離的架構(gòu)模式也逐漸被大多數(shù)企業(yè)所采用。在這種模式下,統(tǒng)一的后端API很難滿足在不同場景下對用戶體驗的不同需求。BFF模式應(yīng)運而生,一方面BFF隔離了因前端UI展示對后端API的需求,企業(yè)可以在后端構(gòu)建核心業(yè)務(wù)能力,另一方面,BFF可以根據(jù)已有的后端API,快速滿足前端在UI展示上的需求,來不斷提升用戶體驗;

另外,從知識管理的角度,BFF模式讓知識邊界定義的更清晰,后端專注于構(gòu)建業(yè)務(wù)能力,不需要考慮前端各種場景適配的問題;而前端更關(guān)注用戶體驗,可以隨時獨立發(fā)布更新。

BFF的應(yīng)用場景

BFF應(yīng)用場景(圖片來自BFF@SoundCloud)

面向前端

BFF為前端而生,隨著前端技術(shù)(iOS、Android、小程序、Web等)的不斷發(fā)展,不同前端對后端要求有很大差異,后端服務(wù)很難提供滿足多個前端的統(tǒng)一接口,BFF則可以針對前端的特定需求,做出適配:

  • 針對前端UI展示邏輯的不同,對后端API返回的數(shù)據(jù)進(jìn)行裁剪和重新組織,提供面向前端的定制化格式的數(shù)據(jù)
  • 根據(jù)前端業(yè)務(wù)需求,對后端多個API返回的數(shù)據(jù)進(jìn)行聚合
  • 對一些特定場景的數(shù)據(jù)進(jìn)行緩存,提高性能,進(jìn)而提升用戶體驗

面向后端

BFF隔離了前端UI展示對后端API的定制化需求,可以很好地支持后端服務(wù)的演進(jìn):

BFF實現(xiàn)中的坑

BFF模式在前后端分離的架構(gòu)模式下的確有很多好處,完美隔離了前后端,貌似從此以后前端干前端的,后端干后端的,不會再有沖突,一切是那么美好。然而事實并非如此,在實際實施BFF的過程中,大家仍然會遇到各種問題,下面介紹幾個常見的實施BFF過程中的問題:

重復(fù)代碼

通常情況下我們會為每個不同的前端構(gòu)建一個BFF,還可能會為一些特定的場景建立BFF(如對第三方系統(tǒng)提供API),不可避免的,多個BFF之間會出現(xiàn)大量的重復(fù)代碼,比如可能會存在相同的數(shù)據(jù)轉(zhuǎn)換邏輯,相同的API數(shù)據(jù)聚合邏輯等等。

重復(fù)代碼通常被認(rèn)為是一種壞味道,但在BFF這個場景下,這些重復(fù)的代碼是為了某一個特定的前端服務(wù)的,因此處理這個重復(fù)要相對謹(jǐn)慎,如果一味粗暴地去掉這些重復(fù),很有可能引發(fā)某一個前端需求變化會影響到其他前端應(yīng)用的情況。

如果確實有些代碼重復(fù)且相對穩(wěn)定,可以嘗試采取下面的方法來消除重復(fù):

  • 共享庫,將重復(fù)的代碼抽取出來放到共享庫中,不同的BFF通過依賴共享庫來達(dá)到代碼復(fù)用,但也要考慮哪些代碼能夠抽取到共享庫中,可以參考我之前的文章 《消滅微服務(wù)的壞味道 之 共享庫 》
  • 將重復(fù)的代碼放到后端服務(wù)中,這種方法適用于重復(fù)的代碼實際承載了真實的業(yè)務(wù)邏輯,而不只是在做簡單的數(shù)據(jù)聚合和數(shù)據(jù)格式轉(zhuǎn)換,那么應(yīng)該把這些重復(fù)的代碼下沉到指定的后端服務(wù)中。

趨向于ESB

除了大量的重復(fù)代碼,在微服務(wù)架構(gòu)下,另外一個問題通常會出現(xiàn)在業(yè)務(wù)演進(jìn)過程中。當(dāng)新的業(yè)務(wù)需求產(chǎn)生時,具體要在哪個后端服務(wù)中實現(xiàn)有時候不是一個很容易回答的問題,特別是不同的服務(wù)有不同的團隊歸屬時,如果每個服務(wù)的歸屬團隊都認(rèn)為新的業(yè)務(wù)需求不是自己服務(wù)的業(yè)務(wù)范疇,最可能的結(jié)果就是讓BFF負(fù)責(zé)幫忙組合各個服務(wù)的功能,完成這個新的業(yè)務(wù)需求。漸漸地,BFF朝著ESB的方向發(fā)展,變成了集成各個微服務(wù),對外提供新能力的中間件。

這種趨勢某種程度上違反了BFF設(shè)計的初衷,BFF為了適配前端而生,而真實的業(yè)務(wù)能力應(yīng)該由后端服務(wù)來承接,而不是BFF。

要解決這個問題,首先要清晰的定義每個服務(wù)的業(yè)務(wù)職責(zé),為了避免服務(wù)過多很難劃分清晰邊界,最開始服務(wù)盡量不要拆的太??;另外要建立規(guī)則來處理新的需求,哪些需求屬于BFF的范疇,哪些屬于業(yè)務(wù)能力,業(yè)務(wù)能力應(yīng)該下沉到后端服務(wù)中,如果現(xiàn)有服務(wù)無法承載這種能力,可以考慮新增服務(wù),而不是寫在BFF中。

性能問題

還有一個比較明顯的問題就是性能問題,想象下面的場景(相信你一定遇到過),既然有了BFF,前端的設(shè)計真的可以放飛自我了,可以把想展示的信息一股腦都放在一起展示,極端情況下BFF可以獲取到任意服務(wù)的數(shù)據(jù)進(jìn)行組合,我曾見過在一個BFF接口中調(diào)用了后端服務(wù)幾十次來拼湊前端需要的數(shù)據(jù),可想而知這個接口的性能一定不會好。

為了解決這種情況帶來的性能問題,通常會采用并發(fā)獲取數(shù)據(jù)然后拼裝的方式,這明顯增加了代碼實現(xiàn)和維護(hù)的復(fù)雜度,往往會引發(fā)新的問題。

因此,在實際開發(fā)過程中要非常警惕這種問題的發(fā)生,如果一個BFF接口調(diào)用了3個以上接口,那就要分析下后端服務(wù)拆分的合不合理,前端UI展示的數(shù)據(jù)是否有必要放在一起,否則性能問題會逐漸成為一個不可避免的問題。

小結(jié)

架構(gòu)設(shè)計是通過合理的組件拆分以及定義組件之間的關(guān)系,將系統(tǒng)整體的復(fù)雜性分散到不同的組件中,在更低的維度上解決問題,分而治之。BFF在前后端分離的架構(gòu)模式下隔離了前端和后端的關(guān)注點,特別是在多個前端或第三方的情況下,BFF都是非常好的選擇。然而在實際實現(xiàn)過程中,仍然要時刻警惕,明確BFF設(shè)計的初衷,避免因引入BFF而帶來了更多的問題。

參考資料

[Pattern: Backends For Frontends] https://samnewman.io/patterns/architectural/bff/
[BFF @ SoundCloud] https://www.thoughtworks.com/insights/blog/bff-soundcloud
[Frontend Architectural Patterns: Backends-For-Frontends] https://medium.com/frontend-at-scale/frontend-architectural-patterns-backend-for-frontend-29679aba886c

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容