跨平台 (cross-platform) 一直是程式設計圈子不斷出現的話題,從 C 開始,程式設計師試著處理平台可攜性 (portability),到了 Java,跨平台變成了一個響亮的口號,影響後來,近年來的高階語言很少不能跨平台的,甚至還有 Haxe 這種直接以跨平台為主打的語言。隨著行動科技及 Raspberry Pi 等裝置的興起,程式設計師又要面對更多的異質平台。如果以 "cross-platform mobile framework" 為關鍵字,也可以搜尋到不少新的框架,像是 Xamarin、Corona SDK、RubyMotion、LiveCode、Xojo 等等。對於不想學習那麼多種程式語言的程式設計者來說,跨平台工具就像是蜜糖般誘人。實際上真的那麼好嗎?
雖然演算法 (algorithm) 獨立於程式語言之外,當我們實作程式的那一刻起,我們就依賴著某個工具。隨著我們使用的程式語言不同,我們對於平台的議題有著不同的處理方式。如果我們使用 C 語言,我們的確不需要再撰寫組合語言,但除了標準函式庫外,不同系統提供的系統函式庫都或多或少有些不同,C 使用條件編譯來處理這個議題,也就是說,將跨平台這個議題留給程式設計者來處理。即使是 C 的前置處理器的語法,也會隨著編譯器而有些許不同。
而 Java 採取另一個途徑,Java 在系統上額外建立另一層抽象層,也就是 Java 虛擬機器。Java 程式不會轉為機械碼,而會轉為適用於 Java 虛擬機器的中介碼。程式設計者只要撰寫同一套程式碼,就可以在不同平台上執行。當然,世界上沒有白吃的午餐,只是昇陽 (Sun Microsystems) 和甲骨文 (Oracle) 幫我們把這種抽象層處理掉了。早期的 Java 程式運行速度較慢,在不同平台上偶而會有一些小問題;近年來 Java 平台的速度蠻不錯的,而且 Java 歷經多年的實務經驗,相當地穩定可靠,現在也有許多運行在 Java 平台上的新語言,像是 Groovy、Clojure、Scala、JRuby、Jython、Kotlin 等。
Python 和 Ruby 等高階直譯語言也是採取類似的策略,雖然 Python 和 Ruby 是直譯語言,其內部也有使用虛擬機器,只是沒有明確的中介碼,在標準函式庫的層面,的確也是跨平台的。然而,這些高階語言的延伸套件,通常是以 C/C++ 撰寫,如果在其內部使用到某個第三方的 C/C++ 函式庫,有時就沒那麼容易安裝和使用了,在 Windows 上這個問題特別容易浮現。Python 的套件,通常會提供在 Windows 上易於安裝的形式,使用者比較少感受到這個問題。而 Ruby 的問題則比較大,Ruby 雖然可以在 Windows 上執行,但大小問題不斷,實際上,筆者不是很推薦在 Windows 上使用 Ruby,時常要浪費無謂的時間處理各種臭蟲。
而 Go 和 Rust 則是一個可以考慮的方案,這些語言本身是跨平台的,又不需虛擬機器,只要沒有用到 C/C++ 的第三方函式庫,通常都可以直接編譯。然而,這些方案也不是完美的,雖然在標準函式庫的層級已經是跨平台的,但這些新興語言的社群資源通常都較少,也不是什麼方面的任務都可以輕易地跨平台。像 Go 語言在網路方面的函式庫相當完整,但到目前為止,仍然缺乏一個具有代表性的圖形使用者介面函式庫。天下沒有白吃的午餐,必要時還是要自己動手實作需要的功能。
至於行動平台的差異性就更大了,基本上,Android 和 iOS 是兩條平行線,程式設計者需要自已針對各個平台撰寫兩套獨立的代碼。如果仔細搜尋,也可以找到一些跨平台的方案,但是,在引入自己的專案前,仍然要小心地評估這些方案適不適合自己。像是 Xamarin 的網頁就提供一個很好的比較表,將 web app、hybrid app、cross-compiled app 等優缺點列表比較。讀者要注意的是,筆者並沒有替 Xamarin 背書,讀者仍然要去思考每個方案的優缺點。通常這種跨平台方案都是取各平台的交集,會比直接使用原生 app 受到更多的限制。
在採用某個跨平台框架時,小心地閱讀其提供的特性 (features) 以及快速瀏覽一下該框架的 API 文件,在還沒開始撰寫程式碼時,大致上了解這個框架的功能及限制。軟體開發時,最寶貴的還是人的時間。如果在使用某個框架撰寫 app 三個月之後,才發現這個框架無法滿足自己專案的需求,而要一切重來時,那種悔恨的感覺,是非常強烈的。與其發生這樣的事,不如在一開始時,多花一些時間來評估。另外,跨平台方案通常和原生程式採用不用的程式語言,這也意味著較少的資源,包括第三方函式庫、線上文件、討論區文章等。以 Corona SDK 為例,免費版只能使用 Lua 撰寫專案程式碼,如果要使用 C/C++/Obj-C/Java 撰寫延伸套件,則需付費購買企業版 (Corona Enterprise)。筆者的建議是,小心地閱讀有關某個框架的外掛 (plugin) 機制,是否能夠滿足自己的需求。
筆者在初學程式設計時,也曾陷入跨平台工具的迷思。平台的差異並不會消失,只是看用什麼機制去處理,如果這個工具處理跨平台議題的方式能夠滿足自己專案的需求,那就放心地使用並信任它;反之,不要被廣告話術輕易迷惑了,及早跳出不當的框架比事後整個砍掉重練好多了。
[Update on 2017/12/09] 由於自身的需要,筆者仍然持續使用一些跨平台框架,像是 Corona SDK 等。一般人的迷思,會覺得一個框架能夠包越多的平台越好,但是,為了要支援更多的平台,對工具所加的額外限制則越多。像是 Haxe 號稱支援六至七種語言,但為了跨平台,針對每個語言又去做了一些該語言特有的函式庫,結果變成語言跨平台但函式庫不跨平台的奇怪現象。對於這種跨平台工具,應優先選擇兩至三種目標平台,其他的基本上就當成可有可無;像是筆者使用 Corona SDK,只取其對 Android 和 iOS 的支援,其他的則不去理會,就不必花過多時間測試用不到的平台。