Airbnb:大規模代碼遷移至Apollo+GraphQL的實踐

Brie Bunge在2019年的GraphQL Summit上分享了Airbnb是如何實現大規模代碼遷移至Apollo+GraphQL。雖然GraphQL這個技術已經誕生好久,同時在接口靈活性、性能等方面都獲得驗證,可是如何在大規模代碼級別上進行遷移,始終是個很是困難的事情。前端

Aribnb採用了一種漸進式而且不會回退的方式進行大規模的GraphQL遷移,此次分享從三個方面介紹了Airbnb進行GraphQL遷移的實踐總結。web

1 遷移狀態

從去年開始,Airbnb開始進行GraphQL的遷移,而且愈來愈多的團隊開始採用。今年一個技術和產品的混合小組進行移動web應用的開發,採用了PWA的技術方案,這個技術方案給用戶帶來了巨大的體驗提高,咱們也經過這個項目推進了GraphQL的落地。npm

能夠看到從今年開始,來自GraphQL的流量正在穩步的提高。移動Web應用是主要的流量來源,固然咱們也看到了來自桌面PC的流量,iOS和Android的工程師也在不斷遷移系統至GraphQL。後端

5.8%的線上流量使用GraphQL技術,到年末這個數字會到10%左右。首先被遷移的功能是搜索、詳情頁和下單頁,後續完整的業務流程包括落地頁、支付頁、收藏頁、旅遊規劃頁、消息頁面都會採用GraphQL。緩存

2 遷移策略

咱們原有的技術棧主要是由React+Redux組成,服務端API採用Rest API,將來咱們指望採用React、Apollo和GraphQL技術棧。數據結構

在遷移策略上,咱們有幾個選項:架構

  • 重寫全部代碼,這個聽起來老是很誘人,可是每每須要時間,要契合一次功能從新設計等待
  • 暫停而且重構,這個每每可能在較小的團隊或者模塊中能夠實現,但每每也會帶來很是多的問題
  • 增量式採用,咱們發現這多是在大型項目中惟一可行的方式,讓咱們來說講是如何實現的

前提條件函數

咱們將整個遷移分紅5個步驟,每一個步驟都能產出一個功能完整、無須回滾、能夠發佈的版本。在咱們開始以前有一些前提條件:工具

  1. 在後端設立好GraphQL基礎設施,能夠經過如下連接瞭解更多的細節

  1. 在前端,咱們須要使用TypeScript,由於咱們能夠從schema定義直接生成TS的類型文件,這個會成爲先後端惟一的數據標準,TypeScript是一個必選項能夠保證端到端的類型正確性。開發會更加迅速,同時研發也會更加有信心。

下圖左邊是一個GraphQL查詢語句,右邊是使用Apollo工具自動生成的TypeScript類型文件,這樣咱們能夠保證類型正確,而且有Null錯誤檢查。TypeScript已是Airbnb的前端官方開發語言,已經有超過3百萬行代碼已經遷移至TypeScript,若是你對如何遷移至TypeScript感興趣,你能夠看看上半年的JSConf的分享。在咱們遷移至GraphQL+Apollo以前,咱們經過內部工具將大量JS代碼轉換成TypeScript。組件化

第一步:REST到GraphQL

第一步是將REST接口遷移至GraphQL,從而驗證端到端的整合,驗證TypeScript類型文件的生成。在這個階段,咱們不會改變任何React組件和API返回數據結構。

讓咱們以預約房間接口爲例,咱們使用Apollo client來發起GraphQL請求,首先咱們要保證GraphQL請求的返回數據格式和原有的REST接口保持一致。若是手動實現GraphQL查詢語句,這個每每很是繁瑣而且容易出錯。

咱們利用了GraphQL的Playground,裏面提供了字段自動補全的能力,同時又能實時驗證結果。

咱們也使用GraphQL中的字段別名的能力,這個對咱們很是有用,由於原有的REST接口採用蛇形命名,而GraphQL中採用了駝峯命名。

咱們經過Schema自動生成了數千行的TypeScript類型聲明代碼,這個簡直太棒了!這個在之前會很是繁瑣,須要根據服務端的請求結果手動編寫,並且接口發生變化也難以同步。

其次,咱們還須要關注轉換代碼(adapt),在咱們的後端的request和response數據結構有少許的變化,因此咱們建立了adapter工具方法,能夠把一個對象轉換成另外一個對象。經過adapter的轉換,咱們保證了GraphQL的request和response同原有的REST接口徹底保持一致。

每一步遷移咱們都保證能夠有上線的版本,因此這一步完成後咱們實現了GraphQL的上線。

第二步:TypeScript類型

這一步的目標是開始使用自動生成的TypeScript類型定義文件,這樣能夠有效的提高咱們的遷移信心,若是出現類型問題會在編譯階段第一時間獲得錯誤提高,但咱們並不會影響運行時的行爲。

使用TS Type文件,一個問題就是Null的檢查,如上圖部分所示,每每須要一層層對對象裏面的內容進行判空處理,咱們經過採用一個IDX的npm庫來解決這個問題。固然optional channing已是JavaScript TC39的提案,而且已經在TypeScript 3.7版本中獲得支持。

第三步:使用Apollo Hooks

在Airbnb咱們很是喜歡使用React Hooks,減小了許多模板式代碼,同時很好的結合TypeScript共同使用。Apollo Hooks提供了一系列函數,能夠用於替代原有的HOC的實現方式。

當前階段咱們使用Apollo Client,同時咱們仍是使用Redux Actions去觸發事件,而且組件也使用Redux Store。

咱們對系統進行了重構,採用Apollo HOC或者Hooks,而且更新了組件數據採用Apollo cache數據源替換掉Redux Store。咱們依舊保留了Redux Store,由於有部分數據還未遷移,但它的做用已經基本宣了結結。

第四步:自下而上的組件化查詢

在第一步遷移至GraphQL的時候,咱們採用保留現有REST的request和response的方式,可是這樣會有很是多的冗餘字段。所以這個階段,咱們將會對查詢語句的字段進行裁剪。

咱們從組件的葉子節點開始,尋找當前節點所須要的字段,而且定義相應的查詢條件。同時咱們也會自動生成對應的TypeScript類型文件,而且經過這個文件來幫助檢查是否有字段的缺失。

而後咱們會將子節點的查詢條件上升整合至父節點,直至App節點,這個過程能夠一直重複循環直至整個樹都轉換完成。這時候App節點就有一份完整的整合好的查詢條件,因爲每一個節點都只獲取它所須要的數據,咱們幾乎能夠認爲App節點的查詢條件也是近似於最簡潔的數據格式。

第五步:狀態管理

當咱們進行GraphQL遷移的時候,咱們總會關心當前Redux Store如何處理。咱們發現Redux Store的能力,一般均可以被React本地state或者context,以及Apollo數據API進行替代。這樣會帶來幾個好處:

  1. 更加一致的心智模型
  2. 減小模板式代碼
  3. 更好的緩存能力

經過這五個步驟,咱們逐步的遷移完成了GraphQL,而且每一步都保證可以正常發佈上線,無需回滾。

3 下一步計劃

Service Worker接口預加載

目標是觸發GraphQL查詢越早越好,這樣可讓用戶體驗更好。咱們採用Service Worker的實現方式來作到這點。

這張圖對比了採用服務端渲染(SSR)和Service Worker的兩種方式的體驗狀況。在圖的上半部分是採用SSR,能夠看到因爲須要等待服務端渲染,因此存在大量的白屏時間,而後直接加載整個內容。而採用Service Worker,用戶能夠一開始就看到應用的骨架佈局,並且因爲大量靜態資源已是本地緩存,所以頁面渲染也很是迅速。

這是一個採用SSR方式頁面的調試結果,首先咱們獲取服務端請求,這個請求同時也包含了GraphQL的查詢,而後解析HTML而且下載JS,而後頁面逐步渲染出來,當React完成了頁面渲染,用戶能夠進行頁面操做。

當採用Service Worker方式,因爲大量資源都是從本地緩存讀取,因此第一時間就會進行HTML解析和頁面渲染,而後會開始GraphQL查詢,數據返回,而後頁面能夠交互。

能夠看到在頁面開始加載到GraphQL查詢發起之間存在一個很大的間隙,所以這是一個很是大的優化空間。

咱們能夠在路由上註冊GraphQL請求,而不是在頁面級別。這樣GraphQL請求能夠在頁面最開始的時候就發起,這樣它把GraphQL請求和React頁面渲染解耦。在這個場景下,咱們將節省400ms,提高了23%性能,這個優化在低配設備上尤爲明顯,咱們模擬了6倍慢速的CPU設備,咱們獲得50%的性能提高。

統一的Schema

另外一個改進是採用統一的Schema,咱們首先來看看Aribnb的SOA服務,SOA服務主要分爲三層:數據層,聚合數據層,展現服務層。

咱們使用GraphQL做爲統一的先後端通訊接入層,而且在這層統一作數據的整合能力。同時咱們也能更好的利用緩存能力。

咱們利用批量請求和緩存能力,這樣能夠減小相同數據的屢次請求。

寫在最後

最後分享一下一些收穫:

  1. 採用Apollo和TypeScript,能夠給遷移工做帶來大量的信心
  2. 採用增量式的架構演進,對於一個大型現存項目,經過增量式的遷移策略,逐步推出可運行、可發佈的系統,這應該是最好的方式
  3. Apollo+GraphQL的組合能夠做爲很是好的前端數據基礎能力

『奶爸碼農』從事互聯網研發工做10+年,經歷IBM、SAP、陸金所、攜程等國內外IT公司,目前在美團負責餐飲相關大前端技術團隊,按期分享關於大前端技術、投資理財、我的成長的思考與總結。

相關文章
相關標籤/搜索