React Native: 回顧 Udacity 移動工程團隊的使用歷程

React Native: 回顧 Udacity 移動工程團隊的使用歷程

Udacity 的移動團隊最近把咱們的應用程序中用 React Native 編寫的最後一個功能移除了。css

咱們收到了不少關於 React Native 及其使用的一些問題,還有人問咱們爲何中止使用 React Native。html

在本文中,我但願可以回答這些問題中的大部分,而且重點介紹:前端

  • 咱們的相關團隊的規模及人員組成?
  • 咱們爲何一開始會嘗試 React Native?
  • 移除 React Native 的緣由?
  • 哪些方面可行?哪些方面不可行?
  • ...以及其它 🙂

我必然不能自稱是 React Native 專家。咱們團隊中有的人比我更有經驗,不過他們也未必可以稱爲專家。java

我只是想談一談咱們本身的經驗,介紹一下在咱們這個特定的使用狀況下哪些可行哪些不可行。React Native 是否適合於你的團隊/項目,這徹底取決於你。而本文的做用是爲你決策時提供一些額外的有用參考。node

「是否在你的團隊/項目中使用 React Native 徹底取決於你」react

還須要指出的是,這裏的經驗和觀點來自於 Udacity 的移動工程團隊,並不涉及到公司其餘團隊。咱們的想法不表明其它使用 React/React Native,或爲之構建內容的團隊的觀點。android


團隊

第一件事,咱們的團隊是什麼樣的?你的團隊的規模,經驗和組織都會對 React Native 在你的工程中的可行性產生重大影響。ios

咱們的移動工程團隊覆蓋了 iOS 和 Android 兩個平臺。git

團隊規模github

引入 React Native 時

  • 1 個 iOS 開發人員
  • 2 個 Android 開發人員
  • 1 個 PM
  • 1 個 設計師

現在

  • 4 個 iOS 開發人員
  • 3 個 Android 開發人員
  • 1 個 PM
  • 1 個 設計師

在咱們使用 React Native 的約 18 個月的時間裏,咱們 iOS 和 Android 兩個團隊都擴容了。整個團隊還迎來了新的 PM。咱們還經歷了多種設計和多種範式。

開發者背景

當引入 React Native 時,每一個團隊對 JavaScript 和 React 編程範式的溫馨度如何?

iOS

iOS 團隊最初惟一的那個開發者對跳進 React Native 陣營至關認同,由於他之間已經有了大量的 JavaScript 和 web 開發經驗。

如今,4 個 iOS 開發者中有 3 人在 JavaScript 和 React Native 開發中比較駕輕就熟。

Android

引入 React Native 之初,兩個 Android 開發者之一對 JavaScript 比較適應。另外一個(我本身)基本沒有什麼 JavaScript,React 或 web 開發背景。

後來加入的另外一個 Android 開發者也沒什麼 JavaScript 或 web 開發經驗。


應用程序

咱們的應用程序是幹什麼用的?

咱們的移動應用程序的目標是將 Udacity 的學習體驗帶到移動設備上。它們須要支持認證、內容發現、項目註冊(某些狀況下還會有支付)、最後還要支持對不一樣的項目和內容類型的學習材料的使用。

這些應用程序仍是新的實驗性功能的測試溫牀,皆在改進用戶的總體學習進展。

代碼庫的規模

  • iOS: 97400 行代碼(.swift,.h,.m)
  • Android:93000 行代碼(xml, java, kotlin, gradle)

功能的一致性

當引入 React Native 時,這些應用程序的功能基本上是一致的。

隨着項目推動,核心體驗基本上保持一致,但每一個團隊都有一些在特定平臺上獨有的「實驗性」功能。

此外,因爲更大的國際化需求,諸如本地化和更小的 apk 軟件包大小之類的需求日益成爲 Android 團隊的優先事項。Android 團隊還和其它地區的團隊密切合做,爲特定市場開發一些功能,這是 iOS 團隊不須要重點考慮的。


爲何/如何採用 React Native?

咱們爲何要引入 React Native?

當時,咱們想要開發一個全新的只在移動設備上運行的功能。咱們但願在兩個平臺上實驗和快速地驗證,因此跨平臺是很是吸引人的。

由於這是一個新的封閉性的功能,咱們將其視爲一個嘗試跨平臺方法的有意思的嘗試。

咱們選擇 React Native 的緣由以下:

  • 愈來愈可行的跨平臺方案
  • 團隊大部分人(2/3開發者)適應 JavaScript 和 web 開發
  • 更快的開發速度
  • 公司外其它團隊的成功故事

咱們是如何引入的?

咱們最初的 React Native 功能基於一個獨立的 GitHub 倉庫,而後將其做爲 git 子樹,同時合併回 iOS 和 Android 倉庫中。

這種方式支持很是快速的原型開發,若是有必要,也可讓這個功能以獨立產品的形式發佈。

隨着積累了更多的原型開發經驗,咱們逐漸在 React Native 代碼倉庫中加入更大的第二個功能。

時間線

  • Aug 2016: 建立功能 1 的 React Native 倉庫
  • Nov 2016: 功能 1 在 Android 上發佈
  • Nov 2016: 功能 2 開始開發
  • Dec 2016: 功能 3 原型開發開始
  • Jan 2017: 功能 1 開發結束
  • Feb 2017: 功能 2 發佈
  • Mar 2017: 功能 3 原型開發結束
  • Nov 2017: 功能 2 在 Android 上的最後一次更新
  • Dec 2017: 功能 4 做爲獨立應用進行原型開發。最後因爲性能緣由從新用本地代碼實現。
  • Feb 2018: 功能 2 在 iOS 上的最後一次更新
  • Apr 2018: 功能 1 從 Android 上移除
  • Jun 2018: 功能 2 同時從兩個應用中移除

移除 React Native 的動機?

答案至關直接。

咱們移除應用程序中與 React Native 相關的最後一點代碼,緣由在於剩下的惟一一個 React Native 功能已經快要下線,咱們不打算對它繼續支持了。

「爲何中止用 React Native 開發新功能呢」

更有意思的問題多是:爲何中止用 React Native 開發新功能呢?

緣由大概有如下幾條:

  1. 須要同時在兩個平臺上開發的功能數目降低
  2. Android 平臺獨有的產品請求量增長
  3. 長期維護成本的噩夢
  4. Android 團隊不肯繼續用 React Native

那麼用什麼來替代呢?

用 React Native 開發的功能被移除且再也不支持,咱們也沒有替代這些功能的需求。


React Native 哪些方面用得不錯?

咱們在使用 React Native 時,有哪些方面用得不錯呢?

  • React Native 的入門、運行、及在兩個平臺上的構建都至關容易
  • 能夠從 React 和 JavaScript 更大的生態系統中獲取代碼庫和工具
  • 咱們能夠在兩個平臺上同時原型開發功能 1
  • 在一個跨功能團隊中,同一個開發者能夠同時爲兩個平臺構建功能 2 的大部分代碼
  • 團隊對 React Native 的共同理解更深刻了

遇到過哪些問題?

在咱們使用 React Native 的過程當中,咱們遇到了一系列的問題。其中一些來源於咱們的使用過程,一些來源於咱們的使用案例,還有一些則來自於 React Native 自己。

設計和用戶體驗方面的挑戰

平臺一致的 UI/UX

由於咱們要將幾個新的屏幕集成到現有的更大的用戶體驗區中,咱們但願新的 React Native 代碼可以遵照本地平臺的開發模式和風格。這意味着咱們在兩個平臺上用的不必定是同一個 UI 設計。

讓 React Native 的風格和本地平臺一致並非什麼難事,可是你須要瞭解每一個代碼庫中的設計範式。至少,你要覈對每一個平臺,甚至要爲每一個操做系統開發新的定製控件。

對咱們而言,常常須要接觸每一個平臺的開發者和設計者,以理解須要作什麼,不然在兩邊同時使用一個風格會致使 Android 這邊的用戶體驗與其他應用徹底不一樣。

在更復雜的狀況下,咱們須要編寫額外的平臺獨有的代碼,來定製每一個應用程序的用戶體驗。

其中一個例子是,確保一個 back/up 圖標的正確行爲。由於要考慮到新的 React Native 功能代碼集成到已有的應用中(集成到哪裏/如何集成),確保 back/up 圖標和 back 按鈕點擊時的正確行爲須要 Android 平臺的本地代碼,並且要在 React Native 代碼庫中進行 Android 特有的代碼改動。

在本地設計中的改動會致使集成功能時 React Native 代碼的變更

至少在一個場合中,Android 應用的導航結構變更時,咱們須要相應地更新 React Native 代碼,不爲別的,只是爲了處理二者的集成問題。

咱們沒能作到讓它們獨立存在,React Native 實現的功能實際上在一個 fragment 中,它先是被放在一個 BottomNavigationView 的屏幕中,而後又被移到它本身與本地其它 fragment 之間的座標狀態中。

這種平臺修改須要回到獨立的代碼庫,進行修改並更新集成,確保新的改動不會對 iOS 應用程序產生負面影響。

設備相關的問題

無論你叫它「碎片化」仍是「分散化」,咱們面臨的現實是,Android 設備上有更多獨特的配置須要考慮。

在不少狀況下,咱們發現佈局不能很好地適配到不一樣尺寸的 Android 手機。咱們發現最新的 iPhone 和 Pixel 設備上能夠很流暢地運行動畫,可是在國際市場上更普遍使用的低端設備上是作不到的。

這固然不是 React Native 獨有的問題,只不過是 Android 應用開發中共有的問題。可是,這確實是咱們須要考慮的平臺相關的問題,當這類問題多起來以後,咱們不得不反思:React Native 的跨平臺到底爲咱們省了多少時間?

全球化增加

在咱們使用 React Native 的時間裏,Android 團隊對國際化愈來愈關注。咱們有數個國際化辦公室,它們要求本地化和輕量化的 apk 包。

React Native 是能夠作字符串的本地化的,但須要額外的設置。在咱們的案例中,它須要對不一樣的倉庫的代碼進行改動。這增長了本地化任務的複雜度,特別是你須要其它團隊輔助完成本地化時,就不是很美妙了。這使得 React Native 實現的功能的本地化頻率變得更低。

咱們可以按要求減少 apk 文件大小,可是難以處理 React Native 佔用的至關可觀的那部分。當咱們移除了最後一個用 React Native 實現的功能以後,咱們的 apk 減小了約 10MB,這包括了命令資源(command resource)和 React Native 自己。

集成的挑戰

與本地組件和導航結構的集成

根據咱們的經驗,將 React Native 集成到已有的應用中時,若是是一個獨立的功能,則集成是至關直接的;不過如何須要與已有組件緊密集成並通訊,則你會遇到麻煩。

咱們發現,經常須要大量的橋接代碼,來實現本地組件和 React Native 組件的通訊。當咱們須要修改 React Native 組件以適應導航結構時,這部分代碼也是須要更新的。

工具鏈/構建問題

集成 React Native 須要更新每一個應用程序的構建過程。咱們使用 CircleCI 來構建咱們的工程,它須要從新配置以支持額外的 React Native 構建步驟。

在咱們以前的一篇文章中介紹過,在 Android 這邊並非那麼直觀。

在 Android 上發佈版本時的 React Native 打包: 在 Android 發佈build_engineering.udacity.com 時如何運行 React Native 打包命令行

一旦咱們的構建過程包含了所需的 React Native 任務,它讓 CircleCI 的發行版構建時間增長了約 20%。

在咱們的代碼庫中移除最後一個 React Native 功能以後,咱們有了以下的改進:

  • CircleCI 構建時間由約 15 分鐘變成了 約 12 分鐘
  • apk 發佈文件大小由 28.4MB 變成了 18.1MB

Android 團隊還經歷了 Android/Gradle 構建工具與 React Native 衝突的一些問題。最近,咱們一直在解決的一個問題是:issues with Gradle 4

iOS 團隊一樣存在很多問題。

配置構建工具比較痛苦,由於咱們使用 React Native 時採用的是非標準文件結構。由於咱們有多個項目倉庫,咱們將 React Native 倉庫置於 srcroot/ReactNative 目錄下,而不少已有的構建工具卻假設默認的應用文件結構爲 /ReactNative/ios/ios。

此外,咱們使用過 cocoapods 來管理依賴關係,它原來是包含 React Native 的推薦方式,可是後來卻再也不被推薦了。這個問題由於咱們的非標準文件結構而變得更爲嚴重,因而咱們須要在 Podfile 中用一些很惱人的小技巧來從正確的位置讀取文件。

因爲 cocoapods 再也不是包含 React Native 的標準方式,因而 Podfile 的更新會依賴於社區的更新,二者不老是同步的。咱們數個版本的 css/Yoga 依賴已經更新,其 Podfile 卻仍然在引用錯誤的版本。直到最後,咱們仍然在使用一些噁心的安裝後小技巧,實際上只不過是用 sed/regex 來定位那些包含的調用代碼。

最後,iOS 項目的 CI 一樣是一個痛點。如今,咱們不得不添加一個 npm 依賴層,並確保在繼續安裝前正確地更新。這爲咱們的構建時間增長了很多時間。

咱們還遇到過一個崩潰問題,由於一個版本的 npm 有 package.lock,而另外一個沒有,這致使咱們在一次 React Native 升級時安裝了錯誤的依賴版本。


React Native 自身的挑戰

文檔

React Native 做爲一個總體發展是很是快的,然而咱們也發現它的文檔有時倒是缺少的。特別是當咱們第一次採用時,咱們發現某些特定版本的文檔/回答也許僅僅是相關的,也許不相關。

當前,將 React Native 集成到一個已有的工程中的文檔是比較少的。這也是咱們更新 CI 構建時頭痛的一個問題。

當 React Native 持續進化時,文檔和社區支持已經有所改善。若是咱們是從今天開始使用,也許咱們曾經的一些問題更容易找到答案。

導航

咱們最初是從 NavigationExperimental 開始的,它不是並容易使用的導航代碼庫。當 React Navigation 出現以後,它迅速成爲社區接受的導航,因而 NavigationExperimental 在 ReactNavigation 徹底採納以前逐步再也不推薦使用。

儘管如此,若是不將一些東西強行組合起來,咱們是沒法用 ReactNavigation 來實現一些功能的(好比:在一個當前 modal 流中推送 flow)。

性能

前面已經提過,咱們有幾回都注意到了性能的問題。

咱們能夠在空間足夠的 iOS 和 Android 設備上實現很是漂亮的動畫,可是這些動畫在國際市場上更普遍使用的低端 Android 設備上卻難以良好運行。

在進入到應用的 React Native 部分時的加載時間比咱們預期要長。這使得它不像是一種無縫過渡。

當原型開發獨立的功能 4 時,圖形渲染性能成爲咱們關心的主要問題,由於 React Native 徹底比不了本地程序的性能。

滯後於本地平臺

由於和 iOS 或 Android 本地應用並非同步構建,React Native 經常滯後於本地平臺。它經常依賴於社區所支持的新的本地功能。

一個例子是咱們急需的對 iPhone X 的 safe area 支持。咱們最終不得不暫時不支持 SafeArea,由於這個功能很快就會出來。SafeAreaView 是一種平臺相關的功能,跨平臺開發者在開發相關的功能時須要考慮到。

在其它時候,React Native 在採納新平臺要求方面也是滯後的,好比在 2018 年 8 月 Android 應用 要求採用 API 26。要實現這個要求,仍然有一些未解決的問題。

不持續的更新

React Native 升級時不支持後向兼容,這點讓人很是崩潰。一個例子是 React Native 在升級它的 React 庫時的 PropType deprecation

除非維護本身定製的複製倉庫,許多第三方庫若是沒有繼續維護則將沒法使用。


維護的挑戰

代碼庫中 React Native 部分的維護是咱們常常要頭痛的問題。如前所述,Android 常常須要額外的工做來與已有代碼集成或修正 UI 問題。這使得 iOS 和 Android 在不一樣的 React Native 代碼庫分支上再也不同步,只有這樣纔不會讓不一樣平臺的開發互相拖累。

由於這種分支問題,代碼開始慢慢變得發散,將它們從新一致起來所需的精力愈來愈多。因而,一個平臺上的更新不會馬上反映到另外一個平臺上。

React Native 的改動的速度也構成挑戰。由於存在不持續的改動的可能性,咱們每每不能很快地更新一個依賴關係,來增長一個新功能或修復一個 BUG。

一樣,一些時候這會產生更多摩擦,從而拖慢代碼維護的頻率。對於一個小團隊,在有限的帶寬下,若是沒法對 React Native 代碼進行容易/快速的修復,那麼代碼中的問題獲得修復的可能性只會愈來愈低,由於它可能牽扯額外的開發精力。

增長了 React Native 以後,咱們每每不是很清楚一個 BUG 存在於哪一個層次。究竟是兩個平臺都有?仍是一個平臺獨有?若是隻存在於一個平臺,那這個 BUG 來自於本地代碼仍是 React Native 代碼?這些問題增長了複雜性,從而拖慢了 QA 進程。

當須要在代碼庫的 React Native 部分中修復一個問題時,目前咱們不得不一樣時考慮 iOS 和 Android,因而有可能須要同時考慮 3 個技術棧,而不是理想中的 1 個。

另外,由於團隊中不是全部人都對 React Native 感到適應,可以在技術棧之間快速跳轉並修復問題的人天然就更少了。


咱們是否能夠作得更好?

我相信咱們面臨的其中一些問題來源於咱們的特定使用案例,不過,有些問題確實是能夠緩解的。

更少的代碼分支

讓應用程序與 React Native 倉庫中的改動保持一致,咱們就能夠作得更好。我相信讓這些更新同步會讓咱們在實現這些功能時有更強烈的跨平臺開發的感受。

增長設備上的測試,特別是 Android,可有助於咱們在早期發現更多 UI/性能問題,而且在發佈以前修復。在新代碼編寫以前修復問題,又能夠進一步減小代碼分支的數目。

更一致的設計

從開始就採用更具體的設計計劃,有可能能夠改善這些功能的本地外觀。一個具體的例子是,採用與本地應用程序其他部分一致的 text/margin 值,而非在新用戶體驗區中使用新值,並同時應用到兩個平臺上。

更好地理解你的團隊

團隊中對 React Native 更不適應的那些成員應該更努力地適應其它技術棧。這會增長可以快速修復問題的人員的數目。


有沒有使用案例更適合使用 React Native?

我不認爲咱們團隊有人認爲 React Native 一無可取。顯然,我相信有些使用案例中 React Native 會更適用。

你是否須要快速地、雙平臺、從頭原型開發/構建一個新應用?

你是否須要實現一個外觀/行爲與平臺無關的應用/功能?

你是否有空閒的 JavaScript 開發者用於移動設備應用開發?

若是上述這些問題的答案都是確定的,那麼對你來講 React Native 多是一個可行選項。

特別是,若是你有 JavaScript/React 背景,而且不須要太多本地代碼,那麼 React Native 將很是具備吸引力。它能讓你無需學習兩個技術棧的狀況下開始構建一個移動應用。

對於一個徹底跨平臺應用的重頭開發,React Native 也將是一個不錯的選擇。


咱們還會不會用 React Native?

iOS 團隊和 Android 團隊有不一樣的說法。

iOS

有可能。iOS 團隊大致上對 React Native 開發至關開心,而且已經考慮用它來構建新功能。此外,在產品發佈方面,相對於 Android 平臺,咱們的 PM 對 iOS 設備上的 React Native 方案更有信心。

Android

不會。理想狀況下,Android 團隊將不會投入到 React Native 中去。咱們發現 React Native 組件的集成過程至關煩瑣,而且其用戶體驗並不能在全部 Android 設備上都一樣運行良好。

此外,咱們傾向於堅持使用一種技術棧,而不肯意在 Android 框架上再增長一層抽象,由於這也意味着增長潛在的 BUG。

咱們的印象是,用 React Native 爲 Android 建立新功能的過程是比較快的,可是這個功能從早期階段過渡到最終發佈版本,以及長期的維護過程,每每會花費更多時間。


咱們是否會再次使用其它跨平臺的方案?

做爲一個團隊,咱們極可能不會在短時間內投入到跨平臺的開發中。iOS 團隊有可能會用 React Native 來構建一些新東西,而且這隻限於 iOS 設備,由於他們大致上會更享受這種開發體驗。

個體而言,團隊成員會繼續關注 React Native,以及 Flutter。由於諸如 React Native 和 Flutter 這樣的解決方案也在一直進化,咱們會持續爲咱們的團隊評估這些技術。

那麼,這就是咱們今天所處的狀態。

咱們對 React Native 如何能更好地適應咱們的團隊以及路線圖方面有了更好的理解。咱們能夠基於這種判斷來指導咱們下一步的決策,從而爲團隊作出正確的技術選擇。

「咱們可不能夠肯定地判斷 React Native 是否適合於你?不能。」

咱們知道 React Native 的優勢以及不足,那麼咱們可不能夠肯定地判斷 React Native 是否適合你?

不能。

可是,咱們的經驗徹底可以能夠做爲你的參考依據,幫助你評估 React Native 在你的項目中的可行性。


想要學習更多移動開發?

關注咱們

想了解更多構建 Udacity 的工程師和科學家,請在 Medium 上關注咱們。

想加入咱們?請 @udacity,機會多多。

移動設備上的 Udacity

[移動設備上的 Udacity | iPad, iPhone 和 Android:咱們已經將 Udacity 的課程體驗帶到了 iPad 和 iPhone 和 Android 上。開始學習你所需的技能吧)(https://www.udacity.com/mobile)

感謝 Aashish BansalJustin Li

若是發現譯文存在錯誤或其餘須要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可得到相應獎勵積分。文章開頭的 本文永久連接 即爲本文在 GitHub 上的 MarkDown 連接。


掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章
相關標籤/搜索