我购买的第一本技术课外书:《Excel图表之道》
摘自:http://blog.zhaojie.me/2010/06/is-cross-platform-a-lie-or-not.html
前几天是个神奇的日子,博客园里咣咣咣地出现了三篇文章,都包含了“跨平台”和“谎言”这两个关键字。从Java开始谈到.NET,最后哐地一下,“跨平台”本身也变成一种谎言了。从文章内容上看,我个人觉得基本不靠谱,主要论述方式是用“气势”或是“自信”来压倒对方……呃,是“说服别人”。我不打算谈那两篇文章的内容了,许多意见我和其他人也在文章后面回复过了。我现在只想在这里简单谈谈我对“跨平台”这个问题的看法。
关于“跨平台”这个问题,我感觉还是要分“客户端”和“服务器端”两个方面来谈,或者说“表现层”或“服务层”,或者说“带界面的”和“跑服务的”……总之您明白就好。当然无论拿方面都还是要再细说的。
说到客户端程序,譬如说是一个桌面应用,那么它的跨平台也是很尴尬的东西。就说UI吧,你说不靠谱,它的确能用;但如果你说它挺好,它从视觉效果,使用体验,样式风格方面,都会和周围环境有些格格不入的感觉,无论是Swing,GTK还是QT,跨平台的UI库都有这个问题。其实这也十分容易理解,一个跨平台的UI库,它的确可以做到在不同平台上出现相同的样式或风格。但是,不同的平台,如Windows,Linux或是Mac,它们的桌面环境都有着非常明显的区别。而即便是XP和Vista,Gnome或KDE,再加上各个参数细节的定制,想要在单一平台上做出合适的界面都是不太容易的事情,更何况跨平台。而且,即便一个界面的Look与周围环境一样了,那还有Feel这个说不清道不明的东西。水果公司为了保证界面美观,还提出了详细的“用户界面规范”,您说这让跨平台的UI库情何以堪?
当然,这方面还可以往细了说。例如,我觉得从某些小处来讲,跨平台的UI库还是很有市场的。比如说Silverlight或Flash,它们的应用场景一般是网页中的一小部分,关注的可能是一个“页面”而不是系统应用的体验。再往大了里说,例如您在做一个游戏,那么选择OpenGL就比DirectX更容易移植到各个平台上去(如果拿Silverlight或Flash做独立的RIA也可以算做这种情况)。在这些情况下,我觉得跨平台的UI库是很有意义的,但它们也有个特点,那就是对系统环境Look & Feel的依赖很小,它们的界面自成一体,更像是从一个空白的画布上自己重新造轮子的情况。对它们来说,“老子本来就不需要来迎合你”,那还有什么可担心的呢?
因此我对这方面的质疑,说的更具体些,可能应该是那些“带窗体的、组件形式的可复用的UI库”吧。
那么服务器端是不是就没问题了呢?反正看不到。不过我倒感觉正好相反:客户端跨平台主要问题是感官上的,对我这种非艺术家来说忍忍便罢,而服务器端的问题在我看来就是“叔可忍,婶不可忍”了。说到服务器端跑的程序,总是给人一种高性能,高可用性啊,高稳定性的感觉,总而言之对运行效果的要求很高。那么,跨平台的服务器运行机制,能否做到在各个平台上都用最佳状态工作呢?
这并不容易,因为如果要提供最高质量的服务,往往都需要利用到平台自身的特性。即便是CPU密集型应用理论上也会受到操作系统的虚拟内存管理机制的影响——更别说网络通信等IO密集型应用了。举个例子吧,Nginx是个高性能的Web服务器,主要跑在*nix环境下,也可以运行在Windows下(是直接使用Win32 API开发的,不是利用Cygwin做中间层的方法)。这看上去做到了跨平台,但是说到细节的话,Nginx在*nix下面用了高效的epoll或kqueue,而在Windows下使用的便是低效的select了。同样,Jetty,Mina等框架所依赖的nio,在Java 6中已经开始使用epoll,而对Windows下IOCP的支持,只能等到尚未发布的Java 7了。要知道IOCP作为一种与epoll类似的基于事件的IO机制,早在NT 3.5 / Windows 2000就出现了,而Java 6诞生于2006年底,我相信“时间”不是问题。
所以问题就来了,在我看来“跨平台”不仅仅是“能够运行”的意思,运行的好不好也是十分重要的一点。前一段时间水果教主对Flash的指责得到了果粉们的一致拥护,许多人还补充了更多理由,其中一点便是“Flash对Mac的支持很不好,虽然能运行但是资源消耗严重”(事实的确如此),接下来就是说Flash目前的处境是自找的等等,不提。那么,比如Nginx和Mina,它们在*nix下表现良好,而跑到Windows下面如并发能力就大大折扣了,这又算是谁的问题呢?与Flash问题的看法相同,我不认为这是Windows或Mac OS的问题,问题出在跨平台的机制上。
但我也不会去责怪Nginx和Java(但我会去XX那些因此认为Windows性能差的说法),因为跨平台本来就是很不容易的事情。有时候,即使两个平台都提供了高性能的编程模型,但是它们的编程模型不同,很难用相同的模型进行统一,而强制统一带来的折衷效果可能就变成“都不是最佳”。而且即便“能够”做到在多个平台上实现最好的性能,也需要我们去投入更多的分散的精力——那么,如果我们把这些精力放在对单一平台的努力优化上面呢?因此,我也很能理解如Go语言不支持Windows的情况,用来做服务器的语言么,只支持单一平台也无可厚非。
而且说实话,我也并不是很看中“跨平台”这一点。有些人说Java比.NET好的理由是,Java能跨平台,而Linux比Windows既XX,又YY,还不要钱。但事实上,那些朋友看中的是“Java能运行在Linux上”而不是“Java能跨平台”。而即便Java只能运行在Linux上,对他们来说也就够了。对于一个正经的应用,您会动辄迁移它的运行平台吗?就我许多年前写Java的微薄经验来说,就见到过一次把应用服务器从Websphere迁移到WebLogic而导致问题不断的情况。完美的基于标准的(这是跨平台的必要条件)实现只能存在于理想之中,想想浏览器就能理解这点了。同理,我中意mono,也不会强求它多么多么追求与MS .NET实现一致,我对它的期望只是个足够好的.NET运行环境就行了(当然也不能跨得太差了)。
顺便插一句,我上面的说法可以得到一个推论:对于一个服务器应用来说,程序员在工作时的运行/调试环境要尽可能与生产环境相符。例如一个在Windows下运行调试的Java程序,但生产环境下却是部署在Linux下的做法我就感觉不靠谱。如果真因为条件限制,至少持续集成时的环境要和生产环境尽可能一致吧?同样的情况还有在Windows XP上开发ASP.NET应用程序的人,在我眼中这就是无比山寨的做法,甚至我认为对此没有怨言的程序员也是相当不专业的。
这样看来,不知道是否有朋友会认为我觉得“跨平台是谎言”——我可没这么说。我常干的事情(例如就是这次的“谎言”事件),便是跳到某个针锋相对的场景,比如.NET vs Java,左边扯扯右边拉拉,谈点楼主的问题,也反对一些楼主反对方的看法,所以千万不要以为我反对您的(部分)说法就是在赞同您的对手的(反之亦然)——总之,千万要仔细理解我的意思才好。事实上,虽然我指出了跨平台的一些问题,也可以理解“不跨平台”的做法,但是我同样认为,无论是.NET,Java在二进制层面上,还是如C++,C语言(也包括如PHP,JavaScript等)在语言层面上的跨平台,都是有足够优秀的案例,或者说是实现的。而各种跨平台的机制本身,也可以显著减少程序员对于平台的依赖,也大大简化了开发跨平台应用程序的难度。
总而言之,我认为跨平台不是谎言,它是成功的,也是必要的,虽然有缺点,但还是值得努力的——就是这样。
此外,文章里的“平台”大都是指“操作系统”,但事实上“平台”这个概念远大于此,比如CPU体系结构,浏览器等等都算是平台——因此,其实我的意愿是您可以用一种“泛化”的方式来理解文章的意思。
延伸阅读