跨端方案的三大困境

寫在前面

2018 年,Airbnb 放棄了繼續使用 React Native,箇中原因主要有兩方面:

  • 技術:成熟度、配套設施/類庫建設成本、首屏性能硬傷等沒能很好地解決

  • 團隊組織:工程師要求高、跨技術棧/跨團隊調試/測試等也產生了新的問題

實際上,跨端方案遭遇的問題遠不止這些,一些時候 Write Once, Run Everywhere 只是美好願景

 

一.技術困境

一言以蔽之,觸碰到能力邊界之前,跨端方案里的一切都是美好的

以 React Native 為例:

 

 

Bridge 層通過消息通訊將 JavaScript 世界與 Native 世界聯繫起來

Shadow Tree 用來定義 UI 效果及交互功能,Native Modules 提供 Native 功能(比如藍牙),二者之間通過 JSON 消息相互通訊

P.S.圖有些舊,但不影響理解原理,更新的 React Native 架構圖見[(React Native 架構演進]//www.ayqy.net/blog/react-native-new-architecture/)

在這樣的技術架構中,寫的和實際執行的都是 JavaScript,調用由 Native 提供的視圖渲染能力及平台特定能力,Facebook 稱之為Scripting native 方案,姑且叫做容器化 Native 跨端方案

將 Native App 改造成標準化的容器,進而允許一套程式碼跨多端標準容器運行,如 React Native/Weex、Flutter

(摘自移動端跨平台技術之下的變與不變

容器能力在很大程度上決定著開發效率,在容器提供了一致的標準支援範圍內,能夠愉快地一人搞定多端。然而,一旦觸及能力邊界,就會面臨高成本的多層聯合開發(Native 層、JavaScript 引擎層、特定業務領域層、業務層……),人效上並沒有優勢。另一方面,如何保持多端一致性,也是個極其複雜並且充滿技術挑戰的問題

此外,相關的配套能力也直接關係到開發效率:

  • 調試:跨技術棧調試一直是難題,問題排查成本越來越高

  • 性能:跨執行緒、跨頁面耗時分析困難、性能工具鏈缺失

  • 工程鏈路:由於技術方案的特殊性,需要量身訂製許多配套設施(包括但不限於 IDE、調試、性能、CI/CD、監控),才能將各個環節的成本降下來

總的來說,技術上最大的困境在於:

  • 抹不平的多端差異

  • 掀不開的 JavaScript 引擎蓋

  • 跟不上的配套能力

多端一致性在技術投入上幾乎是無底洞,底層的平台架構差異(UI 渲染方式、事件機制、系統 API)根深蒂固,以各類跨端方案目前的成熟度僅能覆蓋極其有限的一部分,留有非常大的空白需要通過擴展容器能力來填補,包括通用的基礎能力(如 UI、交互),以及面向業務領域的特定能力(如多媒體、定位)

引入 JavaScript 引擎雖然獲得了動態執行程式碼的能力,但也帶來了技術上的不確定性,幾乎無法跟蹤解決 JavaScript 引擎內部的崩潰或異常行為

通用的基礎設施大多無法直接用於跨端場景,邊邊角角的配套能力都需要花力氣建設,而為了滿足業務快速生長,總是優先建設核心關鍵能力,配套支援通常是滯後的,同樣影響著效率

 

Flutter 能帶來一些不同嗎?

事實上,Flutter(目前看起來)同樣面臨這些技術困境,技術實現的變化並未徹底改變局面

據 2020 Q1 調查結果,Flutter 開發者認為最重要的 6 個問題是:

  • 調試錯誤和崩潰

  • 測試確保 App 能夠跨多平台運行

  • 選用狀態管理方案

  • 理解和處理布局問題(如文本溢出)

  • 根據設計稿創建 UI

  • 排查特定平台問題

同時,認為最困難的 6 個問題是:

  • 排查特定平台問題

  • 記憶體問題的診斷和修復

  • CPU 使用率問題的診斷和修復

  • 接入現有的 Native API

  • UI 卡頓問題的診斷和修復

  • 開發特定平台的 Flutter 插件

因此,跨端方案的調試、性能之痛仍在 Flutter 延續,多端差異以及配套能力的困境並沒有改變

 

二.團隊組織困境

與單端開發模式相比,跨端方案的協作成本更高,體現在:

  • 跨團隊

  • 鏈路長

  • 容器團隊壓力大

  • 職責邊界不清晰

跨端方案下,跨團隊協作成為了最主要的協作方式,需求串講、開發、聯調、問題排查等多個環節都需要跨團隊溝通/協作,溝通成本不容忽視

長鏈路意味著技術細節散落在多層,各自只擁有一小部分知識

表層業務邏輯
-----------------------------
特定業務領域框架
-----------------------------
通用前端框架/類庫
-----------------------------
JavaScript引擎(擴展)
-----------------------------
Native Module | 特定業務領域能力
-----------------------------
Native通用框架
-----------------------------
Native View
-----------------------------
平台作業系統

由於每個團隊都看不到全景,每一個原因不那麼顯而易見的問題就都要一層層向下排查,甚至涉及特定業務領域能力的部分又分為許多層……

另一方面,如此繁多的層次也造成了複雜度堆積,越往下層複雜度越高,因為不確定的可變輸入越多,越難弄明白來龍去脈,排查問題的成本也越高

理想情況下,按漏斗模型逐層過濾,每一層只需要檢查自己的輸入輸出,但滯後的配套能力讓表層業務難以識別出問題所在的範圍,於是容器團隊成為了問題流轉的過濾閥,上接紛繁的 JavaScript 業務,下連複雜的特定領域能力,大量的時間耗費在了弄清楚來龍去脈上,容器能力擴展被迫降速,反覆排查已知問題……

業務視角下,對業務之下的層次職責劃分並不十分清楚,因此很容易找錯層/人,產生無效的「重定向」。而容器層同樣也不具備全景視圖,問題流轉軌跡變得相當曲折,溝通成本充斥在各個環節中,制約著開發效率

 

三.個體困境

對個體而言,面臨的最大困難是跨端方案與 Web 標準存在些許差異,並且這些許差異不像 W3C 標準一樣能寫得清清楚楚:

Weex enables developers to use modern web development skills to build Android, iOS, and Web apps with a single codebase.

也就是說,通用的 Web 經驗不完全適用,學習曲線並不十分友好,例如:

  • rem、媒體查詢、scale/zoom等適配經驗都不一定適用

  • 減少 DOM 操作、合併 JavaScript 文件、開啟硬體加速等常規優化措施也不一定能產生明顯的性能優化效果

  • (像學習 Web 一樣)只了解瀏覽器之上的標準能力是不夠的,想要真正高效地完成業務開發工作,容器原理甚至部分實現細節都要理解

就像有 Native 背景的開發者學習TypeScript一樣,初接觸無師自通,熟悉的ClassInterface靜態類型用起來遊刃有餘……然而,熟知 TypeScript 的開發者一定知道個中細節存在著多少奇怪的地方

 

四.跨端的真正意義是什麼?

React Native 最初的出發點是:

希望 Native 開發也能像 Web 一樣 Move fast

  • 快速迭代(Rapid iteration cycle):Web 一天兩版,產品迭代周期更短
  • 快速回饋(Immediate testing feedback):Web 發布立即觸達用戶,A/B test 等實驗結果立等可取,產品演進更快
  • 快速開發(Rapid development velocity):刷新瀏覽器即可生效,不必等待重新編譯 App

(摘自React Native 簡史

因此,從需求角度來看,開發效率是次要的,動態化的靈活性、快速迭代助業務先贏才是其跨端的主要意義,或者說追求的是生產效率,而不僅是開發效率,更短的迭代周期,更快速的觸達用戶都是直接的生產效率進步

然而,在三大困境之下,開發效率實際上也嚴重影響著生產效率,但還不足以抵消快速迭代、動態發布的重大進步,此消彼長也算是一種平衡,一種可接受的妥協

 

五.在困境中尋找生門

理想情況下,容器應該是趨於標準化的,提供多端一致、豐富穩定的能力支援,之上的業務棧極少觸及容器能力邊界,從而使得容器層能夠不斷優化探索,更好地滿足業務發展的需要

另一方面,跨端方案只是將多端不一致性帶來的複雜度下沉到了容器層,獨立於平台的語言環境(JavaScript 引擎、Dart 虛擬機等)能夠保證上層業務邏輯的一致性,但容器層仍然需要在多端各自實現一套,如何保證容器能力的多端一致性,仍然是個大問題,也並不比非跨端方案下容易多少

因此,首先要解決容器能力豐富度的問題,將邊界拓寬,從根源上減少問題。轉而集中火力到真正的難題上,攻下最有價值的難點部分。同時通過虛擬架構等方式建立全職能的業務支撐團隊,降低溝通成本

  • 業務要有自研能力:化解下層資源瓶頸,共同豐富容器能力

  • 專註必須花大力氣投入的點:調試能力、標準化、性能分析以及持續跟蹤、工程配套設施

  • 要有全職能的業務支撐團隊:有能力兜住所有問題,真正提供一攬子解決方案,消除無意義的溝通重定向

其中,業務自研能力先要有標準的擴展方式,要求容器實現上易擴展,業務開發者不需要了解過多細節也能快速進入開發。調試能力在長鏈路的技術棧下至關重要,問題識別成本越低、準確率越高,效率越高,所能釋放出來的資源就越多

從業務開發角度來看,更需要的可能是一層網關,請求過去響應回來,而不是一系列路由表,需要一跳一跳地跟蹤。全職能的業務支撐團隊組成區域網,讓網關之後的流量得以快速流轉,高效協作的同時提升業務開發的幸福感

 

參考資料