月度归档:2012年06月

『Linux/Unix设计思想』

X Window System的主要贡献者Mike Gancarz总结了Linux/Unix系统中9条设计准则,这9条准则在各Linux/Unix社区中被尊为金科玉律,谓之Unix哲学。

 一、小即是美

小程序易于理解和维护,占用系统资源少。最主要的一点是,小程序容易与其他工具相结合,而这一点通常是代码复用的前提。判断一个程序或者模块是不是足够小,有以下一些方法:

  • 传递给函数调用的参数数量过多,导致代码超出了屏幕的宽度。
  • 子程序代码的长度超过了整个屏幕或是一张A4纸的长度。
  • 要靠阅读代码注释才能记住子程序到底在做些什么。
  • 在开发程序的过程中,已经无法记起一个给定的错误信息是在什么条件下引发的。
  •  二、让每一个程序只做好一件事情

    这条准则实际上与上一条“小即是美”含义差不多,小程序往往功能单一,而单一功能的程序也往往很小。Gancarz认为,现在ls命令拥有20多个选项,越来越趋向臃肿,有背离Unix设计准则的趋势。

     三、尽快建立原型

    作者把人类能够创建的系统分成三类,并取了个十分朴素的名称:第一个系统,第二个系统,第三个系统。第一个系统往往是由个人或者小团队开发完成的,它只包含最简单最实用最令人兴奋的特性,体现了作者的创造力。例如SourceForge就有上大量的第一个系统。等第一个系统吸引了广泛的注意力之后,专家、委员会和形形色色的组织就开始介入,为了体现自己的价值,每个参与者都想确保自己对总体设计有一定的贡献,而不管自己是否具备该设计领域的专业知识,也不管系统是否真的需要这样的特性。因此,第二个系统往往臃肿而缓慢,它试图满足每个人的需要,到头来达不到任何人的要求。第三个系统是由那些被第二个系统所拖累的人所创建的,结合了第一个系统和第二个系统的最佳特性,该精简的精简,该舍弃的舍弃,最终在功能和性能之间达到完美平衡。作者认为,任何试图改变三个系统的顺序都是徒劳,最终所建立的不过是更多的第一系统和第二系统,而Linux/Unix目前的发展水平处在第二个系统和第三个系统之间。通过建立原型,构想才能首先通过可视化、现实可行的方法得到验证,建立原型的主旨就是创建第三个系统。

     四、舍高效率而取可移植性

    高效率和可移植性的取舍是个两难的问题,偏向高效率往往导致代码不可移植,而选择可移植性往往会让软件效率不尽如人意。Unix的设计哲学提倡舍高效率而取可移植性。硬件的升级水平满足摩尔定律,因此运行效率只是个暂时性的困扰,而只有具备了可移植性的软件才能在下一款计算机下一个平台中占得先机。这与『软件随想录』中的观点异曲同工:“从长远的观点来看,那些不关心效率、不关心程序是否臃肿、一个劲往软件中加入高级功能的程序员最终将拥有更好的产品”。具备可移植性的软件可以把更多花在兼容性上的时间用来开发软件新功能,并且还能减少因软件升级带来的用户培训成本。所以,人们在早期为可移植性付出的所有努力都会在后期得到丰厚的汇报。

     五、使用纯文本文件来存储数据

    无处可去的数据是死数据,数据只有流动起来,具备可移植性,才能体现价值。文本是通用的可转换格式,几乎所有的目标平台都能处理文本编码的数据。文本方式存储数据除了易于阅读和编辑,最大的优点还是可移植性,可移植性的优势已在第四条中说明。

     六、充分利用软件的杠杆效应

    良好的程序员编写优秀代码,优秀的程序员借用优秀代码。借用别人的成果,将他人的软件模块、程序和配置文件集成到自己的应用程序中,减少成本,从而使软件变得更有价值,就像使用杠杆,能够撬动另一端的月球。将来,那些能够迅速有效地裁剪和组合模块的开发人员才真正拥有“就业保障”,有了这种能力,开发人员往往能在很短的时间内写完很多软件,企业普遍认为这些员工才是无可替代的人。借用别人成果,避免重复发明轮子,这种观念就是开源软件运作的根本思想。

     七、使用shell脚本来提高杠杆效应和可移植性

    shell脚本可以提高杠杆效应和可移植性,它将每条命令都加载到内存执行,并且间接调用这些程序,管道机制确保shell脚本可以将命令统一起来构成一个强大的整体。由于shell脚本都是解释性语言,无需编译和连接,因此可以说他们拥有Linux/Unix环境下最高级别的可移植性。只要有可能,都应该编写shell脚本来替代C语言程序。

     八、避免强制性的用户界面(CUI)

    用户界面涉及交互,强制性的用户界面(CUI)在Windows系统下较为常见的是模态对话框。这条准则中提到的CUI还包括拥有自己的命令系统的应用软件,例如SFTP、Telnet等。实际上,图形用户界面只不过是CUI的可视化形式。这类程序运行后,在退出之前,用户都无法再与命令解释器进行交互。CUI无法有效利用管道机制,较难与其他项目结合,并且它们的解释器往往规模庞大且难以编写。对用户过于友好,使得CUI程序必须针对多种情况处理不同分支,代码量增多,不如采用Unix的运行参数方法简洁。

     九、让每一个程序都成为过滤器

    每个程序都以某种形式接收数据作为输入,并产生一些数据作为输出,输入和输出之间程序充当的就是过滤器的角色。它将数据从一种形式转换成另一种形式。

    --EOF--

    写在2012年欧洲杯荷兰队出局之后

    两天之前,荷兰1:2负于葡萄牙,以0胜3负的成绩止步小组赛,我没去考究这是否是荷兰史上最差的欧洲杯战绩。于我来说,2012年欧洲杯似乎结束了,对剩下的比赛提不起太多兴趣。

    开赛之前,大多人被荷兰队的前场配置惊艳到,德甲英超金靴自不必说,罗本、斯内德、范德法特也都是当今足坛的顶级球员,再加上南非世界杯和本次欧洲杯预选赛的优异成绩,荷兰被推到了夺冠大热门的队列里。赛前威廉希尔的赔率开到7.5,高居榜单第三名。问题在小组赛首场0:1爆冷输给丹麦后开始显露,人们发现,这支荷兰队的缺点太过突出,与前场豪华的人员配置相比,后场人员显得格外寒碜,竟然没有一名球员在传统意义上的豪门球会里踢球,不知道这是不是16支队伍中攻守最为失衡的球队,难怪有人调侃,刘洋在太空中看到的除了长城就是荷兰队后防的空档。而心浮气躁的前场人员也有没有了在各自俱乐部中的那些灵光一现,最终,荷兰队的第一场比赛给出了一份32脚轰门5脚打在球门范围之内0进球的答卷。第二场面对德国,荷兰人浑浑噩噩踢了70多分钟,在0:2落后的情况下由范佩西扳回一球,总算控制住了场面,但是前面浪费了太多,留下的时间已不足以从德国人手中拿下分数了。1:2,荷兰人选择了最差的结局来结束这场生死之战。之后,他们的命运已经掌握在了别人的手中,出线也只剩下理论上的可能。反观德国队在这场比赛中的表现,跑位、传切配合、战术犯规,换人调整,与跟其他对手的比赛并无二异,看得出来有所保留,不温不火地把3分拿了。背水一战的荷兰人在最后一场面对葡萄牙首发排出了类似505这样的奇葩阵型,效果还不错,开场10分钟由范德法特攻入一球,但此后葡萄牙人洞穿了荷兰队中前场没有防守能力的bug,犀利的防反彻底打穿了荷兰人的防线,加上C罗非常习惯这样的踢法,最后荷兰队只以1:2告负已属侥幸。需要辩解的是,这场比赛的场面不能体现两队在实力上的差距,起点不一样,目的不一样,荷兰需要净胜2球以上,所以后期祭出自残式的406阵型,不成功,便成仁,就是这样。

    足球世界的逻辑里无法预测胜负,但却可以总结成败的原因。荷兰队失败的原因,除了前面已经提到的防线短板之外,前场进攻效率也是一个重要因素。小组赛后统计数据显示,荷兰队的射门次数为60次,位居第三,威胁传球次数50次,并列第一,但是仅有2粒进球,转化率如此之低也属罕见。在整体足球的浪潮之下,荷兰人的英雄主义似乎有些过时。反观西班牙、意大利、德国和英格兰,大量招入某支俱乐部中的队员,巴萨、尤文、拜仁和利物浦成了国家队的半边天,球队主心骨就由这些俱乐部的队友构成,这样的好处就是国家队根本无需太多时间磨合。因此,那些慢热型的球队也就不再有市场了。

    传统强队中只有荷兰止步小组赛,按照往年的传统,舆论应该会掀起一阵缅怀无冕之王的声音,然而今年似乎有些不一样,更多的是责备的声音,责备这支荷兰队缺少血性,缺少准备,缺少诚意。黄健翔的总结有些道理:“荷兰足球,美的时候是神仙附体,神鬼难当;丑的时候是神经发作,神鬼难测。好像某些艺术家的风格,起伏大,感性,不稳定甚至神经质。好得近乎癫狂,差得歇斯底里。永远令人着迷,又常常令人揪心。”

    怀念范尼斯特鲁伊。

    --EOF--

    从FreeMarker模板获取插值(变量)名称的方法

    FreeMarker官方并没有提供从模板获取插值名称的API,据『FreeMarker Manual 2.3』上介绍,FreeMarker的设计初衷是为了分离业务逻辑和显示对象,业务对象不应该依赖于模板,所以官方干脆不提供从模板中获取插值名称的API。

    有时候系统实现中又需要用到这个功能,这篇『FreeMarker的模板标签获取』介绍了一种可行的办法,通过模板实例Template的getRootTreeNode()方法获得TemplateElement对象,遍历模板中各个模块,判断其是否是freemarker.core.DollarVariable类的实例。这种方法只能得到最简单形式的插值名称,它无法获取控制语句<# xxx></# xxx>命令内的插值,例如<#if var_exist??>${var_exist}</#if>中的var_exist就无法获取。

    遇到复杂的FreeMarker模板,要获取其中所有的插值名称,最好还是自己解析整个模板文件(ftl),在上文提到的已经获得TemplateElement对象的基础上,利用正则匹配中的分组功能,将插值名从各个模块中析取出来。

    示例代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    
    Template template= new Configuration().getTemplate(templatePath);
    TemplateElement templateElement = template.getRootTreeNode();
    for (Enumeration children = templateElement.children(); children.hasMoreElements();) {
        Object object = children.nextElement();
        String regex = "\\$\\{[0-9a-zA-Z-')(@_?!]+\\}"; //定义正则匹配规则。
        //合法的插值名(包含内建函数的用法)是以${开头,}结尾,
        //中间一个或多个0-9、a-z、A-Z、-')(@_?!等字符组成。
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(object.toString());//object为模板上待匹配的一个模块。
        while (matcher.find()) {
            String variable = matcher.group(0); //获取正则表达式中的分组。
            //group(0)表示匹配上的表达式本身。group(1)表示分组1,group(2)表示分组2,以此类推...
            System.out.println(variable);
            //输出示例:${var} ${var!''} ${var?default('null')} ${var_url?url('UTF-8')}等等。
        }
    }

    以上程序直到解析出${}为止,这里面还包含着一些内建函数名称等,实际上还不满足获得插值名称的需求,故还要进一步进行解析,比如滤去前缀${、后缀}、第一个!及其之后的内容、第一个?及其之后的内容等。

    --EOF--

    『天意』

    这是一部穿越型的历史科幻悬疑小说,下面开始剧透:

    人首蛇身的伏羲是地外生物,没见过海,有天坐着飞碟来到地球,把渤海湾平静的海面当做了陆地,哪知飞碟不防水,进水后坏掉了。当时的地球还处在远古时期,没有智慧没有科技没有文明,伏羲悲剧地发现回不去了。但是他有制造时光机的能力,于是他想到一个办法,想把飞碟降落的海域填平了,再控制时光倒转到飞碟降落的那天,从而从根本上改变目前尴尬的处境。

    要实现填海的目的,伏羲不得不将自己那个星球的科技和文明授予还未开化的地球人,教他们文字、算术、冶金、建筑等等,为了避免人们内耗太过严重,影响填海工程进展,他还发明了九鼎,九鼎不是鼎,而是一个监控工具,君王有了它以后就可以足不出户地扑灭各种可能引起暴乱的星星之火,从而减少维稳成本。同时伏羲还积极地寻找在地球的代理人,通过代理人出面发动群众填海。他连控制时间的能力都有,所以扶植代理人成为君王对他也是小菜一碟。伏羲找的第一个代理人是秦王嬴政,后来因为嬴政追求长生,贪念太重,被伏羲设计扰乱心智搞死了,第二个代理人选本是张良,但因为张良长得太清秀太柔美,在那个勇力至上的年代无法驾驭平民去填海,所以伏羲只好将目标锁定在了韩信,也就是『天意』中主人公,智勇双全、能屈能伸、仁义信诚,非常完美毫无缺陷的一个男人。韩信凭借伏羲的时光倒转能力在“明修栈道,暗度陈仓”这一历史事件中成功上位,到最后成为齐王和楚王。伏羲都准备让他取代刘邦了,哪知韩信太聪明,了解到伏羲的真实目的后,思维发散,开始想到了一个悖论:没有因,哪有果。假如帮伏羲把海填平了,当年他就不会飞碟进水,也就不会耐心地帮地球人发展科技和文明了。历史将改写,那不就等于毁灭了地球文明?想通了这一点后,韩信非但没发动群众去填海,还从伏羲那骗来几个火箭筒,把几千年来伏羲填海工程获得的阶段性成果给轰了。还让自己的红颜知己通过伏羲的时光机穿越到千年以后,著书立说(也就是『天意』),把伏羲的阴谋抖了出来,以醒世人。

    所以,在『天意』的世界观里,伏羲至今仍潜伏在渤海湾的某处,暗中扶持代理人,继续着他那苦逼的填海事业。至于伏羲为什么几千年来一根筋地填海想要穿越回飞碟进水的那一刻,而不是换个思路,穿越到启程前往地球的那一刻,那就不得而知了。

    --EOF--

    『摄影作品分析』

    多年来,人们欣赏摄影作品的角度发生过一次根本性转移。过去,人们注重拍摄制作技巧,而如今,人们更多地把注意力放在了作品的内涵,把对内涵深层次的追求当成了摄影的主要任务。荷赛奖中国选手的作品鲜有斩获,究其原因,乃是他们选送的作品太讲究技巧方面的完美,太讲究构图、光线和影调,而现实是不会那样完美的。摄影作品的意义本身是矛盾的,一方面,在快门按下时,当前空间和时间下的被摄对象就凝固了,瞬间变成永恒,这是一种以小见大的表达方式。另一方面,摄像机只能捕捉到被摄物体瞬时的状态,很显然这又是一种以偏概全的表达方式。表达方式的两面性需要摄影师去处理,消除局限性,最终体现在作品之中。

    作品分析,就是分析摄影师通过镜头语言在“说”什么、怎么“说”、“说”到何种程度。

    1. “说”什么。“说”什么是看摄影作品画面所揭示的主题,概括主题思想,读懂画面含义。

    2. 怎么“说”。怎么“说”是分析摄影师在作品成型过程中使用的各种表现技巧,例如,构图技巧、用色技巧、用光技巧及后期技巧等等方面。

    3. “说”到何种程度。作品成功的评判标准有以下几个维度:难易程度、创新程度、思想程度和美感程度,“说”到何种程度就是看作品在这四个维度上的分布。

    --EOF--