Archive for 2009年6月

超乎预期的《变形金刚2》

2009/06/30

似乎应了那句老话——期望越高,失望越大。《星际迷航》、《终结者4》、《变形金刚2》这三部片子即将上映的时候,我最不看好的就是《变形金刚2》。不过统统看过之后,失望最小的是《变形金刚2》——甚至应该说还有一些惊喜。

其实我对《变形金刚》电影的不满在于它对原始形象的肆意修改。和《终结者4》对T-800始终如一的展现相比,《变形金刚》对威震天的形象设定简直只能用“What the fuck”来形容。

走进影院终于发现习惯了朋克风格和反乌托邦风格之后,对《星际迷航》这类太过歌剧风格的电影已经略感厌倦(《Lost in Space》的票房惨淡似乎也是因为歌剧风格过于浓重)。而且这部最新的《星际迷航》情节明显有些单薄。比如科克和史巴克的指挥权争夺形同儿戏。为什么地球和史巴克母星全文明的力量都拿那艘采矿船改装的星球毁灭者无能为力而企业号一己之力就将其击溃?《终结者4》最大的败笔则是最后马库思在状态良好的情况下牺牲自己拯救约翰。虽然高尚,不过牺牲一个活蹦乱跳的人来搭救另一个人无论如何不是让所有人都能从伦理上接受的决定。

相比之下《变形金刚2》的情节比较流畅。没有什么磕磕绊绊的地方和让人反感的地方。其中出现的变成美女的变形金刚还在提醒大家,我们变形金刚比什么终结者T-800T-1000T-X都牛多了。看我们的形象多么完美。比起你们那种刚刚脱离人类怀抱的人工智能要强大万倍。

其实撇开对威震天形象的不满,我很喜欢《变形金刚》的一些设定。非碳基自主生命体是《变形金刚》提出的独特概念(而且是在80年代初)。变形金刚不是机器,比如,他们有自己无法解释也无法创造的灵魂,他们的身体构成既不同于普通的机器也不同于碳基生命(广义的碳基生命,比如在高温下硅和碳的常温性质相仿,所以这种类型的高温硅基生命形态也可以看成碳基生命,或者称为有机生命)。

对《变形金刚》的喜爱有很大一部分来自其小说。这部小说的设定是第一部真人电影的前传。小说着力描写了电影不曾似乎也无力表达的一些迷人的问题。比如,变形金刚是永生的,他们对待战争和生命短暂的智慧生物的看法会和我们有什么不同?再有,变形金刚对人类的技术奇异点视若无物。他们有自主的思维,但是同时检索和精确分析的能力又超群,红蜘蛛在小说中用几十秒就能理解人类超级计算机的所有程序并控制其运行。这样的生物,他们延续和发展文明的手段与我们有什么不同(比如,人类不可能靠少数个体延续文明,必须依靠强大的行星工业体系)?另外,他们也有自己的技术奇异点,火种是他们一直不懈研究但是又无法解答的问题。是否所有文明最终都有无法超越的奇异点?

威震天和红蜘蛛又一次在结尾逃走了。不过相比其它的系列电影没完没了的开放结局,《变形金刚》似乎更有资格这样做。金刚们有的是时间,几百万年一瞬而过。

Mac OS X的字体[2]

2009/06/27

《Mac OS X的字体》发布之后,甫鸼提出了一系列质疑。当然他没有否认很多人认为《Vista puts Mac OS X font rendering to shame》的作者是微软的枪手(不过修辞十分诡异),但是回避了自己对该文的看法。

我对Mac OS X的字体确实有所偏爱,周围的很多人此的看法与我不同。其实当下有多少人与我感觉异同的重要性在其次,我更希望搞明白的是人们做出偏爱Windows的判断有多少成分是出于习惯,有多少是出于(潜意识中的)深层次原因。但是这个问题并不那么好回答。

Vista puts Mac OS X font rendering to shame》(并非原文,而是附带的评论和调查)的意义在于给这个问题添加了一个可信度很高的旁证(尽管由此得出确定性的结论还显轻率)——62%的参与投票的人更欣赏Mac OS X的字体渲染效果,也许可以一定程度上说明身边人的不同看法在于这些人群接触Mac的比例还是不如北美高;及评论中给出的各方面解释,很大程度上说明从深层次原因看还是Mac OS X的方式更有优势;综合说来,很多偏爱Windows的判断中武断的习惯的成分更高一些。搞清楚这个一方面满足了我的好奇心,一方面也是对未来的一种预测——基于习惯的选择往往会逐渐让位给基于其它本质原因的选择。(当然有些习惯的力量是巨大到无法改变的,比如键盘的QWERT排列。不过Mac OS X已经取得的9%的份额让我相信关于字体渲染的习惯没有巨大到无法改变。)

下面讨论一下甫鸼的疑问。第一是显示器分辨率的提高能否“自动”减轻Mac OS X字体边缘发虚的问题。首先说明,这里的分辨率不是像素数,而是每英寸像素数。所以iPhone的屏幕虽小,分辨率却高于大多数LCD的分辨率。在解释“能”与“不能”之前,重申一点,边缘发虚是一个缺点,但是在无法达到完美的计算机方案中称其为代价更加合适,而《Mac OS X的字体》已经解释了这种代价是合理并且值得的。也就是说,即使这个问题还停留在今天的程度,对于字体渲染的整体优劣也并无影响。

下面说说这个问题能否被“自动”减轻,首先举两个例子,第一是《Vista puts Mac OS X font rendering to shame》的评论2.2.1.1.4,在评论者的旧CRT显示器坏掉之后,他为自己的旧Mac接上了新的LCD,同样的硬件(除了显示器),同样的渲染算法(苹果从Mac OS 9就采用的),在接上新LCD之后字体的效果焕然一新;第二是很多人使用了iPhone之后,都感觉iPhone的显示效果比LCD要好;而且当整个大页面缩小到小于iPhone屏幕的时候,虽然不适合阅读,但是页面的布局和整体效果是不错的,而且很多情况下单个字体仍然可以分辨,而基于Windows CE的设备在相同的比例下字体已经完全不可辨认。

例子就是例子,我不想用两个例子就粗暴的泛化到一般情况,但是实例也有其独特的说服力。另外从推理的角度看,重视准确度的渲染方案和一般图形的渲染方案相比原则上更为一致。一般图形的反走样算法也是重视准确度的。也就是说,在Mac OS X上对一条普通贝塞尔曲线的反走样(anti-alias)算法基本上与Mac OS X上一个字型上的贝塞尔曲线的渲染方法是一致的。而Windows上对字型的处理是区别于一般图形的,你不可能把Windows对字型的那种强行修改以适应显示器像素的做法应用到普通的斜线或是曲线的反走样上,所以Windows的字型渲染在Windows的整体图形方案中是ad-hoc的(从《Mac OS X的字体》的截图中,IE对于日文字体中的斜线的处理可以看出,如果真的把Windows的字型渲染方式应用到斜线上是多么恐怖——因为日文假名中存在比较明显的斜线,而拉丁字母中比较少见长斜线,所以这一现象对于英语使用者并不熟悉)。

总的说来,实例说明Mac OS X的方式不经太多调整就能很好的适应显示器分辨率的提高。而推理说明,即使Mac OS X的字体渲染真的需要调整,只要借鉴普通图形方案的调整经验就好。另外,苹果始终坚持同时控制软硬件最后把关的做法也能占到先机,可以比较严格的控制Mac OS X运行的硬件平台,从而选择适合Mac OS X的显示器材。

对于字体选择的问题,很高兴Windows缺省自带的文本编辑器采用了两级管理的方式。不过Word 2007和很多其它更专业的应用似乎没有这样做:

基本上似乎是因为Windows APIs主要还是用font face来列出字体。文本编辑器自己做了归类管理。但是很多功能更全的应用似乎把精力花在了别处。高兴的是,Office 2008 for Mac的字体管理是两级的。另外在《Mac OS X的字体》中有一点没有提到,Mac OS X的字体既可以在系统级别安装,也可以为用户单独安装,这一点似乎也是Windows没有的。(由此也一窥Mac OS X的Unix血统让其多用户风格自然呈现,而Windows的单用户风格难以在短期内消除。)

接着是Safari在Windows上的字体问题。严格的说,这个不算是字体渲染的问题,因为很明显是字体的选择出现了问题。(OK,我承认我也引入了字体管理这个和渲染不相关的问题。)这个问题我得研究一下,因为手头没有在用Windows,而且还要下载Safari for Windows。不过,Mac OS X本身的字体渲染体验仍然是完美的。而且字体选择的问题终究没有字体渲染的问题那么难以修改。 🙂

最后是关于苹果软件的字体渲染功能的提供问题。上面说的字体渲染策略都是指Windows平台上和在Mac OS X上由操作系统提供的方案,准确的说在Windows平台上是GDI,在Mac OS X上是Quartz。当然一个在Windows平台上的应用选择不使用GDI的字体渲染方案也可以,那就是用GDI的低级原语(如像素)来自行渲染,Adobe Acrobat for Windows和Safari for Windows基本上就是这样做的典型例子。不用Quartz提供的字型渲染也可以,但是似乎没有Mac OS X的应用这么做。FireFox、Opera在每个平台上都是直接使用平台本身的渲染的,Microsoft Office也是如此。所以看看他们的渲染效果更有代表性。

Mac OS X的字体

2009/06/26

经常听到有人说“Mac挺好用的,就是字体有点发虚”;或者“就冲Mac的字体效果我也不买”。老是听到这些不免有些迷惑——我原来是Windows和Linux的用户,从Windows转向OS X 50%因为UNIX,50%是因为字体;从Linux转向OS X 那就90%以上是因为字体了。莫非自己的感觉太神秘,太不理性,太孤僻?

今日在网上看到一篇《Vista puts Mac OS X font rendering to shame》。从题目看觉得阅读它又要体会一番道不同的煎熬。不过进去才发现自己并不孤单——虽然作者对Mac OS X的字体渲染口诛笔伐,但是文章下面的调查里62%的人认为Mac OS X的渲染效果最好。评论更是精彩。

关于字体之争,大家有一点是赞同的:Windows把字体形状根据显示器的像素进行变形,使字体尽量和显示器像素吻合,称为注重可读性;Mac OS X即使在低像素下仍然尽量通过反走样算法最大可能接近字体的原始数学描述的形状,称为注重准确度。最大的争议在于到底是可读性还是准确度才是大多数人需要的?(说道这里插一句。Windows里面对于某些字体(比如宋体)的小号字干脆图省事使用了点阵字库。)

上面从左到右就是Windows下的点阵(宋体),Windows ClearType,和Mac OS X的效果。从最下面一行的“听”字可以看出,Mac OS X的“听”的“口”和“斤”的比例是最匀称的。Windows的雅黑和宋体为了硬性的适应显示器像素,“斤”的最上面一撇的斜度有很大变形,”口“的位置和高度也和原始字型的设计有出入。这种情况在”通“字的”甬“与“走之”的相对位置,”话“的”言字旁“和”舌“的位置也有体现。另外就是字体大小变化的比例线性,如下图(左为Windows,右为Mac OS X),OS X的字体大小是符合线性的。

谈到这里可以得出一个大多数人都同意的结论。做出版印刷的专业人士必用Mac。接下来就是常见的反驳——”喂,我每天都对着屏幕阅读,但是不会打印一张纸。OS X对我根本没用!”  如果是这样,那么我也属于整天对着屏幕的人,我对Mac OS X显示效果的偏爱难道是一种不合逻辑的病态吗?

还好,那62%的人也并非都是每天消耗一叠A4纸的人。他们给出了对我的直觉的解释。语言不是单个字或者字母的简单组合,字组成词,词组成句,句组成段落。当我们阅读的时候,解释语言的速度远远高于我们的大脑分辨每个单独的字是否清晰的速度(更加高于分辨每个笔画的清晰的速度)。我们的思维更多的落在词或者句上面。这时,注重准确性的渲染方式对于词或者句子的整体表现效果更好。也就是说,Windows注重的”可读性“是对于字母的可分辨性的过分注重,反而牺牲了人真正的能够感受的可读性。从上面中文字体例子也能看出,单个字体的显示越匀称,整行字也就显得越整洁。相对的,为了笔画清晰而牺牲匀称度,整行字也会有些许里出外进的感觉。

另一个问题是显示器的分辨率必然越来越高。在这个过程中,Mac OS X的显示算法不用做任何调整就能自动适应,而且其边缘不够清晰的缺陷也随之越来越不明显。Windows的ClearType技术则必然要经历调整。

Windows算法更大的问题是它对单个字母的可读性的注重其实也仅限于拉丁字母。用日文字体的对比来比较一下,就能够看出擅自改变字型的渲染算法对于复杂的字体渲染是多么不友好。当然用繁体中文(尤其实斜体效果)比较更好。不过我懒得自己截图了。

最后再说说一位字体专家在评论中提到的关于字体的,但与渲染无关的话题。Windows的字体管理仍然比Mac OS X混乱无数倍。直到Office 2007,Windows的大多数应用仍然不是根据font family和font face两级来管理字体,而是把所有字体混为一级让用户选择。这和Windows提供的字体管理API有很大关系。而OS X的字体管理服务天然的让一般应用按照两级来管理字体。

好了,这个话题由ZDNET上一篇吹捧Vista的文章开始。中间有统计数字,也有专家的评述,还有大量外部引用。我很高兴有如此多的人和我感觉相同,并且从专业角度说明了我的自觉(而且广博到我没法完全详细读完)。而身边一些人接触过Mac OS X之后仍然执着于Windows的字体渲染也让我心存迷惑——是否能完全用习惯的惰性来解释他们不能欣赏Mac OS X的字体呢?现在下此结论未免轻率。不过从这些专业的评论来看,即使我们尊重个人的选择,也只能说对Windows清晰边缘渲染的偏爱是一种更加神秘的无法用理性解释的感情渊源。

3G——又一个“铱星”

2009/06/22

3G这个东西我怎么看怎么像是另一个“铱星”。技术上说,当年刚刚被提出的时候真是众望所归。等到姗姗来迟的时候,“铱星”遇上了GSM,3G遇上了Wifi。

用户由来已久的习惯是差不多就得(good enough)。“铱星”还勉强能和GSM同台竞技的时候,不过是比GSM多覆盖了偏远地区。同样,和铺天盖地的Free-Wifi相比,3G的覆盖能高到哪里去呢?再说当年到了农村就改用用老乡的固定电话不好么?如今找个清静的地方用GPRS上网休闲一下呗。

从带宽方面来说,3G的底气也不足。自己先告诉用户,别指望像ADSL那样挂BT,我们3G就是个有益补充。咱做有益补充的不用和固定的ADSL比。是么?我怎么隐约记得“铱星”不能在室内通话也是被抛弃的原因之一?

不过3G也没惨到“铱星”的份上。3G的设备大多都能和Wifi无缝切换(要是WAPI不松口,这一条也只能适用水货),也没有当年“铱星”电话和GSM电话比较那么贵。还算有点儿希望。但是我就是觉得,骨干网都IP化了,电信网还能撑着不和Internet合并多长时间?

缓存与文件系统——之一

2009/06/18


当你觉得需要一个缓存的时候,把情况再探究得深入一些然后问自己为什么需要这个缓存。

Unix认为世界是静止不动的。

妥协并不讨好。

——《The Art of UNIX Programming》

最近一段时间的主要工作是维护和开发一个文件浏览器类型软件(类似于Mac OS X的Finder和Windows的Explorer)。这个软件与Finder和Explorer的一些重要的不同之处有,从功能上说更加偏重图片管理,从技术上说设置了一个缓存,用来存储经常遇到的图片的缩小版本。缓存会让显示文件缩略图(Thumbnail)的速度大大加快。应该说这个缓存功能对于管理大量高分辨率图像是很有用的。但是它未能避免违背《The Art of UNIX Programming》的一些告诫。尽管违背这些告诫有很好的理由,而且大部分用户还是对违背这些告诫的代价和收益表示认可,但是维护中因此遇到的越来越多的麻烦导致我开始思考是否这些设计上可以有更好的替代。

缓存是在谈及提高效率时通常被首先考虑的技术之一,但负面影响也在《The Art of UNIX Programming》里被强调——和主存的同步问题和命中率问题很难解决。这个软件的缓存比较特别,由于存储的是图片,而且是主存的缩小版本,所以该缓存可以存储所有访问过的主存图片,而不必用类似最近最少(LRU)算法去丢弃某些部分(至少不必像CPU缓存那么频繁),因此不存在传统的命中率丢失问题。但是它有另一种形式的命中率问题。如果没有这个缓存的存在,那么一个程序要显示一个图片的缩略图,只需要把图片读出,用down-sample算法缩小,然后绘制在屏幕上。有了这个缓存,除了上述的操作,程序还需要把down-sample的结果存储到缓存中(由于绘制在屏幕上的缩略图每次大小不完全相同,存储到缓存中的缩小版本的分辨率还要比屏幕缩略图需要的高,这样以后读取缓存来绘制缩略图的时候仍然需要down-sample,虽然down-sample的程度减小了)。另外,为了用批处理提高效果,缓存的生成是以文件夹为单位。这样即使一个文件夹用户只浏览了前几个图片,后端的线程也会为整个文件夹生成缓存。如果用户偶尔浏览一些以后很少用到的文件夹,对磁盘I/O和磁盘空间可能都会造成一定程度的浪费。所以在某些情况下这个缓存会拖慢而不是提高效率。这说明任何类型的缓存(甚至任何类型的优化策略)都会在某些极端情况下劣于简单的直接访问(蛮力策略)。

《The Art of UNIX Programming》提到的缓存的同步问题主要受到主存更新方式的影响。但是现代软件越来越多的采用plug-in架构和具备online live update的功能,所以缓存的同步也开始受到软件本身更新方式的影响。如果一些plug-in或者软件本身的更新改变了生成缓存图片的方式,那么如何同步已经缓存的图片就成为一个复杂的问题。比如,一个plug-in的升级可能改正了原来有色彩失真的缓存生成方式,但是原来哪些文件会造成色彩失真并不是一个可以简单的用某些轻量级算法判断的标准。所以保险的方法只能是在升级plug-in的同时清除所有已有的缓存。由于plug-in架构本身是为了屏蔽不同plug-in实现的细节,所以缓存中哪些图片是由哪些plug-in生成的也往往不容易判断,所以最后常常只能通过清除整个缓存来解决。

主存的更新是缓存同步的最主要挑战。对于这个软件来说,这个挑战的更加艰巨。因为这个软件的设计是把整个文件系统作为主存。正如《The Art of UNIX Programming》指出的,UNIX文化建议利用文件系统达到重用,但是没有过多的考虑通过并发访问文件系统来协作,UNIX假定程序的运行是短暂的,在运行期其涉及到的文件不会被其它程序访问;假定程序间的文件访问是交替的而不是并发的;假定程序对频繁修改的文件独享,而只会共享少量罕有修改的文件。把整个文件系统作为主存,通过设置缓存来提高性能,这样的设计会遇到很多问题。比如,对于正在被写入的大文件,很难判断是正在写入过程中,还是写入已经完成。如果在写入过程中被生成缓存,那么缓存文件就是错误的,但是没有机会得到改正(除非用户手动清除缓存——但是缓存策略的主旨就是避免用户经常手动清除缓存)。由于所有操作系统在文件系统方面受到UNIX很大影响,所以它们都很大程度上有同样的问题。解决的办法往往很难做到高可移植性,往往非常复杂,会引入更多的线程同步问题。

将软件设计成为一个类似Finder和Explorer的全系统浏览器,还有一个问题,那就是是否要用其本身的GUI反映一个文件系统的所有细节。显然,出于并不希望复制Finder和Explorer和突出自己特有功能的目的,该软件选择了简化某些细节的做法。比如不会显示文件的读写权限,只显示文件的锁定状态。但是,和很多复杂系统一样,文件系统的很多概念是相互联系,但是又部分正交的。很难完美的掩饰某些细节而不造成混淆。比如,文件是否可以锁定是受到文件读写权限的限制,所以文件锁定状态的改变会因为读写权限的原因而失败,最终用户还是必须了解被隐藏的概念和细节,这就抵消了最初了通过简单的UI简化用户操作的初衷。其实就连Mac OS X的Finder本身也有这样的问题——OS X的HFS拥有传统的user-group-other权限和ACL的权限,但是Finder没有区别显示而是混在一个GUI权限列表中;另外,HFS的锁定(lock)有user-lock和supervisor-lock两种,Finder也没有区别显示,这样Finder对于一些ACL比较复杂和一些拥有supervisor-lock的文件的显示结果就比较奇怪。这说明文件系统的细节的复杂程度连专门浏览器的GUI都有些难以应付。当你希望隐藏细节的时候,“妥协并不讨好。”

而且,不要忘记,所有这些被显示或者被隐藏的细节,都可能被其它的程序在任何时候修改。在决定了让你的应用可以访问整个文件系统的同时,相应的就必须承担其它应用和你的应用竞争访问的后果。(有人认为Windows那种强制文件锁(mandatory file lock)可以解决问题。其实强制锁引入的问题比解决的问题多,而且其功能与文件权限概念有重叠和混淆。)更不要忘记,在被显示的细节里,有一部分会被放到缓存中。这些问题加在一起,会把系统卷入无穷无尽的边缘情况(edge case)中。

有了这些观察和思考,我开始理解为什么类似iPhoto的软件开始采用另一种设计模式——私有数据库。iPhoto类的软件没有被设计成直接处理文件系统任意区域的软件,而是要求用户必须把待处理的图片“引入(import)”。引入操作实际是把图片置于一个受到保护的私有数据库。引入私有数据库是否意味着要重复实现很多文件系统已经提供的功能?并不是必然的,因为这个私有数据库可以普通文件夹——唯一的特殊之处是不对其它程序开放(比如位置难于访问,或者在文档中说明,或者利用其它程序的一些功能——比如Finder中显示为单个文件——从技术上完全阻止直接访问内部),对其编程访问仍然可以利用文件系统的操作,同时省去了诸多的文件并发访问问题。在私有数据库内部,文件的细节也更好控制,比如你完全可以控制数据库内的任何文件都没有ACL(甚至拥有统一的user-group-other权限),也没有supervisor-lock,因为修改这些细节的只有你自己的程序。这时一个简化的UI也极少会导致混淆(即使会也是易于修改的bug而不是上面那种由基本设计导致的问题)。在私有数据库模式中,缓存的两个固有问题不会消失,但是会得到大大的缓解。也可以说,如果为了图片管理中的性能目的而必须引入缓存,那么私有数据库模式是一个很值得考虑的选择。

现代操作系统是一个非常复杂的高度协作的系统。通过单个应用程序达到一个全系统级别的简化操作就算不是完全不可能,也是一项有极端挑战性的工作。因为这意味着你的应用程序就像一个把全系统都覆盖在后面的幕布,但是同时你又必须允许你的用户绕过幕布去操作这个系统(因为你把全系统都盖住了,但是用户又不可能只用你这一个应用)——这种矛盾的策略让你很难在这个幕布之前演出一幕没有纰漏的剧目。更为可行的办法仍然是针对自己的需求,把应用程序的操作涉及范围尽量局部化,这样,你的幕布仅仅覆盖了系统的一小部分,你更为容易说服用户永远不要绕过这个幕布。

后记:出于篇幅的考虑,有些问题的细节没能全面展开。这样可能造成一个假像,让一些喜欢思考的不易被轻易说服的读者认为文中列举的问题没有严重到必须采用私有数据库架构的地步。所以我考虑冠以“之一”来让以后的“之n”等展开说明那些被质疑的比较多的问题。

C++恶性录——之二

2009/06/10

C++中有很多东西是发现的,而不是设计者故意设计的。STL,Template Metaprogramming都不是设计者预先料想到的。所以Bjarne给他的书起名为“C++的设计与演化 (The Design and Evolution of C++)”,我认为这是它迷人的地方,它能够进化。你不能把这些称为workaround或show off

——樊志岩对《C++恶性录——之一》的评论

It’s risky to design minilanguages that are only accidentally Turing-complete. If you do this the odds are good that, sometime in the future, some clever fellow is going to think he needs to press your language into doing loops and conditionals for him. Because these are only available in an obfuscated way, he’ll produce obfuscated code. The results may be serviceable in the short term, but are likely to be a nightmare for those who come after him.

——《The Art of UNIX Programming》


认为C++“迷人”的同学中,有一部分是因为从C++里面发现了那么多意想不到的东西。意想不到的东西给人悲伤、震惊、或者乐趣。但是带来惊喜和乐趣的意想不到并不一定代表好的工程设计。

从C++里能“发现”这么多东西,是不是说明了C++的设计是经过深思熟虑、抑或就是其设计者灵感迸发、(相比那些后来从中“发现”的东西不那么多的语言的设计者更)才华横溢的体现呢?看来有一部分人是这么认为的。但是崇拜经常来自于知识的缺乏。如果你了解了“图灵完备”的概念,然后把template考虑成一种compile-time minilanguage,再把两个概念放到一起,就会把“迷人”的外衣剥落。只要你让一种语言达到compile-time图灵完备,不从中“发现”那么多东西倒是奇怪的了。达到图灵完备是任何一个语言设计者都轻而易举能掌握的技巧。事实上,正如《The Art of UNIX Programming》所告诫的,了解图灵完备概念的意义在于避免无意中触发它而不是不必要的实现它。

那么,抛开“发现”这么多东西的原因,“发现”的这些东西是对工程有实际作用的吗?“[S]erviceable in the short term, … nightmare for those who come after …” C++里面发现的东西,可读性都很差,如果出了编译错误更是没法收拾。例如,C++曾经用template实现了一个LL(k) parser generator,很奇妙么?但是这个东西产生的parser对unpredictable syntax的处理是silent failure。所以这个东西只能是孤芳自赏的玩具!

C++ template是为了静态类型安全设计的。但是当一个在高级语言里可以用smoke test很快发现的错误在C++里变成一个晦涩的编译错误的时候,只能说C++的设计者失去了更广的视角。静态安全在一定限度内是有益的,不知道在什么地方停步是C++设计者的问题。不舍得付出任何代价,用template specialization这种补丁来达到效率提升从而意外的引入“图灵完备”,最终让C++失去的东西更多。

回忆Java乱谈

2009/06/07

昨天聊天被甫鸼问到有没有看过什么Java写open source项目,回答没有。被追问为何没有,回答说真正对open source开始感兴趣的时候已经对Java失去兴趣了。

回想当年对open source还只是草草尝试、没有上手的时候,感觉阅读CC++的代码真的很头疼(其实只是因为当时还没有掌握基本的grep操作,只会用UltraEditsearch in files)。那时候对我来说编译过程就更神秘了(后来花费了两个月的时间读Linux kernelmake file,其中包括一个星期阅读make文档花费,这种神秘感才彻底消除——不管你能不能看懂代码,也不管你的修改是不是在编译之后真的起作用,只有你真正明白到底是什么样的一组命令把一堆C文件变成了一个没有扩展名的文件你才能开始感觉一切在掌握之中)。那时候我对Java的评价是open source设计的完美语言,因为one-true-way的风格让代码只有一种写法,编译过程简单,根本没有连接和后期的binary文件处理。

讽刺的是,当我真正开始推崇open source的时候,已经对Java懒得看上一眼了。这发生在将近四年前,稍候在工作中完全脱离Java也已经近三年。其间也偶尔考虑过Java的成败。这时被甫鸼问起,想来也应该写下来一些感想。

Java失败(姑且认为是失败了吧,可能有人不同意这种说法)的最主要的原因就是Sun只做平台不做应用——甚至还有更绝的,当年有种说法是鼓吹Sun只做标准,连平台实现也不做了,言语中还对能靠写写标准就能赚钱的企业十分羡慕。可惜的是用户可不买帐,没有end-to-end(一头是硬件,一头是最终用户能看得到的产品)的方案,用户不会掏钱。看到Windows独占市场的人都嚷嚷当年的Wintel联盟,可是是不是没看到有多少用户仅仅是因为离不开Office而不得不Windows掏钱的呢?

Sun不好好做应用,天天大吹大擂平台本身。最后的结果是不管如何大家都开始认为这个平台本身就能赚钱了,吸引了一大批围着平台打主意的厂商。微软的J++被干下去了,IBM自己的JDK最终推出了。Sun这下子有点恼火,马上打定主意,对Java标准还得看的死死的。

Sun对待Java标准的态度极大的伤害了Java平台。事实证明,所谓JCP一类的民主,相对于真正的Linux kernel风格的open source来说,都是不可救药的官僚,根本起不到改进软件的作用。Sun也有自己的委屈,所谓一统就死,一放就乱,标准都放开了,Java标准岂不是都乱了。其实问题要从两方面考虑,第一是得相信大众的智慧,好的软件是进化出来的,不是一下子设计出来的,不放到严酷的环境中自然演化不行。第二是如果真的乱了,说明软件本身的接口复杂度过大(参考《HTML 5想到的[2》),换句话说,是不是Java本身的野心太大了?一统武林的想法是好的,但是别成了岳不群。

其实Java这么庞大,也未必是每个模块都开放用户才高兴。Sun应该学学苹果,把Mac OS X的内核和SafariHTML engine和盘托给open source社区,自己安安心心做Cocoa,做OpenGL优化,做高级的色彩管理和字体渲染,做Safari的用户体验。Sun如果早早把JVMopen source社区,自己把Swing的架构、控件和主题做到最好,好好做上层应用而不是把这块丢给ApacheJBoss,那么JVM本身未必会分裂(谁会让一个用户都喜欢的Swing或者App Server运行不起来呢),Java本身未必会失败。

回头看看我对Java失去兴趣的时候也是对open source真正开始入门的时候。这仅仅是一个巧合吗?也许Java满足的只是一种虚假的需求。话说初学者推崇备至的技术有些到了高手看来很难用(反之的情况也有)。软件开发是否也是这样呢?也许很多人只是欠缺一些阅读分析代码的技巧;或者是有些人被C++的滥用语言特性迷惑而失去了对现有语言的信心;或者是当时更为抽象的动态脚本语言比如Python还不为大多数人所知。Sun的强大宣传力量让很多人一时无从分析自己真正需要的是什么,转而寻求一种激进的替代品(话说人类历史上那个被经济危机打乱的年代似乎也有类似的情况)。

过去的已经过去。由Java的现状和它为自己赢得的名声来看,我认为它永远不会回归主流了。我们的未来的语言会如何?C大概会一直占据底层系统开发的地位。C++继续受到C和高层语言的打压。高层应用的仍然保留大量C++代码,但是在寻求转变。原本认为由Java占领的阵地由JavaScript、Flash/Flex、AIR、Objective-C、Python、Ruby、Perl等工具来占领。这些工具能够比Java成功都在于克服了上面所说Java的一个或者多个弱点——或者更开放,或者在早期就拥有优秀的无法让用户割舍的应用。

从HTML 5想到的[2]

2009/06/06

MIT风格注重界面的简洁,“新泽西”风格注重实现的简单。⋯⋯ 虽然遵循MIT风格更有可能达到更好的抽象度,但是(较差的)“新泽西”风格的软件更容易传播。假以时日,“新泽西”风格的软件更能吸引人们的注意力,从而得到更大的改进。良莠因此对调。

——《The Art of UNIX Programming》

 

HTML替代plug-in的趋势也许意味着“新泽西”模式再一次战胜MIT模式。由于HTML最初低下的表现力(expressiveness),各大公司并不屑于把HTML标准作为宝贵的财产牢牢的控制,而是漫不经心把标准交给国际组织,形成了HTML/CSS/JavaScript更为开放的姿态。

HTML的接口比plug-in技术更为复杂,HTML的数据、表示、代码相互混杂的接口比plug-in的编程脚本语言难用的多。复杂的接口意味着意味着更少的操作原语(primitive)[1],以及原语和底层实现能更直接的对应。这意味着,首先产生歧义的机会更少,其次接口的实现更为容易,用户能够更快的得到参考实现作为进一步消除标准歧义、统一接口行为的依据。

从更广的视角来看,软件业解决一个特定问题时选择的接口复杂度的过程呈现一种在震荡中趋于稳定的模式。最初由于技术不成熟选择过于粗糙的复杂接口,而后开始进行抽象简化接口的努力。简化使用的需求推动寻求更高的抽象层次,但过高的抽象层次会被自己的实现复杂度压垮,因为过于抽象的接口定义的会因为实现复杂度过大而歧义丛生,导致实现的分裂。最后接口的抽象度逐渐在简化使用和接口统一的双重需求下收敛于有利于两方面的最优点。CORBA一类的RPC技术最后普遍退回到基于HTTP请求的页面访问服务或者基于socket的应用协议接口就是典型实例。

认识技术竞争的本质和对统一接口强烈的需求,在分析软件技术现状的时候会抛弃对高度抽象的所谓优雅接口的不切实际的追求。对粗糙接口的坦然面对也是一种放弃执着的体现。软件的复杂度不仅仅受到人类个体智力的限制,也受到人类社会行为的限制[2]。

 

注[1]:接口复杂度的高低并非取决于原语的多少,而是取决于使用每个原语时的难易。因此高复杂度的接口往往拥有更少的原语(比如汇编语言拥有更少的原语,底层网络协议接口也比高层网络协议的原语更少)。这也是接口复杂度和实现复杂度成为tradeoff关系的原因(实现复杂度很大程度取决于原语数量)。

注[2]:这种限制即技术奇异点。技术并非不能越过奇异点,但是越过之后开始自身发展而超出人类的理解能力。

《太空堡垒卡拉狄加》的结局

2009/06/05

前天和老婆看了《太空堡垒卡拉狄加》大结局——幸存的12殖民地居民和塞昂人决定放弃所有科技,回归原始状态。虽然只是一部商业剧,但是我还是对这样的结局感到失望。

首先,考虑到一个文明得到这些技术的漫长经历,很难相信人们会同意放弃所有的技术。也许《卡拉狄加》的人们(人类和塞昂)在经历了由于技术发展导致的一切之后心态有所变化。所以我不就这点再深究。

其次,剧中放弃科技的目的是为了打破人和机器之间战争的循环。但是在我的信念中,打破循环需要恰恰是了解更多的知识,而不是抛弃知识。抛弃所有知识,让人们从黑暗中再次摸索一遍,期待这样的摸索能够不再走入循环,这样的计划似乎有些盲目而缺乏逻辑。依我看,这样根本没法打破循环,只能让这一次的循环拖延更多的时间。(剧情似乎也支持了这一点,从科博到地球,从地球到12殖民地的循环用了几千年,而第二地球用了15万年得到一个单一行星上没有宇宙航行能力的更加和脆弱文明,但是却并不缺少对技术的滥用。)

作为一个怀疑主义者,我并不认为追寻知识有至高无上意义。但是《卡拉狄加》结局对知识作用的否定似乎和整部剧的其它部分自相矛盾。即使怀疑主义在更高层次上是正确的,但是它否定了人类自身延续的意义。而整部《卡拉狄加》都是在为文明的延续而努力。结局告诉我们,12殖民地和塞昂人终于精疲力尽,放弃了延续文明的努力,或者他们最初的信念也仅仅是保存DNA而已?

可能《卡拉狄加》的理念是希望人们不要执着于已有的知识。但我认为不执着并不意味着把它们都扔到太阳里去。

写下这些不是为了谴责编剧的智力。也许我确实没有参透编剧的思路。另外,美剧确实有着各种现实原因影响情节。另外,作为把架空的时空和实际现实联系起来的某种风格,在连接点上一定程度的牵强附会也很难避免。整部《卡拉狄加》都让我感受到文明在技术奇异点周围徘徊的奇妙体验,最后的结局是一种退缩,破坏了这种感觉。

 

从HTML 5想到的

2009/06/04

最近发现很多地方在讨论HTML 5。突然感觉HTML标准照此发展下去,最终可能迫使Adobe Flash这样的plug-in退出Web的舞台(还有微软的Silverlight,如果它能真正登上舞台的话)。

HTML 5是HTML标准化力量(很多人相信是Google和Apple在推动)的一种努力,以争取更强大的,不依靠于私有plug-in的表现能力(expressiveness)来支撑复杂的Web应用。HTML 5为标准还有待时日,但Web在过去几年里的表现能力已经有了大幅度的提升。下图是对不同的界面表现技术从其出现至今表现能力的一个大致估计(这不是我的估计,但是我很同意这幅图)。

这幅示意图说明,界面表现技术(甚至推广到所有计算机技术),都具有不可阻挡的收敛趋势。一开始,不同的技术针对不同的应用范围(比如,界面的发布广度决定了是选择表现力较差的HTML瘦客户技术,还是表现力强的OS native技术;硬件的速度——工作站或是嵌入式移动设备,是另一个决定技术选择的因素;等等)。针对不同应用范围的技术不会直接竞争。慢慢地,不同技术独立的发展让它们的各项指标逐渐接近,各自的使用范围开始扩大,重叠最后重合。竞争最终会得出确定的结果。一种技术——最多两三种——会成为主导。这种趋势揭示了一个事实——虽然竞争能够给用户带来好处,但是用户不会容忍不同技术间无休止的竞争(即使它们有互操作接口,无止境的异构并存也不能容忍)。有人认为竞争的优势体现于迫使厂商不断改进产品;我说这是竞争的初期目的,最终目的是让真正优秀的技术脱颖而出,最后获得胜利的技术必定充分走向公众领域(对于软件来说通常是标准化和开源),从而使后续的发展从竞争推动转变为协作推动。

这幅图还说明,如果一个领域的不同技术之间差异太大,无法做到自发收敛,业界就会选择另外的突破口。Plug-in和HTML/CSS即针对不同操作系统之间界面技术差异过大、中长期之内都无法收敛这个现状的突破口。替代品最初作为被替代品的高层封装,提供功能子集。如果低层接口差异过大、拒绝收敛,高层的替代品功能不断增强,最终会边缘化低层接口。另一方面,如果低层接口收敛的速度超过高层替代品功能增强的速度,高层替代品就会成为昙花一现的技术。例如,因为网络技术快速收敛于TCP/IP,CORBA的GIOP被更具体的和TCP/IP绑定的IIOP完全替代;CORBA本身也被更低层的socket接口替代。

因为操作系统界面技术始终差异过大,Flash才作为OS native的替代收敛途径出现。HTML/CSS作为Flash的替代并不是因为现实的plug-in技术无法收敛(事实是Flash仍然在plug-in领域占有绝对主导),而是因为Flash的私有实现性质导致人们对未来plug-in技术的发散存在恐惧。占主导地位私有技术标准被另一种技术夺取绝对主导地位的可能行大大高于一种公有技术标准。也许,面对HTML 5,Adobe最好的策略是更加开放Flash。作为商业公司,不能无限度的自动开放技术,但是当市场开始寻求替代标准的时候,最好不要心存侥幸。如果HTML 5真的替代了Flash,那时也许Adobe保存Flash这一技术财富的方式就只有推出自己的Web浏览器。如果提前做好准备并且幸运的采取了正确的策略,也许Adobe的浏览器在继承Flash的基础上还能取得一些竞争优势,但是那样付出的努力和代价,以及所冒的风险远远高于通过开放Flash保持其主导地位。