【在主画面加入捷径】
       
【选择语系】
繁中 简中

技术杂谈:跨平台工具的甜蜜陷阱

【赞助商连结】

    跨平台 (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 的支援,其他的则不去理会,就不必花过多时间测试用不到的平台。