Dropbox與C++的“七年之癢”難跨越跨平台真的是偽命題嗎?
Perl 語言創建者Larry Wall 曾總結過好的程序員有3 種美德:懶惰、急躁和傲慢(Laziness, Impatience and hubris)。因為懶惰,程序員絞盡腦汁地將大量的重複性勞動交由機器處理;因為懶惰,程序員希望通過“一次編寫,處處運行”而實現“一勞永逸”的美好願望。
“一次編寫,處處運行” —— 簡單來說就是跨平台。然而這個十分符合程序員思維,且承載著他們美好願望的方案,在實際操作中往往不能如其所願,甚至會適得其反。
Dropbox工程師近日在其官方博客和大家分享了他們“棄暗投明”的經歷——放棄在其iOS和Android客戶端之間共用同一套代碼的策略,轉而使用各自平台的原生語言進行開發。
工程師表示,Dropbox在2013年開發iOS和Android平台的移動應用時,採用了通過C++語言在兩個平台之間共享同一套代碼的策略。當時的想法十分簡單,開發團隊希望使用C++編寫一次代碼即可,無需分別針對iOS和Android平台各使用Objective-C和Java編寫兩次代碼。另外,當時負責移動應用開發的團隊規模相對較小,為支持快速增長的移動應用,他們需要找到一種方法以通過這個小團隊在iOS和Android平台上快速部署大量代碼。
但現在Dropbox放棄了這個策略,轉而使用各自平台的原生語言(主要是Swift和Kotlin)。之所以做出這個決定,是因為在兩個平台共用同一套代碼的隱藏開銷其實很高。他們從中總結到的經驗就是:如果遵循廣泛使用的平台默認標準,而不是以非標準方式編寫代碼,他們可以不用承擔本應不必考慮的開銷,這種開銷最終比編寫代碼兩次更昂貴。
Dropbox工程師將這些隱藏開銷歸納為四類,在介紹這些隱藏開銷之前,工程師強調他們實際上從未達到大多數代碼庫均使用C++開發的階段,因為正是採用C++帶來的隱藏開銷阻止了他們完全朝這個方向發展。
維護自研框架和庫的開銷
使用C++ 首先面臨的開銷是需要自己構建框架和庫,這大致分為2 個子類別:
- 支持與主機環境交互以構建完整的移動應用程序的框架。例如:
- 用於替代本可以在平台原生語言中使用的默認或者開源標準庫。例如:
Dropbox工程師表示,如果採用平台原生語言,這些代碼都不是必需的,而且他們對開源項目的貢獻可能會使更多的開發者受益於平台原生語言。值得注意的是,上述的這些開銷在C++中尤其高(與其他非原生語言如Python和C#相比),因為它缺少單一的全功能標準庫。話雖如此,C/C++是唯一包含受Google和Apple支持的編譯器的語言,如果使用不同的語言會產生許多其他需要處理的問題。
維護自研開發環境的開銷
移動生態系統有許多工具可幫助提升開發效率。其中用於移動開發的IDE 也非常豐富,Google 和Apple 為其投入了大量資源,讓開發者在相應的平台上擁有最佳的開發體驗。由於Dropbox 沒有使用平台的默認方案,他們自然無法享用這些便利。其中最值得注意的是調試體驗,在平台的默認IDE 中調試平台原生語言的體驗通常優於調試C++ 代碼的體驗。
Dropbox 工程師舉了一個尤其令他們印象深刻的例子,在其後台線程框架中出現了導致應用程序隨機崩潰的錯誤。為此他們使用了簡單的標準堆棧,但是也難以定位這些類型的錯誤。因為這個問題涉及調試在C++ 和Java 之間來回運行的多線程代碼,最終他們花費了幾週的時間才定位了問題所在。
除了工具的缺失,工程師還需要花費時間構建支持共用同一套C++ 代碼的工具。最重要的是,他們需要一個自定義構建系統,該系統用於創建包含C++ 代碼以及封裝Java 和Objective-C 代碼的庫,並且可以生成Xcodebuild 和Gradle 都能理解的對象。正是這個系統對Dropbox 的資源造成巨大的拖累,因為它需要不斷更新以支持兩個構建系統的變更。
可以看到,大量的時間被耗費在造輪子-> 補輪子的重複中。
解決不同平台之間的差異的開銷
雖然iOS 和Android 應用程序都統稱為“移動應用程序”,並且兩者通常具有相同的特性和功能,但平臺本身存在一些影響功能實現的差異。例如,應用程序在每個平台上執行後台任務的方式是不同的。即使剛開始採用這種跨平台策略時具有一定的相似之處,但隨著時間的推移這些差異會大相徑庭(例如,與系統相冊的交互)。
因此,工程師甚至無法真正實現編寫一次代碼並讓它在不同平台上開箱即用地運行。他們必須花費大量時間將代碼集成到不同的平台,並編寫特定於平台的代碼。
所以這裡的“只編寫一次代碼”並不能如願以償,大大降低了這種方法的便利性。
招聘、培訓和留住開發者的開銷
當Dropbox 在其移動應用產品上採用這種策略時,他們擁有一批經驗豐富的C++ 開發者。這個團隊啟動了C++ 項目,並對其他的開發者進行了培訓以為項目貢獻代碼。
但隨著時間的推移,這些有經驗的開發者逐漸去了其他團隊或者其他公司。剩下的開發者缺乏足夠的經驗來支撐和推進項目,而招聘具有相關C++ 開發經驗的高級工程師也變得越來越困難。
最後團隊缺乏維護C++ 代碼庫的關鍵專業知識,而要滿足這一需求團隊有以下兩種選擇:
- 找到並僱用具有這種特定技能的候選人(現實情況是招聘了一年仍未能找到合適的人選)
- 針對缺失的技能,在內部培訓移動(或C++)工程師。但現實情況是缺少擁有所需技能的人員來進行培訓,所以這個目標也難以實現。甚至在培訓前,就有移動工程師透露出對學習C++ 不感興趣。為此培訓所需的開發者也是一大問題。
在招聘問題上,Dropbox 工程師發現許多移動開發者根本不想在C++ 項目中工作,這也導致他們許多優秀的工程師離開項目。畢竟移動開發技術的更新非常快,這些開發者希望自己的技術棧能時刻跟上潮流。
結論
Dropbox 表示隱藏開銷導致最終的成本超過了收益,還不如使用各自平台的IDE 開發更為簡單和便宜。所以最後他們不再通過C++(或任何其他非標準方式)共用同一套移動端代碼,而是使用各自平台的原生語言編寫代碼。