Posts Mentioning RSS Toggle Comment Threads | Keyboard Shortcuts

  • tin 2:50 pm on December 11, 2009 Permalink | Reply
    Tags: language, meta programming, method_missing, ,   

    Python中的method_missing和*get*钩子方法族 

    刚才实验了一下,发现Python里面声明类的时候是否选择继承objects还是有很大区别的。只有继承了objects,才可以使用钩子方法如’__get__’, ‘__set__’, ‘__getattr__’, ‘__getattribute__’这些方法。也就是说这些有用的钩子方法是所谓的new object里面的东西。今天我在项目的代码里面尝试了一下类似Ruby method_missing的写法,实验在Python里面加点元编程的东西。发现很相似的三个方法’__get__’, ‘__getattr__’, ‘__getattribute__’方法区别挺大。注意,一定要继承object才可以享用三个钩子方法。

    • 访问对象方法的时候首先会访问’__getattribute__’,它是访问类里面所有属性的时候都要经过的方法,包括创建对象的时候访问’__init__’, ‘_meta’这些都回经过’__getattribute__’访问。如果你什么异常都不抛出,它就不会访问’__getattr__’方法。
    • 如果’__getattribute__’方法抛出’AttributeError’,那么会继续尝试访问’__getattr__’方法。再有异常抛出,那么这个类就没有钩子再接住异常了。所以从这个角度来说它的工作方式非常相似于Ruby的method_missing。
    • 我本以为’__getattr__’是系统内建函数hasattr(object, property)优先访问的方法。不过实验证明,实际上还是先走’__getattribute__’后走’__getattr__’的。也就是说hasattr这样的函数没有优先绑定’__getattr__’。
    • ‘__get__’方法是用来监视自己的类作为其它类的成员的时候被访问的钩子。对应的是’__set__’,是相应属性被赋值时的钩子。这个方法与’__getattr__’和’__getattribute__’完全不是一会儿事。刚才看《Python核心编程一书》完全没有解释清楚。《How-To Guide for Descriptors》这篇文章对解释’__get__’帮助很大,有兴趣可以看看,不过我倒是没有想到什么是合理的应用场合。

    我目前还没有调用方法的method_missing,目前只是访问一些属性。我们实际处理的是一个可以直接用属性名读取/修改对象里面的持久化json属性的方法,就是类持有一个{‘property’: ‘value’}的json文本属性,我们就可以直接用Model.property访问和修改里面的方法,而不用特别的去生命json结构过来。是一个在Python中做meta programming的尝试。

    测试刚才说的几个*get*方法的测试如下:

    # -*- coding: utf8 -*-
    import unittest
    
    class A(object):
        def __init__(self):
            print 'init A'
    
        def __get__(self, *args):
            print '__get__ A', args
    
        def __set__(self, *args):
            print '__set__ A', args
    
    class B(object):
        a = A()
    
        def __init__(self):
            print 'init B'
    
        def __getattr__(self, *args):
            print '__getattr__ B', args
    
        def __getattribute__(self, *args):
            print '__getattribute__ B', args
            raise AttributeError
    
        def __get__(self, *args):
            print '__get__ B', args
    
        def __set__(self, *args):
            print '__set__ B', args
    
    class MeTest(unittest.TestCase):
        def test_simple(self):
            b = B()
            print b.a
            b.a = A()
            b.c
            hasattr(b, 'e')
    
     
  • tin 12:53 am on November 5, 2009 Permalink | Reply
    Tags: great firewall, , , , script   

    在Mac下使用脚本重载proxy自动配置脚本(pac) 

    Mac下对网络设备使用proxy自动配置脚本可以透明使用代理穿墙(可以配合ssh tunnel和tor)。但是我一直不知道如何用脚本让系统重新载入pac文件(在更新了pac的规则时我们需要重载配置)。昨天一位叫做Dylan的网友留言告诉了我如何做,我在此记录一下。在命令行下面:

    networksetup listallnetworkservices

    然后会会返回一个网络连接服务的列表:


    An asterisk (*) denotes that a network service is disabled.
    Bluetooth DUN
    ADSL
    Ethernet
    FireWire
    AirPort
    Bluetooth PAN

    我一般需要配置pac文件的是Ethernet和AirPort,那么相应的重载命令是:


    sudo networksetup -setautoproxystate 'AirPort' off
    sudo networksetup -setautoproxyurl 'AirPort' 'file://localhost/Users/tin/pac/tin.pac'
    sudo networksetup -setautoproxystate 'AirPort' on
    sudo networksetup -setautoproxystate 'Ethernet' off
    sudo networksetup -setautoproxyurl 'Ethernet' 'file://localhost/Users/tin/pac/tin.pac'
    sudo networksetup -setautoproxystate 'Ethernet' on

    然后pac文件就已经被重载完毕啦!在此感谢Dylan。

    顺便共享一下我在bash下的alias:


    alias px='ssh -qTfnNC -D 7777 tin@zztin.com'
    alias rpx="sudo networksetup -setautoproxystate 'AirPort' off;sudo networksetup -setautoproxyurl 'AirPort' 'file://localhost/Users/tin/pac/tin .pac';sudo networksetup -setautoproxystate 'AirPort' on;sudo networksetup -setautoproxystate 'Ethernet' off;sudo networksetup -setautoproxyurl 'Ethernet' 'file://localhost/Users/tin/pac/tin.pac';sudo networksetup -setautoproxystate 'Ethernet' on"

     
    • Dylan 3:25 am on November 5, 2009 Permalink

      比较奇怪的是safari不能通过proxy查询dns,现在只好用ff+foxproxy.
      不知有什么诡异的设定能搞定safari吗?

    • xyb 3:38 am on November 5, 2009 Permalink

      用privoxy把socks代理转变为http代理,浏览器就可以使用代理做dns查询了。

    • redoasis 9:27 am on January 3, 2010 Permalink

      博主能否提供一个编译好的for mac osX 10.6.2的privoxy,我去下载,似乎都只有源码,编译这种事情对我等菜鸟来说,难度太高,搞不定。要是有空的话,打包个有图形界面的app那就太完美了。谢谢。另外,pac文件我写来写去都不能工作,博主能提供一个在mac osx 10.6 下可用的pac文件范本么?

  • tin 1:24 am on November 4, 2009 Permalink | Reply
    Tags: DDD, , Refactory, , 重构, 领域模型   

    DDD重构初步 

    所做的系统是一个连接到外部信息发送和搜索引擎调用服务的Web前端系统。系统与外部的接口使用的是一层Service外观进行包装,原先的设计目的是使用服务层剥离对外部系统的强依赖──解耦,同时还希望使用Service将系统的商业逻辑集中存放──提高复用的可能。但是实际上我们发现Service这样的抽取方法并没有提高代码的复用度,反而造成数据结构和其算法的大量重复。经过分析,发现由于使用了大量的Hash结构存放接口间的返回结果,造成数据与其Service内部的行为分离,传递后商业逻辑就出现了重复(这样的结果是引入大量Quick but dirty的解决方案所欠下的技术债造成的)。所以我和我的Pair绝对对其进行DDD(领域模型驱动设计)的重构。

    领域模型驱动设计和面向对象设计在代码的抽象上很相似,它们都推荐让数据结构(状态)与商业逻辑(行为)统一管理。这样数据的状态与行为就不会分离,这样可以很大的减少由于商业逻辑分散造成的代码重复。这可以让我们实现我们非常重视的DRY(Don’t repeat yourself)。
    一开始我们尝试的是找到重复的商业逻辑和其对应的数据结构,然后尝试让它们映射到我们的领域模型。这样的效果还不错,但是经过了一天的工作,我们发现我们对领域模型的理解有问题,我们居然抽取出了重复的领域模型类。这个时候暴露的问题是我们对系统的领域模型没有统一和深入的认识。

    所以下一步我们计划进行领域模型语言的讨论会,目的就是使用自己的“领域语言”描述系统的所有行为,从这样的领域故事中找到我们的领域模型(领域概念模型,不是具体编程的时候的类)。

    领域模型讨论会最好由最熟悉领域模型的人起草,可以由这个人把它写在白板上。领域的故事最好能够涵盖系统的主要行为,描述要使用简练的语言。一般来说IT系统的内部行为可能很复杂,但是到了领域高度还是可以用比较简单的语言描述的,如果遇到一块白板不够的话最好首先考虑提高观察的高度,让领域的描述简练一些,其次再考虑扩展到第二块白板。在这个过程中我们要注意消除歧义,比如同样一个“术语”在两个功能区域中出现,那我们就要妥善的给他们各自取一个容易区分的“领域术语”作为名字。还有就是我们应该在写领域故事的时候考虑领域模型(或者理解为系统模块的抽象)之间的交互关系,最好在写领域故事的时候对行为的归属(它会指导行为到底会被建模在哪个领域模型中,可以体现为类的调用关系,哪个类持有交互逻辑)达成共识,这个时候达成的共识比在做具体的OO设计时候分辨商业逻辑归属要更体现商业价值。完成领域故事后我们要找到其中的所有领域模型(也就是前面说的领域对象和领域中的术语)。然后团队最好一起通读这个用户故事,一起讨论是否通顺(行为是否完备,抽象是否合理),是否有遗漏(遗失的领域模型或行为)。对于有外部系统的情况下,即使外部系统是面向消息的(或者说是没有使用领域模型驱动的SOA接口),那么团队最好对消息的内容有一个讨论,对其中设计到本系统和外不系统的领域模型进行认领,然后使用一个适配器来保证数据到达系统后就使用领域模型表示,外不系统的数据(一般没有行为)最好也使用一个领域模型进行约定。

    完成了上面这一步后,DDD最重要的一部分就完成了,它可以实现系统领域模型自顶向下的“名正言顺”,减少在自底向上的重构过程中产生的大量重复领域模型。下面的重构过程就是给领域模型写测试,使用TDD(或者也可以用BDD的方式提早对行为做验收测试,用它们来驱动对领域模型的实现,其实对领域模型的TDD和BDD是殊路同归)的方式逐一实现领域模型。而后争取给系统写一些验收测试或者高级别的集成测试,再逐一替换这些领域模型。这样就达到了DDD重构的效果。

     
  • tin 1:33 am on October 20, 2009 Permalink | Reply  

    可测试性驱动开发还不是“测试驱动开发” 

    看完老赵精彩的两篇“可测试性驱动开发(上)”“可测试性驱动开发(下)”

    写了篇回复

    老赵,我觉得你说的“可测试性驱动开发”和“测试驱动开发”的结果是非常接近的,可是实际观察下来我觉得不是一样的。我觉得测试驱动开发的一个好处就是从外界向内部逐渐迫近,逐渐的暴露的你意图。意图其实是更接近你的商业流程和商业价值的。所以更接近与“意图驱动开发”。因为TDD鼓励从系统的外部行为向内部行为逐步细化,逐步测试-通过,循环。这样产生的结果就是方法小,方法名考究,高层的代码非常容易读懂(经常达到看起来就像文档)。

    可是在“可测试性驱动开发”中,我觉得随时考虑的还是“可测试性”,但是“可测试性”本身与商业价值无关。所以驱动开发的东西就转变为程序员自己的一些“修养”问题了,你可能会倾向于使用模式来解决一些微观问题,让代码具有“可测试性”。这种做法可以产生组织良好的代码,它对于程序员来说易读(容易理解算法细节),但是这样的代码在被维护更久以后容易产生与商业价值的偏离。还有就是“测试性驱动”的经济问题,如果一个测试是纯技术意图驱动的,那么就是追本逐末了。

    测试驱动开发中的ATDD(验收测试驱动开发)鼓励你将系统的流程Spec在实现前写出来作为驱动,而BDD则从微观行为上将你的领域模型的行为Spec写出来驱动,这两种方式我想才是经典TDD的“新外衣”,因为他们都继承了“意图驱动”并进化为“商业意图(价值)驱动”。

    此文甚好,只是我觉得上面问题是个关键,”目标“最好还是在产生”策略“之前找到比较好,所以才写这个评论,冒犯了 ^___^

     
  • tin 4:10 pm on September 30, 2009 Permalink | Reply  

    程序员的点滴回忆 

    在ThoughtWorks就要两年了,相比进来之前的自己,现在做事可以抱有更低调的态度了。因为当你和众多聪明的人做事情的时候,你不得不谦虚,逐渐的你就会形成“开放性格”,这是我从ThoughtWorks收获的最有价值的东西。

    今天反思一下自己在开发中遇到的一些问题和TW的答案(只是一个Check list,没有逻辑顺序),有如下地方需要考虑:

    1. 做一个需求(对于我们指User Story或Tech Task)的时候要做好评估。评估一般都不准,因为预测本身就不容易准确。有几个方法帮助你让它变得准确,最重要的就是在你工作的团队里面计算Velocity,通过不断的评估Story point(实施工作量的一个概要评估,可以使用1、2、4、8、16这样的大概数字,和人天没有关系)记录实际完成时间,两者相除则为Velocity。有了Velocity就可以作为之后该团队评估需求实现所需时间的参考。Story point使用民主投票的方式,民主要做好就要保护好“异见”,任何高估和低估的情况都要平等的讨论清楚,并达成一致。
      上面说的方法在某个需求有未知技术点的时候会产生严重的评估偏差,甚至完全无法评估。此时一般使用的方法是Spike。Spike的做法是从技术可行性着手,多参考网上的资料和现成代码,使用Quick and Dirty的方式让他们工作,并且在这个过程中评经验得出实现它大概付出的代价,帮助你正确评估一个需求。Spike要尽量覆盖自己所有拿不准的技术点,不要深度,但是要有足够的广度。Spike代码可以不写测试,但是推荐使用测试的方式去实验(因为它更容易组织)。Spike代码一样需要使用源代码控制,并且要多做提交。最后,最重要的一点是Spike代码永远不要进入production code base。李晓曾经说理想的Spike方式是做一个基本满足需求的Spike原型,然后抛弃,重新用TDD的方式实现相同的需求,保证进入code base的代码都是TDD出来(或者起码是有测试保证)的。
    2. 关于些代码是否要测试的问题,Kent beck说我只给会被Break的逻辑写测试。但是实际上不仅如此,在Kent beck总结出的TDD中,测试还是用来明确你的“意图”的代码。做事要有明确的“意图”,一方面它保证你不会迷失目标,另一方面它也是你和你的代码还有你的同事沟通(还包括你自己)的重要手段。但是这里有一个容易让人迷惑的事情,TDD出来的测试到底是测试分类(单元、集成、验收)中的哪一种呢?同事们的答案是它们没有直接关系。TDD是可以表达你对代码行为/结果“期望”的任何一种测试,当然你要尽量保证你的测试是更靠下面的测试(单元测试),因为底层的测试运行快依赖少,所以保证你的红-绿节奏更快。冤有头债有主,每个测试表明一个“意图”,几个“意图”对应一个需求,一个需求对应一些商业价值。如此的映射帮助你从代码的“意图”到“价值”打通经脉。
    3. 一般说User story以“As someone, I want to do something, Then I can achieve some business goal”的形式书写。一般说与之对应的验收条件以“Given some context,When something happened, Then you got the result”的方式去组织,这种书写方式可以保证你的验收条件被映射到一些Specs上面,一些逻辑相关的Specs就组成了对一个Feature的验证。如果你用这种方式组织你的测试,那么你就自然的实践了BDD。BDD是一个很大的概念,组只好测试只是个开始。Ruby里面的Cucumber是一个很好的验收测试工具,它能帮助你更好的从你使用需求及验收特性Driven你的测试,书写有价值的代码。而Rspec这样的BDD测试框架则可以帮助对你的其它测试(如单元测试)进行管理。这些都是形式,但是形式影响你思考的方式,最终可以帮助你提升的代码的“价值”量,减少“无价值”的代码。
    4. 如果你是一个测试驱动狂人,你是否要考虑试验ATDD(验收测试驱动)呢?我们认为ATDD是TDD的一个极致形式(因为它最大程度保证你的商业意图和代码的有效映射)。但是这里还是有很高的门槛。一个是ATDD的难度的确比其它层次的TDD要高,很多时候你都苦恼于不知道如何做Assertion,这种问题会影响效率。因为测试代码本身是没有商业价值的。另一方面即使你是脑力超人,可以很好的写出验收测试级别的测试代码作为驱动,这些代码运行的速度一般也比较令人失望。因为根据测试分组(Category)的理论,越在上层的测试运行速度越慢。所以,如果你用验收测试作为高层驱动可能会拖慢红-绿节奏。这时你需要清除的知道要向下面层次的TDD进行委托,保证节奏效率的同时还能清晰的让自己的测试回溯到“商业价值”上面。
    5. 保持一致的标准。有的时候你会说我们的Code base不允许Quick and Dirty代码的污染,有的时候你又说我们的首要任务是让它Work。Teck lead此时要保证好统一的标准,找到自己团队能够接受的合理平衡。
    6. 站立会议一定要短,昨天作了啥,有什么问题,今天准备做啥这个形式如果哪个方面与团队没什么关系就可以省略。站立会议不是报功会,所以不要说你Fix的bug的编号是什么,那个完全没有价值。
    7. 回顾会议非常重要,如果大家都觉得需要回顾会议的时候就开。时间可以是几个小时一次也可以是几个星期一次。常用的Theme是“Well/Less well/Puzzle”,回顾会议需要Time box,一般半小时以内比较好。长时间跨度的回顾可是使用Timeline的Theme,就是大家不根据资料回忆一个时间段内发生的印象深刻的事情(团队和项目相关的)和记忆中他们发生的时间,然后大家讨论这个事情产生的正向/负向的效果,因为记忆会“骗人”,所以收集到的记忆的偏差实际上都可以和当时团队的情绪变化产生映射(类似精神分析法,可以帮助团队找到很多有意思的东西)。回顾产生的偏差是个很有趣的话题,这是为什么我们办公室有大量的精神病和精神分析相关书籍的原因。其它的Theme还包括Future retrospective,就是回顾“没有发生的未来”的回顾会议,使用“Well/Less well/Puzzle”作为容器,收集你想要得到的和希望避免的事情。出了这些基本形式,我们的Bonna还发明过大字报方式(就是搜集Headline hot news,bad news,流言八卦),用来收集各种客观消息并且集体对齐进行评估。Star fish也是一个Theme,不过因为大家总是忘记它的缩写是什么意思,用的比较少。回顾会议的主持人非常重要!还有回顾会议归档以后所有Action item都需要有负责人,并且要定期验证结果。
    8. 结对的时候两个人产生分歧是正常的,争论也是好的。不过不要争论太久(如超过15分钟)。久的争论大部分的原因就是互相没有聆听,产生了共同障碍。此时解决方法就是暂停争论,按照听起来比较短的路径前行一段实验一下,然后再讨论。此时一般会发现殊路同归,或者发现死胡同以后可以早点掉头。
    9. 只结对解决重点问题和难点问题是可以的,但是大部分的问题是你根本不知道哪里是“难点”和“重点”。所以资源和体力允许的时候尽量结对解决问题。
    10. 评价一段代码的好坏:首先看是否容易读懂,意图是否明确。这个要求需要你无惊讶的设计(使用模式、精心的设计)还有make sense的方法/变量命名。其次代码/方法要短,代码短是硬道理。然后是是否有代码重复。都达到了以后再看效率等问题(效率关键场合除外,但是这种场合很少)。
    11. 做事要尽量自动化,DRY。

    困了,下次继续。

     
    • xhan 6:32 am on October 27, 2009 Permalink

      写的很好,#1,#5,#7 很受用。

  • tin 2:19 am on September 24, 2009 Permalink | Reply
    Tags: css, em, html, layout, length unit, px   

    再谈网页设计中的em与px 

    回应hax大牛在“em or px“的讨论:

    上次看到你在我分享的friendfeed上面的评论我就想好好讨论一下这个问题了。’em’是从字体设计上面继承的一个概念,是指字模的高度,一般书上会说em能够保证不同字体的大写X的高度保持一致。那么大写X的高度就是这个字体的em。

    你说的px是相对单位不仅在你说的显示器尺寸上是相对的,而且由于大部分的矢量元素的渲染来说比较先进的浏览器都支持“半像素平滑”,连像素内的颜色的投影也可以是相对的(渲染引擎会进行像素平滑的计算)。

    在网页渲染的布局上来说它要转化em到px这个单位,就是说在一定的zoom下两者是等价的。

    但是为什么我还是很支持使用em作为首选的字体和布局单位呢?当然这不是用来保证一行到底可以显示多少文字,因为px也可以保证。主要目的是区分布局中“缩放友好”的矢量元素(如字体,布局相关的所有html元素)和“缩放不友好”的标量元素(如很多“替换元素”是不友好的,典型的如图片,还有在使用某些Windows主题以后的input元素)。在使用webkit的浏览器,缩放会更加友好,文字和布局会随缩放变化,但是图片等却保持原有的最佳尺寸。Firefox3以后所使用的全部缩放我觉得在有些时候是有用的,可是总有它让你不爽的地方⋯⋯

    比如如果你在某些设计场合希望容器变大文字尺寸不变,从而在缩放显示更多内容。另外一些地方你希望容器和文字尺寸一起变化。px和em的配合让两种需求可以比较容易的在同一个页面出现。

    从设计为内容服务的角度考虑,使用em作为基本单位可以让你更集中于“内容驱动”,避免过分的”设计驱动“。我的工作范畴内前者更常见,也更符合客户的需求。

     
    • hax 12:36 pm on September 24, 2009 Permalink

      em是大写X高度这个我倒没听说过。我只知道ex是小写x高度,并且x-height是字体排版中的非常重要的概念。

      针对屏幕的浏览器中,网页样式计算出来的最后结果(computed value或used value),都是以px为单位,而且是允许小数的。“半像素平滑”带来的区别,可以认为是在actual value上,原本必须取整,即渲染引擎只支持整数,现在渲染引擎支持了小数——虽然屏幕上的物理像素总是离散的。

      你后面说的意思我反复考虑了2个小时,觉得值得深入探讨。你提出的将em用来标示“缩放友好”(实际我觉得是“文字缩放友好,text zoom friendly”,具体我们再讨论)这个问题,不仅涉及页面的设计,也涉及浏览器的设计。它还暗示了引入css新长度单位rem的必要性。有机会和你当面聊,然后再做总结。

      btw,偶属羊不属牛。。。

    • hax 12:37 pm on September 24, 2009 Permalink

      BTW,这个页面的默认字体好像小了一点。comment的字都看不清了。不过倒是正好做你的zoom friendly的样本。。。

    • tin 2:16 am on September 25, 2009 Permalink

      关于计算值的你说的很详细,现代浏览器都可以在actual value里面使用小数。不过我观察IE6/7好像并不支持半像素,因为之前我fix一些半像素造成的bug的时候发现IE并不受影响。
      css3里面的rem这个单位感觉只是一个更方便的(不继承)的em。现在的情况下em已经工作的不错了,起码对于我比较喜欢的safari来说。你所说的ex和em(还有百分比)很相似,都是相对单位(Relative length units),他们都是相对于绝对单位(如px和gd)所言,我认为css设计的本意就是解决不同的缩放效果(和不同的设备映射关系)的。
      从《写给大家的设计书》这样的从设计角度考虑内容的书里面推荐字体尽量一致,如果不一致则尽量不一致,基于这样的理念,使用em比较流畅。当然这个和使用的字体有关,中文字体一般不能保证缩放平滑(尤其是linux和windows),所以倾向使用px是合理的。可惜我目前所做的英文应用比较多,英文字体缩放相对平滑(尤其是放大),所以我们选择em就比较流畅。
      FF3和IE8里面那样的缩放并非我所希望的样子,这个角度如你所说em/rem可能是个很重要的单位了。

      BTW:我太懒了,用的wp的默认主题,这个字号绝对是为英文设计的。待我老婆批准时间我修改个theme出来……

  • tin 1:31 am on September 10, 2009 Permalink | Reply
    Tags: , ,   

    pac文件生成脚本 

    之前写过一个我的pac文件,但是非常不好意思。因为那个脚本我为了定义网站列表比较简单,用了个数组。可是pac文件并非在完备的javascript环境运行,所以动了手脚以后这个pac文件只在firefox里面可用,而safari和系统级别都不能用(MacOS X)。所以还是老实写传统的好。可是转念一想,不如还是ruby一下吧。这样修改起来还是加一个域名就OK了。

    #!/usr/bin/env ruby
    proxy = 'SOCKS 127.0.0.1:7777'
    gfucked_sites = [
      'youtube.com',
      'ytimg.com',
      'googlevideo.com',
      'tinyurl.com',
      'bit.ly',
      'blogspot.com',
      'twitter.com',
      'plurk.com',
      'torproject.org',
      'wikipedia.org',
      'tumblr.com',
      'soup.io',
      'pandora.com',
      'adobe.com',
      'last.fm',
      'photoshop.com',
      'google.com',
      'googlecode.com',
      'appspot.com',
      'acer.com',
      'demonoid.com',
      'alexa.com',
      'wikimedia.org',
      'yahoo.com',
      'zend.com',
      'aptana.com',
      'uncyclopedia.tw',
      'uncyc.org',
      'webarchive.org',
      'pornhub.com',
      'yourporn.com',
      'facebook.com',
      'mail-archive.com',
      'versionapp.com',
      'friendfeed.com',
      'ff.im',
      'chinagfw.org',
      'bullogger.com',
      'mulhollanddrive.com',
      'iphone-dev.org',
      'plurk.com',
      'imageshack.us',
      'zendesk.com'
    ]
    puts "function FindProxyForURL(url, host) {"
    gfucked_sites.each do |site|
      puts "  if (shExpMatch(url, \"*://*.#{site}/*\")) { return \"#{proxy}\"; }"
      puts "  if (shExpMatch(url, \"*://#{site}/*\")) { return \"#{proxy}\"; }"
    end
    puts "  return \"DIRECT\""
    puts "}"

    如果使用tor则修改proxy=’SOCKS 127.0.0.1:9050′就OK了。生成一个放在可以访问的Url上,然后让整个系统使用这个proxy,我们就又可以使用我们喜欢的twitter客户端了(for me it’s tweetie)。

     
  • tin 3:34 am on September 6, 2009 Permalink | Reply
    Tags: , , , patterns, , programming to patterns   

    Javascript库的“实现模式编程(Programming to patterns)” 

    今天看到了一篇很好的讲Javascript Library的文章:http://www.clientcide.com/best-practices/jquery-and-the-ajax-experience-programming-to-the-pattern-and-what-really-makes-one-framework-different-from-another/
    作者是一位MooTools开发者,他写了对实现模式编程(programming to the patterns)进行了阐述。告诉我们像Prototype、MooTools这样模拟类继承并鼓励使用OO的方式组织你的代码对于你的好处。而对比的对象就是红火的JQuery。他的观点我举双手双脚同意。

    JS的通用库最基本的目的是给你解决浏览器兼容性差异,让你在与浏览器兼容性的战争中给你一个巨大的后援保证。但是只提供浏览器兼容性的JS库是不会流行的,你还需要在编程模式和代码效率(Code efficiency)上提供帮助。对于我个人来讲,对语言的流畅性改造最好的就是Prototype这个库,因为它营造了一个“最小惊讶”的Ruby语言环境,让你几乎感觉到是在编写流畅的Ruby,尤其在Rails项目里面使用更让你感觉到Ruby和Javascript结合的流畅。(此处我想到了上周Cat Chen同学和我提起的“Language Oriented Programming”的概念,也许这就是它的表现吧,扩展语言减小编程中的“惊讶”)相比之下JQuery则在代码效率上做了很大功夫,这个代码效率不是指运行速度,而是单位代码完成的功能。JQuery对Dom的DSL化封装,还有对method chain的大量使用,几乎让你感觉在声明行为,所以它让非常多的对啰嗦的Dom编程厌烦的前端程序员迅速“上瘾”。但是,我们知道DSL化的JQuery还不够,因为它很好的解决了可读,但是并不一定容易维护(尤其是过度使用method chaning)。另外一个原因就是习惯使用“声明化”以后会让一些程序员忘记“抽象”和“封装”,很多JQuery都没有使用面向对象OO的方式去组织自己的代码,而是拥抱了面向过程编程,而很多人却还自我安慰说自己使用的是“函数式编程”。如果你没有做好函数抽象,那么绝大多数情况下你的JQuery code都不符合函数式编程的本意,此时你也就离抽象出可复用的“模式”越来越远了。

    其实JQuery的很多UI plugins是很好的例子,尤其是支持Progressive Enhancement的JQuery UI插件,它们都很好的规定了自己的micro formats,然后根据dom的模式来组织自己的行为模式(Behavior and Patterns)。它们才是很好的对实现模式编程(programming to the patterns)的例子。缺少了对模式的抽象也就失去了在大的项目中实现代码效率(Code efficiency)的优势(因为代码复用度会下降),这对于JQuery这样一个以“Write less, Do more”为口号的库来说就失去了它最大的卖点。

    所以,实际上关键的问题就是,用哪个JS库都没错,但是如何使用和形成模式才是关键。每个库组织自己的“模式化代码”的风格不一样。但是像MooTools和Prototype(还有YUI)这类基于类去组织代码的库的源代码本身就已经告诉了你如何组织你的代码,而且它们的OO实现对于任何一个熟悉OO的程序员来说都“没有惊讶”,那么你就很容易吸取他们所推荐的代码组织风格了。

    最开始所引用的文章归纳了几个不面向“模式”组织代码的坏处:

    • 缺少抽象,缺少复用
    • 会形成零散的代码,修改起来成本会比较高,维护成本也就增高了
    • 不OO,不容易组织扩展

    我补充一点:

    • 过程化的代码不容易测试,不使用模式的代码也会造成测试的零散,造成浪费

    更新:有一点不准确,就是关于复用,其实Javascript的各种Widget库(如ExtJS、Dojo和YUI的widget库)都做到更好的复用。缺点是目前的widget库中的高级控件都严重的绑架了Dom结构,造成自己修改Dom结构比较麻烦。而没有使用Micro Formats这样的基于标准的弱耦合,这是一个很大的问题。所以由于这样的实现绑架的问题,这些Widget库不包括在上面所述的框架对比中。

     
  • tin 2:01 am on July 27, 2009 Permalink | Reply
    Tags: , ,   

    解决Mac环境下的Java Version问题 

    前一段时间遇到了一个奇怪的问题:我的Mac下面的Lotus Notes 8.5和FreeMind 0.9rc4都不能工作了,它们的共同特点就是都基于Java。我试验了在Terminal里面启动/Applications/Notes/Contents/MacOS/Notes的话是可以启动的,但是会启动以前的Basic界面(后来我才知道可能它是个Cabon应用,而不是Java版本)。所以就一直凑合着用。
    可是昨天我尝试运行/Applications/Utilities/Java Preference的时候它也无法启动了,我这才觉得这不是个简单问题,必须要彻底解决。

    我回忆了一下,我最开始的时候尝试用Java Preference的时候修改了JDK的顺序,将JDK6放在最上方,可是在Terminal里面(java -version)依然只可以访问1.5。所以当时就手动修改了系统的指向:


    /System/Library/Frameworks/JavaVM.frameworks/Versions/Current -> /System/Library/Frameworks/JavaVM.frameworks/Versions/1.6
    /System/Library/Frameworks/JavaVM.frameworks/Versions/CurrentJDK -> /System/Library/Frameworks/JavaVM.frameworks/Versions/1.6

    这样修改以后就工作了,命令行里面执行java -version显示:

    java version "1.6.0_13"
    Java(TM) SE Runtime Environment (build 1.6.0_13-b03-211)
    Java HotSpot(TM) 64-Bit Server VM (build 11.3-b02-83, mixed mode)

    但是大家千万不要这样做,这个其实是后面很多问题的一个重要原因。

    如果你修改了上面的指向,我推荐你unlink它们,然后下载Java for Mac OSX 10.5 Update 4 (http://www.apple.com/downloads/macosx/apple/application_updates/javaformacosx105update4.html)重新安装一下就可以重新生成这些link了。不过记得要unlink自己手工建立的符号链接(比如我的是Current, CurrentJDK, 1.6),否则升级包无法替换你建立的那些。

    但是我这样做了以后还是没有解决所有问题,Java Preference可以正常启动了,不过它设置的顺序依然不管用,java -version总是返回1.5。我突然想到估计是运行我们的Ant脚本曾经提醒过JAVA_HOME的问题,我手动设置过一个,忘记去掉了。所以去查我的.profile,发现了罪魁祸首:

    export JAVA_HOME='/Library/Java/Home'

    这个设置是错误的,虽然它存在,可是它不会根据Java Preference修改的结果去寻找你的Java的bin和lib,也就造成了后面的一系列错误。

    修改为(或者删掉JAVA_HOME声明也是安全的):
    export JAVA_HOME='/System/Library/Frameworks/JavaVM.framework/Current/Home'

    问题解决,教训是如果你手头有工具,应该学会使用它,如果没有耐心学习就错误的使用工具,一开始感觉能解决问题,可是后来它会造成越来越多的错误。那么决绝方案就是回到原点,恢复,学习,正确的使用工具。

     
    • blader 8:14 am on July 30, 2009 Permalink

      Lotus Notes是基于swt的吧,有可能是因为notes里的swt native binary不支持64bit的原因,我就遇到过这个问题。

      ps:snowpard里面默认没有1.5的Java了。

      PS2:好久不见,嘿嘿

    • Tin 5:49 am on July 31, 2009 Permalink

      Notes 8.5是基于Eclipse的,设置错了JAVA_HOME会让它工作不正常。info.plist里面已经设定了Java的版本是1.5和32bit了,所以不会因为版本不匹配的问题启动不了。不过赞哦发现最好还是不设置JAVA_HOME而使用空值比较好,除非遇到哪个软件不行的时候再设置。

    • blader 8:39 am on August 1, 2009 Permalink

      “发现最好还是不设置JAVA_HOME而使用空值比较好”——恩,是这样的,呵呵。

  • tin 2:54 pm on June 24, 2009 Permalink | Reply  

    什么是渐进是增强呢?让我们为开放标准的Web做出一份贡献吧! 

    今天面试前端开发,令我相当不满意。称自己是前端开发,5年以上的工作经验居然说不清楚em、pt、px的意义(是她自己提出了这些单位,简单的给我解释为相对与绝对,我问她区别就打马虎眼……),也完全说不清楚一个自适应两栏布局的实现思路。和我说了一堆交互设计的观点,我的感觉就是经验有一点,不过思路完全是混乱的,一点逻辑都没有。作交互的看看UCD的文章很好,但是如果仅仅限于凑热闹那么就没有意义了。好比一个注册设计,说了太多种不同的观点,但是她依然没有说出如果做一个设计的所以然。实际上作为交互设计显然需要根据需求和客户类型做设计,然后应该有思路,有感觉,做出初步的设计后要通过一些用户调研的手段来取得有效的反馈。这仅仅是交互设计或者开发工程师达到工匠要求的一个基础,要想进阶一些那需要很多的设计感觉的。所以,像我这样的傻傻的程序员出身的前端并不要求你马上让我看到你对设计的强悍感觉(sense),起码你让我知道你是一个有思路有方法的人吧。

    今晚看到淘宝的小马(泽新)同学的一篇博文:http://ued.taobao.com/blog/2009/06/24/web_dev_improve
    写的挺好,是在说我们国内一些前端开发的朋友还在讨论基本的问题,我认为犯这样的错误主要是对Web标准的认识还是太浅显了。上周末我在Beijing Open Party上面临时救场(因为这次话题意外的没有达到9个),我讲的是《什么是渐进增强/如何渐进增强》。这里面没有太多具体的技术,主要是强调HTTP作为Web的支撑,是如何演化出了HTML、CSS、Javascript这三大法宝的。HTTP解决了我们构建一个相互联系在一起的对资源的不同表现(Representation)进行沟通的网络(Web),它解决了我们如何查询和定位资源的不同表现(Restful),以及如何修改这些资源的操作方式。因为它是资源的不同表现,所以实际上它是具有逻辑的数据访问层的一种新的抽象(如数据库+存储过程),这个观点是徐昊同学提出(告诉我)的。如果加上语义网的逻辑推演能力,那么这个数据表现的网络就可以成为智能网络,也就是语义网的概念。也就是说HTTP实际上是一个身肩重任的技术。而在目前阶段,这些非智能的网络的资源表现已经足够被人类直接消费了,那么为了服务它,HTML、CSS、Javascript这些技术也就顺理成章的出现了。他们三剑客要解决的是关注点分离,让我们从数据结构(Representation)、表现、行为方向去帮助人类能够直接消费的HTTP上面的资源。

    说到这个东西总是扯远,但是如果理解到了这个层面,我们知道原来这些技术技术是一个分层的结构,它要解决一个巨大的问题,但是却需要走一个漫长的路程,做到每一层都有所受益。从Restful本身来说它可以是一个计算机消费的资源访问API(里面可以封装Business logic),交换数据应该使用一个结构化的格式,HTML是一种天然的选择。如果作为阅读,人类需要美观的外表和帮助交互的行为,这些是CSS和JS应该去解决的。在这些内容具备以后我们就可以用语义网的推演能力实现数据之间的语义交互,那么就真的是道法自然了。这样的一个逐级实现伟大目标的过程我们就可以称为“渐进式增强”,也就是Progressive Enhancement。上周末的Session我就是从这个角度出发神侃了1个小时的,期间插播了各种渐进式增强所需要注意的最佳实践,他们都是为了我们光荣而伟大的目标而服务的。如符合语义的HTML tag,与资源表现(消费与解析)密切相关的Micro formats,在micro formats理念驱动下的css selector设计,最小化的css selector权重设计和复用,Rails 3.0的行为声明DSL化改造(如使用JQuery时常用的$(‘符合micro formats元素的css selector’).hasSomeBehavior()的声明),传统Rails RJS的缺点,开始使用HTML的新增tagName作为class渐进等等。我不想在这里重复,那天的内容没有提前准备,所以有点天马行空……所有的这些看似风马牛不相及的最佳实践实际上都没串到了渐进式增强实现终极目标的这个过程。我们看到现在桌面应用中微软的WPF也从Web的结构中吸取了经验,提供了一个结构、行为、表现分离的模型,而Flash所用的MXML+ECMAScript+CSS也是这个路子。

    因为这个博文毕竟是个牢骚帖,所以我不想在这里阐述什么是渐进式增强,也许以我的能力根本说不清。我计划着用更多的时间多分几次分别讨论相关的话题,这里只是个开始。

    回到关于小马的那个讨论大家要不要那么温和的问题上,我希望我们还是放弃那些中庸,站到几年以后的Google的技术桟上面。我相信,如果Google推动Webkit成功的话,那些药不用Table实现一个透明边框的Facebook对话框的问题就根本不是个问题了。工程就是工程,我会妥协去用Table,我会做很多Work around,可是,可以折腾的时候我一定要折腾一下,推动那个理想的实现。

    这个是在小马帖子上面的回复:

    HTML要解决的是结构,所以我们压根不用考虑太多到底用哪一种标签来布局。因为标签本来就不是布局的。如果Web是一些数据的表现的状态转移,那么我们在HTML的各种标准需要找到的是数据的筋骨本身。在XHTML1.x的成熟和HTML5的初露端倪的时候,我们已经可以开始幻想YAML、JSON、HTML作为数据源的标准表示方式了,那些表现我们还是继续留给那看似不完美却已经足够强大的CSS吧。偶尔,我们做些妥协,所以我们决定的不妥协正是对基于开放标准成为主流所贡献的一份力量。

    那么,我们不要讨论HTML5什么时候会实现了吧,我们现在就开始为基于开放标准的语义化Web做出一份贡献吧!

     
c
compose new post
j
next post/next comment
k
previous post/previous comment
r
reply
e
edit
o
show/hide comments
t
go to top
l
go to login
h
show/hide help
esc
cancel