Mar 3, 2013 - 编程珠玑番外篇之番外篇-N 答 UNIX 痛恨者王垠

Comments

(标题是标题党)

王垠最近的一篇文章中,提出了很多有趣的观点。其中最核心的一点,就是 *NIX 系统的设计哲学非常糟糕,而 Windows 系统才是真正为开发者设计的系统。凡是涉及到哲学层面的争论,最后都是以谁也说服不了谁收场。我相信王垠有足够的理由来证明 UNIX 设计哲学的糟糕,但遗憾的是,他的文章并没有表现出这一点。我摘抄一些论点并作答复。

Unix 的 shell,命令,配置方式,图形界面,都是非常糟糕的。每一个新版本的 Ubuntu 都会在图形界面的设计上出现新的错误,让你感觉历史怎么会倒退。但是这只是表面现象。Linux 的图形界面(X window)在本质上几乎是不可治愈的恶疾。

以现在的眼光看,X Windows 是一个设计过于繁复的系统。实际上,20年前出版的 The Unix Haters Handbook 里,就有专门的一章论述为什么 X Window 的 client-server 架构是糟糕的。可是,这和 Ubuntu 的设计演化之间似乎没有太多关联。Ubuntu 所谓的图形界面设计的错误(以 unity 为例),都是桌面环境层面的问题。一个设计师在这个层面犯错误,就像一个画家因为构图不够工整就去怪画布不行一样,之间还相差不少逻辑链条。

X Window 和其他操作系统上的 GUI 系统最大的不同,是它和宿主操作系统的松耦合。因为这种松耦合的存在,在不需要图形界面的地方,操作系统可以不带 X Window。很多云服务的服务器,都是没有 X 的。当下如日中天的移动操作系统如 Android 和 iOS 都是 UNIX 家族操作系统,而这两者都没有用 X Window 提供 GUI 支撑,而是另外开发了一套专门适合触摸式移动设备的图形界面系统。图形系统和操作系统间的松耦合,使得操作系统可以从头搭建适合具体设备的图形界面交互(如 Cocoa Touch),并且快速的迭代(如 Project Butter)。

在 GUI 和内核的耦合关系上,架构的确决定了产品的形状。我们都知道,微软 NT 内核和 Widnows UI 系统是绑定在一起的。Windows Phone 8 要和 Windows 8 共享内核和其他组件的结果,就是它们都必须兼顾桌面和移动平台。为此,微软做出了两个可以做榔头也能做螺丝刀的东西。一个是 Windows 8,支持触摸屏,Modern UI 界面长得像手机界面;一个是 Windows Phone 8,界面很适合触摸设备,却又同时支持移植来的桌面程序,造成有的程序界面长得像桌面。无论你认为哪个操作系统的图形界面漂亮,哪条路更加有光明的未来,微软的这些系统之间的关系之繁复,开发迭代的周期如此之长,都是客观事实。

UNIX 系统的Unix 的 shell,命令,配置方式的确有不少的问题,在痛恨者手册里也有详细的论述,我以前也写过,就不一一列举了。

Unix 依靠自己的“宗教”和“哲学”,“战胜”了别的系统在设计上的先进,统治了程序员的世界。胜者为王,可是 Unix 其实是一个暴君,它不允许你批评它的错误。它利用其它程序员的舆论压力,让每一个系统设计上的错误,都被说成是用户自己的失误。其它系统里面某些优秀的系统设计,也许就要被历史掩埋……

一个操作系统,是不可能凭着“宗教”和“哲学”就能统治程序员的世界的。程序员不是天主教徒,UNIX 也不是程序员世界的教皇。实际上,所谓的 UNIX 系统,不是一个特定的系统,而是一个家族的系统。这个家族的系统包罗万象。不喜欢微内核的做了宏内核,不喜欢一切还不都是文件的做了 Plan 9, 不喜欢 X Window 慢如蜗牛的做了 XGL 加速。优秀的设计不断地加入这个系统,改造这个系统。UNIX 来源于 Bell 实验室,X Window 却是 MIT 的,BSD 来自于 Berkeley, Solaris 来自于 SUN, Mac OS 来自于 Apple。如果说这里面有宗教的话,这一定是世界上最诡异的宗教,里面的教徒还天天打架。

在 UNIX 系统中,所有的设计,都在开放的环境下竞争。我们可以说 UNIX 不是一个设计良好的系统,但是它的设计哲学在竞争中获胜的原因,不是因为它是“暴君”,控制了程序员的思想,而恰恰是因为它的开放,所以最终汇总了很多优秀的东西。至于 UNIX 这种不怎么好的系统为何最终获胜,20年前的一篇文章也讲得很清楚了。

因为 TeX 的语言是非常糟糕的设计。它的设计者几乎完全不明白程序语言设计的基本原则,不明白什么叫做“抽象”。

而这些源于 Unix 的工具却像是“魔鬼棋”或者“三国杀”,有太多的,无聊的,人造的规则。有些人鄙视图形界面,鄙视 IDE,鄙视含有垃圾回收的语言(比如 Java),鄙视一切“容易”的东西。他们却不知道,把自己沉浸在别人设计的繁复的规则中,是始终无法成为大师的。就像一个人,他有能力学会各种“魔鬼棋”的规则,却始终无法达到象棋大师的高度。

这里,王垠把两个不相关的东西放到了一起。一个是工具的设计哲学,一个是我们如何学习知识。魔鬼棋本身是一种工具设计哲学,和成为大师无关。

军刀工具一文中我提过,面向特定领域的软件工具之所以让人觉得复杂,是因为这个问题本身复杂。我们把解决特定领域问题而所需的知识叫做”领域模型“(domain model)。如果我们不了解领域模型,就不能理解为什么 Photoshop 比系统自带的 Paint 复杂几千倍, 或者为什么我们需要正则表达式这种诡异的东西。我们讲的复杂与简单,都是工具设计哲学层面的。

以王垠说的 TeX 为例。写出《计算机程序设计艺术》的 Knuth 到底知不知道程序语言设计的基本原则我们可以不加讨论。了解一点字体设计和排版的都知道,计算机排版问题是个复杂的问题。的确,软件工具的设计目标,是把复杂的问题简化。然而,大多数人不知道的是,简化问题是一个两步过程。第一步,我们需要把现实的问题映射到一个领域模型。第二步,是把这个模型简化到我们人可以处理的地步。很多时候这两步合并起来了,让我们觉得这两步好像是一步,并且认为所有的设计,都应该朝简化的方向走。这是一个对设计的错误认识。

举个非计算机领域的例子:用电饭锅煮饭非常简单,加米加水再按个按钮就行了。电饭锅的设计者的设计目标是操作简单且能完美地煮米。作为工具的设计者,它一方面需要了解大米是怎么煮熟的,另一方面需要提供给用户一个简单的按钮。TeX 作者,从一开始就不是设计一个电饭锅,而是一个精确的温控炉子。有了这个精确的温控炉子,想烧饭的可以把它封装成电饭锅,想做蛋糕的可以把它封装成蛋糕烤箱。设计电饭锅的人的设计,并不比设计精确的温控炉子的人好,或者差。设计者的初衷决定了产品的形状。 Kunth 的初衷,正是设计一个可以让他人排版出任何想排版的东西的系统。也就是说,做出一个最终非常简单的,只有一个按钮的排版系统不是他的设计目标。做出一个可以高度定制的系统才是他的目标。

其实,TeX 本身也是一个由繁到简的软件系统。它把所有排版中的问题,都提炼成了一些控制原语。有了这些控制原语,针对特定领域做优化就不是问题了。现在通用的科学出版排版工具 LaTeX, 正是这样的一种优化。这是有心设计的结果。我们抱怨 TeX 复杂,其实是抱怨排版本身复杂。Windows 系统上有许多排版软件,可以毫不客气地说,没有一个可以达到 TeX 所能到达的精确控制。以此责怪 UNIX 下的软件工具是魔鬼棋,就类似于责怪 Photoshop 为啥不象 Paint 那样简单一样,有选择性地忽视了两者所要解决地问题不一样。

我欢迎所有的 UNIX 使用者加入痛恨者阵营,因为我也是 UNIX 痛恨者。只有成为了 UNIX 痛恨者,你才是一个真正的 UNIX 使用者。至于 Windows, 我们对它没有感情,无所谓爱恨。

Oct 24, 2012 - 佛教艺术中的沙

Comments

  • “沙” 是佛教里很值得一提的物件,很多佛教艺术都和沙有关。

日本禅宗的“枯山水”就是一种依赖于沙的园林艺术。枯山水在西方很有名,以至于在西方直接被称为禅花园(Zen Garden)。一般的园林都会通过假山和水构景,通过人造的山和水,来引起观者自然的联想,从而联系人与自然。而枯山水园林却反其道而行,不采用真正的山,也不摆放真实的树,竹等物。枯山水中的水,是细细耙制的静态的白色砂石,模拟水的动态形态;枯山水中的植物也极少或者没有。这种美学上的差异,其实是和中日两国禅宗在修行上的侧重不同有关的。

中国禅宗传统上就是位于名山大川,因此在修行时秉承了一种自然主义的路线,让修行者在见山是山,见水是水的自然景观或者园林中修行。日本的禅宗主要继承了曹洞和临济两家。曹洞侧重于打坐和冥想,即“只管打坐”(Shikantaza)。临济强调”心即是佛”,也是促使人向内求索。在这种思想指导下,园林就不再坚持自然主义,而转为为修行着提供安心之法。枯山水正是这种哲学的体现。一个枯山水园林一旦建成,一年四季景色完全相同,恒久不变,宁静无碍。在枯山水中修行,心不会四处乱走。

枯山水是用静态景观来展现这个大千世界动态的一瞬间,而藏传佛教里的坛城沙画 (Sand Mandala),则是用动态的构建,来展现万事无常这个恒久不变的佛理。构建坛城沙画的目的,不是为了让它成为一项艺术品,而是为了最后摧毁它。这种最终什么也得不到的艺术创作,正是说明了佛教里一切无常的道理。

佛教的艺术家很早就意识到沙是彩色的。《大方广佛华严经》就提到过四条不同的大河流出不同颜色的细砂:“恒伽河口流出银沙,私陀河口流出金刚沙,信度河口流出金沙,缚刍河口流出琉璃沙”。结合华严经所说的恒河沙中的世界,用彩色的沙构建大千世界这种佛教艺术的出现是自然的。

为了构建坛城沙画,喇嘛们需要用尺子和圆规仔细的规划沙画的基本结构和几何形态。同时,所有的彩色沙都是仔细遴选甚至磨制而成。这些彩色的细沙被装入一个小口沙漏,然后由有经验的喇嘛,将这些细沙细细铺出。构建沙画是费时费力的,往往需要众多喇嘛们连续好天的工作。而不管花多少力气,多么美丽的沙画,只要沙盘倾覆,都一瞬间化为无形。从这个意义上来说,要揭示世事无常的道理,没有沙更加贴切的道具了。

坛城沙画

坛城沙画一旦建立,它的唯一命运就是被摧毁。高级别的喇嘛会先诵经一段,然后以一定的规则将沙画摧毁,将各色细沙汇作一堆,装入瓶中,撒入江河。就像熵只能增加一样,美丽的沙画的每一次破坏都是不可逆的。这种摧毁美丽艺术品的悲剧感和无力感,正是佛教想要说明的道理:诸行无常,是生灭法,生灭灭已,寂灭为乐。

佛经里对沙的数量,沙的色彩和沙的无常感都有论述。有趣的是,尽管大多数人认为“一花一世界,一沙一凡尘”出自于佛经,实际上佛经中从来没有明确的提出过这个论题。这个很有佛学意味的句子,实际上来自于英国诗人_William Blake_ 的《纯真预言》:

To see a world in a grain of sand,
And a heaven in a wild flower,
Hold infinity in the palm of your hand,
And eternity in an hour.</p>

May 22, 2012 - SpaceX 开创了人类航天的新纪元

Comments

今天,美国一家私人公司 SpaceX 成功的从美国佛罗里达州肯尼迪航天中心火箭的空军发射场发射了一颗火箭,这颗火箭的终点,是国际空间站(ISS)。这是继上次成功发射并回收卫星后,一家私人公司首次将载荷送到国际空间站附近。自美国的航天飞机退役后,能够将载荷运输到国际空间站的方法只有一个–俄罗斯的联盟号飞船。而现在,私人航空已经离这个目标不远了。

SpaceX 的成功是美国社会一直引以为豪的企业家精神和创新精神的成功。2002 年,eBay 以 15 亿美元的价格购买了 PayPal,一家从事电子支付的公司。很多 PayPal 的员工一夜之间成为亿万富翁、PayPal 的共同创始人 Elon Musk 极具冒险精神,眼看 PayPal 已近逐渐成熟,便在 2002 年 eBay 收购还没定型之前,马不停蹄的创立了一家叫做 SpaceX 的公司,致力于民用航天探索。

和 Jobs 用自己的钱投资 NeXT 和 Pixar 一样,Musk 将自己口袋里的 1亿美元投给了 SpaceX。当时,Musk 同时主持两家创业公司,一家是 SpaceX,从事空间探索,另一家是 TelsaMotor,从事电动汽车生产。这两家公司都不是传统的软件或互联网公司,因为空间探索和生产汽车的成本,无需多说,公司的烧钱的速度远远快于硅谷的其他创业公司。可以想象,这两家公司在发展过程中屡屡不绝的资金不足的问题。最后问题严重到需要 Musk 将自己口袋里仅存的 70 万美元拿出来发工资的地步,这在投资人遍地的硅谷是非常少见的事情。

如果换到其他创业者,到了这种地步,可能唯一的路就是缴械投降了。和 Steve Jobs 一样, Musk 的过人之处之一,就在他不但毫不畏惧风险,而且还能说服别人和他一起冒险。通过与 PayPal 一帮一夜暴富的富翁之间的关系,SpaceX 从一家创业基金拿到了一笔钱,暂时保证了公司不会关门大吉。同时,他加快了说服军方和NASA与 SpaceX 签订合同的谈判。2005 年,在 SpaceX 最紧要的关头,美国空军与 SpaceX 签下了价值一亿美元的发射合同。随后,2006年,NASA 与 SpaceX 又签订了价值10亿美元的向国际空间站运送补给的合同。这些合同带来的巨额项目投资,使SpaceX 终于摆脱了市场和资金的两大问题,成为民用航天的一家标杆,此后就是大家熟知的火箭发射,卫星回收等历史了。而 Musk 在 TeslaMotor 一侧的成功也非常耀眼。该公司是第一家量产锂电池汽车的公司,并在 2010 年成功上市。就像当年 Jobs 同时运营两家公司最后让 Pixar 上市一样。

SpaceX 用很少的钱,在极短的时间里完成了某些号称体制优越的国家举国都不能完成的事情(我说朝鲜呢,不许联想),最重要的当然是 Musk 的远见,无数的工程师杰出贡献。这里,美国政府和 NASA, 也起到了锦上添花的作用。美国政府不敢擅自夸耀自己,但公平的说,SpaceX 的成功离不开美国的航天政策调整。

美国政府在空间探索上的策略虽然一个总统一变,但因为 NASA 具有较大自主性,因此空间政策大体上还是很有政策的延续性的。因为航天飞机的退役日程,小布什政府一直在规划如何在航天飞机退役后继续维护国际空间站。当时小布什政府的设想是一箭双雕,既要国际空间站,又要重返月球。这样,NASA 就提交了一个双火箭的星座计划。因为该计划预算巨大,而美国政府又面对巨大的预算压力,因此联邦政府要求 NASA 同时也寻找其他替代方案,而 SpaceX 的火箭和龙舱,即在当时被  NASA 选中。

奥巴马政府的空间政策比小布什政府更有远见。因为预算问题,奥巴马政府取消了星座计划的登月部分。NASA 内部的一些专家早就预言过,现在已经不是冷战时期,美国公众根本不想和中国比赛登月。如果美国想再次登月,就要消减国际空间站。而且即使美国登月,中国不会因为美国再次登月了就放弃登月,所以美国和中国竞赛登月连政治意义都没有,美国就应该放弃登月。奥巴马政府采纳了这样的建议,让NASA跳过月球,除国际空间站外,把眼光放在 James Webb 太空望远镜等太阳系尺度的空间探索上。因为这样的政策调整,NASA 得以缓出人员和精力从事更加深度的空间探索,而将给国际空间站运输货物这样“技术含量较低”的项目,交给 SpaceX 这样的私人公司完成。NASA 和美国政府都不顾及所谓的面子问题,在航天飞机退役后,委托俄罗斯用联盟号飞船运送美国宇航员和货物。从短时间来看美国好像丢了人,而长时间来看,是省了NASA的预算,并给了 SpaceX 等私人航天巨大的成长空间(美国私人航天领域公司很多,不限于 SpaceX,SpaceX 是领跑者)。

按照 NASA 的计划,SpaceX 需要先将龙舱发射到国际空间站附近,伴随飞行。然后下一步设计出能够于国际空间站对接的龙舱,最终完成飞行,对接,分离的三步目标。随着 SpaceX 的成功发射,未来已经离我们不远,航天历史正在翻开新的一页。

 

Feb 2, 2012 - 编程珠玑番外篇 -M. 软件工具的设计哲学1

Comments

我们通过工具的设计者和使用者的视角观察工具,讨论工具背后的设计哲学和对应的学习曲线。

设计者和使用者

从某种意义上来说,工具是个联系使用者和设计者的桥梁。工具的设计者为解决一类问题而设计工具,工具的使用者也是为了解决一类问题而使用工具的。这两者对于工具都有自己的理解。工具的设计者通常会预测此工具会被用来解决怎样的问题,在设计工具时预见使用者的偏好,而工具的使用者则根据所面临的问题选择合适的工具。

在理想情况下,设计者和使用者对问题的理解 (Vision) 是类似或者重叠的。这时候,工具的设计者能够完全理解使用者的需求,而使用者完全理解这个工具的长处和短处。成语“得心应手”说的就是这样的一种情况:掌握了一样工具,因此使用起来非常顺利。

在现实中,设计者和使用者对问题的理解可能是有差异的,随之对工具的使用方法的理解也有所不同。有时候,工具的使用者能够将工具用到远超出设计者想象的地步。有两个著名的例子可以说明这个问题。第一个例子是出自 Bell 实验室的 AWK 语言。从 AWK 的三位作者的角度看,这是一个与 sed 互补的,处理文本记录的语言。而AWK在贝尔实验室内部推广开来后,三位作者发现其他团队用 AWK 来写作大的数据管理系统,而三位作者本人从来没有写过超过一百行的 AWK 脚本。第二个例子是 C++ 的模版 (template)。模版的设计者的初衷是让 C++ 在处理对象时更加灵活,而自从C++模版的图灵完全特性被发现后,写作一些通用的库成为可能。如C++的Boost库,即重度依赖于模版。设计模版的人未必想到 Boost 库那样对模版的奇妙运用。这两个例子,都充分说明了工具的设计者未必能够充分体验到自己设计的工具的强大之处。

另一种情况是工具的设计者是解决问题的专家,对问题有深刻的理解,而工具的使用者则没有能够完全体验到工具的强大。工具的使用者因此需要学习如何使用工具,学会像工具的设计者那样思考,从而领略到工具的强大之处,达到得心应手的地步。对于完成学校教育后的成人来说,大多数学习都是在学习工具的使用。那么,如何学习软件工具呢?

在我看来,虽然工具千差万别,学习工具的用法也大相径庭,不过如果细细总结,工具的设计者所奉行的套路无非就两种,所对应的学习方法也有两种。我把这两种设计讨论形象地称为瑞士军刀工具链。这两种设计哲学背后的假设,以及相应的学习曲线是不同的。

设计者的哲学一:瑞士军刀

瑞士军刀以方便著称,一把军刀包含了很多小部件,配合使用能够解决很多野外生存问题。不少计算机工具借用了这个类比。在Google 上搜索 “The swiss army knife of” 会发现很多软件工具号称某领域的瑞士军刀(见表一)

工具名称 用途领域 广告词
BusyBox 嵌入式 Linux 命令集 The Swiss Army Knife of Embedded Linux
Perian Apple QuickTime 组件管理 Perian – The swiss-army knife of QuickTime® components
Sox 音频文件编辑 The Swiss Army knife of sound processing programs
Netcat TCP/IP 数据包分析 TCP/IP Swiss Army Knife
FFMpeg 视频和视频流文件编/解码 The swiss army knife of Internet Streaming
Kanif 计算机集群管理 Cluster management and administration Swiss Army knife

从表一我们不难发现,这些宣称为“瑞士军刀”的工具有一个共同特点:都是针对某个特定领域的问题而设计的。这一点和瑞士军刀是相似的。瑞士军刀的多功能,并不是指这是一把砍树修桥盖房子的万能刀,而是说在野外生存这个领域内,军刀能够解决许多问题。回到表一,用过这些工具的读者一定有所体会:这些工具解决所在领域的复杂问题的能力是非常强的。比如,FFMpeg 内置多种视频编、解码器,众多格式能够相互转换,支持的视频编码格式比任何商业软件都要多。这些优势让 FFMpeg 几乎能解决所有现实中遇到的视频处理问题。因为这些工具针对特殊领域,且功能强大,用瑞士军刀做比喻是很形象的。

除了自称为“军刀”的这些工具外,还有许多耳熟能详的工具属于此类。如平面设计软件 Photoshop,是融许多复杂图像算法和插件于一体的图像处理之瑞士军刀;GNU 的 GCC 编译器,是集语法分析,代码优化,代码生成等功能于一体的专门负责程序编译的瑞士军刀。这些软件包的内部结构,都不是一个单一的程序,单一的部件,而是一揽子的部件,一箩筐的功能模块。

瑞士军刀巧妙地将众多小工具紧凑地组合到了一起。同样,我们说的军刀工具的一大优雅之处也是类似的,即通过一个统一的控制界面,将这一揽子的部件有机地组合在了一起。设计模式里,这种组织功能的方式称作为 Facade 模式,具体指以一个命令或者一个统一的界面抽象内部复杂的操作。如 FFMpeg 和 GCC 这样几乎无所不能的软件包,都可以通过一个单一的命令 (ffmpeg 或 gcc) 加不同的参数调用。在 GUI 程序的世界,所有的 Photoshop 插件都可以通过 Photoshop 的图形界面菜单调用。Facade 模式隔开了用户和“军刀”工具复杂的内部逻辑,让用户从一个”抽象”的层面理解工具。正如我们开车并不一定要了解引擎是怎么工作一样,工具的使用者不需要关系这些工具的内部是如何运转的。

总结这类工具的特点,瑞士军刀是一种把各种工具组合到一起,一起解决一个复杂问题的设计哲学。核心是。设计模式里的facet 模式,一个领域的问题,而不是一个特定的工具。这里实际上是一类工具,而非一个单独的工具。这一类工具被精巧地安排在一起,对外提供一个一致的服务接口,让用户以简单的控制方式完成相对复杂的任务。

领域知识假设和学习曲线

“瑞士军刀“工具都是面向特定领域的。无论是图片,视频处理,还是查看TCP包信息,这些工具都假设了使用者知道图片处理,视频处理或者TCP包的结构等知识。心理学上把这些为了解决特定领域问题而所需的知识叫做”领域模型“(domain model)。工具的设计者是不负责教授这些知识的。因此,作为工具的使用者,掌握这些特定领域的知识就成了使用工具的前提。一般的软件都是基于领域模型的。比如,平面图形处理工具 Photoshop 假设图片是个多层次的物体,如果我们不了解这个模型,就完全不知道为啥这个软件为啥比系统自带的 Paint 复杂几千倍。

因为军刀背后蕴含着领域知识假设,学习军刀工具就不仅仅是学习工具的使用本身,而是学习背后的领域知识。如果不了解背后的领域知识,即使我们会操作这样工具,依然谈不上是个熟练的使用者。相信诸位读者都属于“懂计算机”的一类人。现实中,我们这类人常常因为“懂计算机”,而被家人和朋友要求编辑图像,做个视频或者做个网页等等。有些要求还特别专业,让只会写程序的人非常吃力。究其原因,是因为程序员群体掌握的,只是编程的领域知识。如图像,视频处理所需要的领域知识,均是编程之外的了。即使像 Eclipse 这样专门给程序员用的软件,也隐含假设了使用者需要重构,设计模式等等的知识。不掌握这些知识的程序员用 Eclipse 也仅仅是将其当成一个花哨的编辑器使用而已。

因为需要领域知识做铺垫,军刀工具的学习曲线是因人而异的。对于有的人来说,如果本来就知道工具背后的假设,学习计算机操作就毫不费力。以我爸爸为例,本身用计算机并不熟练,但他学过画画,作图感一流,若干年前从书店随便买了一本 Photoshop 入门后就把 Photoshop 玩得很熟。而我知道这个软件每个选项的意义,却处理不出什么像样的图。对于我爸来说,他的学习曲线就很平缓,而对于我来说,就很陡峭。

学习曲线不一样这一点在计算机语言的学习上尤为明显(计算机语言是众多编程特性的大糅合,是典型的军刀设计)。像 Google 这样的公司面试时完全不考察语言细节,很多人入职的时候都不会 Java。因为我们相信任何合格的程序员都能很快学会 Java 这个语言。道理很简单,只要考察一个人掌握了Java 语言背后的领域知识,即面向对象的设计,数据结构,控制结构等等,就有充分理由相信这个人学 Java 毫不费力。但是,话说回来,每个语言背后的领域假设都有细微的差别。比如 Lua 只支持哈希表,Awk 支持哈希表也支持记录处理,Vim 里一切都是文本对象等等。真的领会这些领域模型并且将这些语言用得纯熟,没有长时间的投入是不可能的,这就是为何 Peter Norvig 强调“十年学会程序设计”。这两种对待编程语言的态度是不矛盾的。引申出来,对于语言或者工具的初学者来说,要分情况学习军刀工具。在不熟悉领域知识的情况下,应该找一本非常简单的书熟悉领域模型,获得一个 Big picture,而非上来就想着要解决手头的问题。而对于已经熟悉领域模型的人,比如会了一个 MVC 框架再学另一个的人,随便捡起一本 In Action 或者 Cookbook 也能事半功倍;有人甚至书都不需要买,看看文档就可以了。不清楚内情的可能会把这类人叫做强人,其实了解了背后的底细后,所有人都可以如此。

最后谈一下军刀工具的设计策略。我们说了,军刀工具背后蕴含的是领域知识。因此,设计军刀工具的人,必然需要是对问题有深刻理解的领域专家。这一点很好理解,因为很难想象一个不懂图像处理的人会指导 Photoshop 的设计,或者一个不懂统计的人会设计 R。不过,即使是最资深的专家,也未必能设计出一个能覆盖到所有问题的工具。这时候,工具的扩展性就成了一个重要的考量。可以这么说,几乎所有成熟的军刀工具,最后一定会进化出一个插件系统,用以扩展功能。插件系统的好与坏是考验设计者功力的时候。像 Firefox 和 Photoshop 这样的工具,若不是第三方插件,至多是一个普通的软件。加入插件系统后,这些工具成为了一个平台,从而衍生出了无数的新用例。即使像功能小巧和 Emacs 格格不入的 Vim, 最终也进化出了插件系统。这是一样工具成熟的体现。

总结一下军刀工具的特点如下:

  •  面向特定领域,覆盖该领域大部分问题
  • 由领域专家设计,使用者需要了解该领域的基本知识才能熟练运用工具
  • 内部由众多小模块组成,对外提供一致,简单的控制界面
  • 常常具有强大的插件系统,以方便用户扩展现有系统

Nov 24, 2011 - 编程珠玑番外篇 -L. Plan 9 管道工的启发

Comments

Smalltalk 作者 Alan Kay 曾说过,对象不是 Smalltalk 的本质,对象间的消息传递才是。对于操作系统中的基本对象–进程,类似的说法也是成立的:进程不是操作系统的本质,进程间的通信才是。像 Mach 这样的微内核操作系统的全部,就是一个供进程传递消息的框架。

进程间通信的技术细节繁杂,以Linux 系统为例,就有文件,管道,消息队列,信号量,RPC,UNIX Socket, RPC 等等多种方式。Windows 系统还有邮件槽, COM 对象等等。Mac OS 则有 AppleEvent 等等。在这里我们介绍 Plan 9 系统中一个不太为人所知的 IPC 机制:Plumber,或者叫做管道工。我在”开发人员为何应该使用 Mac OS X 兼 OS X 小史“中曾赞扬过 Mac OS X 系统中的 AppleEvent 进程间通信机制对工作效率的提升。和AppleEvent 类似,管道工也是对图形界面下进程间通信的一个尝试,不过在通信的粒度上有所区别。

我们从一个简单的例子入手。在如今网络普及的时代,几乎所有的软件都能自动识别链接。只要打入 http:// 开头的一串字符,就立即转化为一个可点击的链接,点击这个链接则自动召唤出浏览器。我们对此毫不感到新鲜,因为这功能再自然不过。其实这些功能在上世纪90年代还是很少见的。 Plan 9 的管道工,在当时就前瞻地提出一套匹配字符串和自动投递给指定应用程序的机制。我们只需要告诉管道工,用户选中字符串匹配某类型的时候就交由某应用程序处理,管道工即负责具体的程序间的通信。这是对 UNIX 管道机制的一个革新。如我在Mac OS 一文中所说,纯粹的管道机制在图形界面程序中已经不再适用了。

我们所熟悉的URI 处理仅限于浏览器,且只能处理由 RFC 2396 预先定义的 URI 模式。即便如此,我们也能体会到 URI 处理器的方便。像大家熟悉的电驴链接实际上是 ed2k:// 打头的 URI。在浏览器点击后就自动用电骡打开;苹果的 iTunes 的链接实际上是 itms: 打头的 URI;Android 商店的链接其实是 market:// 打头的 URI 等等,都是让用户更加方便的例子。有了这些机制后,我们难以想象没有这些机制而需要拷贝粘贴的日子是如何度过的。

管道工是 URI 处理器的推广形式。在管道工里,不仅仅是 URI,一切的字符串都可能匹配。因为读者可能没有用过管道工,我们仍然以大家熟悉的例子来说明。安装了 Skype 浏览器的插件会自动把网页上的电话号码变成一个特殊的“用 Skype 拨打该电话”的按钮,在 Gmail 里开启一些插件后 FedEx 和 UPS 的包裹号码能自动变成链接直接转到包裹查询网站等等。管道工的功能,就是让我们可以很方便的自定义这些转发功能,而不依赖于应用程序的实现。在 Plan 9 系统中,即使你不装 Skype, 不用 Gmail, 用户依然能够通过制定正则表达式匹配规则,来决定如何处理电话号码和包裹追踪号码等等。

管道工的原作者用编译器和编辑器的例子来说明管道工的作用。我们知道编译器报错语法错的时候,会以一定格式报出发生错误的文件和行号,如

Line 43: Hello.cc syntax error.

我们可以设定规则,在用户点击这些错误信息的时候,让管道工自动匹配和提取文件名,行号,并自动发给编辑器,就省却了我们人工打开编辑器跳到某行这个繁琐的步骤。尽管 IDE 已经通过集成编辑器和编译器的方式绕开了这种进程间通信,这种匹配/转发的通信方式仍然用在不少地方。比如 Vim 就引入了一个叫 errorformat (错误格式)的机制,让编辑器能够理解和匹配“错误格式”,并跳到指定的行。

通过 Plan 9 from user space 这个开源实现,我们可以在 Mac 和 Linux 上使用管道工。不过我们已经有了很多现成的工具能够部分实现管道工的功能。因为我日常只用浏览器和shell,因此简略介绍一下我是如何在浏览器和shell中实现类似于管道工的功能的。

用油猴子或者其他浏览器插件,我们可以将网页中某特定的字符串转变成一个定制的链接。然后,取决于所在平台,我们可以将这些链接和预定义的应用程序挂钩。Mac 下一个好用的工具是 RCDefaultApp ,Linux/Gnome 下的 gconftool-2 也直接支持对 URL-handler 的修改。Windows 下的方法则是修改注册表。(当然这些方法都有安全隐患,所以只适合个人使用)。

在终端里,对于 Linux 用户,urxvt 这个终端非常强大,可以使用 perl 扩展来匹配和执行命令,基本上可以完全实现管道工的这种匹配任意字符串且发送给其他程序的功能。在 Mac OS X 中,iTerm 2 是程序员应该用的终端。该终端目前还没有 urxvt 的强大扩展性,不过也能完成大部分匹配任务。比如说,iTerms 的最新版本支持一个叫做 Sementic History 的功能 (Preference -> Profile -> Advanced)。这个功能使得我们可以直接点击 Terminal 里面的文件名召唤出 Finder。用苹果的可能都知道 Mac 里有个 Proxy Icon (应用程序标题栏里面的小图标)的概念,我们可以直接把这个小图标当成文件的代表,拖来拖去,甚至可以直接拖到 Gmail 中当附件。我们其实可以把 iTerms 2 里面的文件名直接当成一个对象拖来拖去。

因为我日常只使用浏览器和终端,Plan 9 的管道工给我的启发是,如果有一套好的进程间通信机制,拷贝粘贴是完全没有必要的。如果你和我一样基本不用鼠标,并且认为拷贝粘贴是一个降低工作效率的事情,那么我建议你尝试一下用管道工的思想去改善你的工作流,看看哪些拷贝粘贴是可以由计算机完成的。