看到这段话,来自这里: Recently I discovered that l…

看到这段话,来自这里

Recently I discovered that learning a foreign language teaches you two things: how to communicate in that language and how to communicate in your own language to non-native speakers. You learn that simple grammatical structures and shorter sentences are easier to understand. You get a feeling for when someone’s following you and which words in the sentence are most important to pronounce clearly.

感觉说的很好。你需要知道如何和没有熟练掌握这门语言(或者领域)的人交流,你需要知道如用简单的表述,清晰的表达你的意思。

数据导入的过程也应该是一个“事务Transaction”

上上周导入数据,我们约定了数据格式,写好了导入脚本,进行了充分的测试。但是当天给我们的数据结构却发生了巨大的变化,但是给我们的更新window就是当天,所以我们只能再写程序将格式转化为我们先前约定的格式。我和 @nasiless 同学结对做这件事。经过3、4个小时的努力,转换没问题了,将中间数据转化的操作演练了一下,没啥问题。当准备好停机升级,又从数据提供方得知其中一部分数据是错误的,然后又给我我们一份补丁文件(名-值对,需要覆盖现有值)。我们由于担心重新生成数据非常费时间,所以分析一下补丁对我们操作的影响。@nasiless 同学和我确认应该只影响其中一个中间数据文件,然后写脚本修正了一下。最后我们“成功”导入数据恢复服务了,当时很庆幸居然成功了(那个时候已经是晚上11点了)。当然其中有一部分导入失败的数据(9xx条)我们输出了一份文件准备后面手工输入。

一周后来(期间系统又进来很多新数据),我们发现导入的数据中失败的那部分可能是由于补丁文件也需要应用在另一部分的中间文件上造成的。可是当我们想反推这个过程并重现它的时候,我们发现我们的临时转换脚本(就是把那天修改的数据文件向中间文件转换的程序)居然放在了我的/tmp目录下,而其间我的mac重启过,所以这些脚本已经不见了。剩下的只有那个导入失败的log和映射补丁文件,我们经过推演问题已经变得非常复杂了。几个错误因素结合在一起,数据再回复的确是个非常费脑子的工作。还好经过反复排查,这些结果都是可逆的,不过其中人工操作众多,非常费事。我们也只能硬着头皮做了。因为这个系统还涉及到钱的问题,钱又涉及分帐问题,所以反推非常麻烦。

我们的结果还算好的,因为有方法反退效果。可是最大的问题在于这个过程本身应该是“事务”,必须全部完成或者全部恢复,当时我们的做法没有遵循这个基本的原则。而且我们的导入程序中复用了系统逻辑代码,但是忘记修改事务边界,没有将多个事务join起来,所以造成了脏数据的出现。这个也是后来折腾我们的一个主要原因。

所以教训就是:数据导入操作本身就应该使用事务,确定好所有的事务边界。而且数据导入的流程也应该是一个事务,不应该允许可能出现脏数据的请款存在,因为这种问题往往是追悔莫及的,也就是safe steps的极致。

最近被开发团队的成员blame的几个错误: 一个从老系统导入新系统的脚本,其中…

最近被开发团队的成员blame的几个错误:

  • 一个从老系统导入新系统的脚本,其中一些是订单导入,还涉及到相关订单的支付问题。结果这个脚本创建订单和支付的操作没有声明事务,而是默认的在它们自己的事务完成后自动提交。结果其中一些因为帐户余额不足无法支付的订单被创建了,造成账目对不上。这个错误的教训就是在复用系统逻辑的时候一定要用心察看事务边界,而且对于导入脚本这样的脚手架也一定要对“事务”有个弦,不能忽略。
  • 一个Django的项目,在重构阶段,一些包正在逐渐被移动到心的地方,我们测试环境中manage.py runserver这几日都正常,但是部署的时候发现mod_python部署报告一个模型无法Import,而后同事又换了mod_wsgi,但是问题依旧。他们用bisect的方法找到了开始出问题的revision,这个revision是我提交的(我那天solo),但是仔细看了diff也很难找到问题,经过多次尝试发现是某一个import后出问题。先开始李明同学怀疑是我用textmate的时候混用了tab和space,但是后来发现问题不它。他们最后定位到这个诡异的问题是循环依赖造成的,虽然说不出具体的问题在哪里,但是经过一些包移动后问题解决了。这个教训是不要太相信Django和脆弱的Python的提示,遇到问题要多怀疑python脆弱的包依赖管理。当然这不是主要问题,对于这个问题也许我们要做的是频繁的部署,这样我们就能早些发现这个问题了。

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')

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库不包括在上面所述的框架对比中。

我的书柜

看到Fenng同学共享了自己的书柜的照片,我也想把我的书柜照个像放上去。

这几年买书也上万了,当然不都是计算机的书,还有很多闲书 P1110170.jpg

经典的技术书籍占了我的书柜的绝大部分区域。还有一些漫画书,大都是大学时代留下来的。 P1110173.jpg

一些放不下的书就随手放在转角的书柜里。 P1110171.jpg

为书花钱大都值得,不过技术书容易过时,处理的时候又舍不得。即使是好书,它也会对你的移动性产生不良的影响,搬家的时候这些东西可是太沉了。

工具-不会用不丢人,怕会用才丢人

工具就是进行生产劳动时所使用的器具。工具的目的在于提高生产劳动的效率。感慨于一些真正的Geek的blog,我也想了一些工具对于我的重要意义,用来作为下一段的目标。

人家说工欲善其事必先利其器,还有磨刀不误砍柴工,实际上在说明工具对提高工作效率真的非常有意义。

今年的我,上游离于前端开发和后端开发之间,同时我还要在两个不同的团队(ThoughtWorks StudioCruiseMingle两个产品开发团队)之间切换,所以对于我来说频繁的需要Context Switch(工作环境切换)。两个团队所使用的技术也不同。

  • Cruise是一个标准的Java团队,大家的开发工作站都是Ubuntu环境,IDE是Intellij IDEA,源代码控制是Mercurial(aka. HG),自动化构建脚本基于Ant,持续集成工具就是自己开发的Cruise。
  • Mingle团队是标准的JRuby on Rails团队,大家开发机器是Macbook pro或者Mac mini,编辑器是TextMate(JRuby部分有IntelliJ IDEA的工程),源代码控制是Git,自动化构建脚本基于Rake,持续集成工具有两个,其中提交前使用的precommit CI是基于我们公司的开源产品CruiseControl.rb,而主持续集成服务器是基于Cruise(也就是前面那个团队的产品)。
  • 两个团队所使用的敏捷环境是Mingle,用过Mingle的朋友知道,这个NB的工具的可配置性很高,这两个团队的Mingle项目模板区别很大。
  • 这两个环境的区别还是相当大的,而且每次我切换了团队(大约2个月的周期),我很有可能就需要很大的更新我的Macbook pro上面的各种库。
  • 当我做前端开发的时候,我还要切换与我的Mac上的Photoshop CS3和Mac的VMWare Fusion上的Fireworks中(使用Windows的Fireworks的原因是授权,我的正版授权是Windows的)。使用Fireworks的原因是我们的设计师使用它,所以我需要使用它来调整一些小的设计。
  • 在做Javascript逻辑的部分,我需要在Firefox 3/2、Safari 3、IE6/7(VMWare Fusion)之间切换,每个浏览器都有不同的附加调试工具(主要的三个Firebug、Inspector、IE Dev toolbar)。

我想对于一个强悍的程序员(最近比较崇拜的delphijhdcola云风等神人)来说做这样的环境切换也许还是可以的。可是对于我这个不善于multi-task工作的人来说,马上让脑子适应不同环境,熟练使用不同的工具就成为了一个挑战。

所以,结果是,这一年中,我基本上对于这些工具很少深入学习,基本上就是凑合着使用,如果没有通用的快捷键我就懒得去翻手册学习了。结果就是使用HG的queue功能(超级有用的qnew、qrm、qpop、qpush系列)的时候经常把自己搞崩溃(今年居然有和李彦辉教授在pair的时候搞丢了2个小时内的修改,相当丢人),所以后来在使用HG的时候异常小心,生活在心理阴影下面。而对于Git,我居然完全没有使用过stash功能(和HG的queue类似)。昨天胡凯还问我是否用过bisect,是一个折半查找坏提交的功能(在HG和Git里面有等价的功能),我完全没有使用过。因为这些精巧的基于命令行的源代码控制工具对于程序员来说非常之重要,从这个角度体现了我对于工具的不求甚解达到了什么程度。突然想到梅兰芳里面十三燕那个很棒的台词“输不丢人,怕才丢人”,用不好工具没事,但是害怕学习用工具那就是很丢人的问题了。

那么自我分析的结果就是,由于环境切换,我缺少了专注,形成了对学习环境中的工具的恐惧,最后影响了我的工作效率。

下面的内容用来自勉,分析一下工具对于我到底有多么的重要(也就是说这个是我使用和学习工具中比较Happy的部分)。对于还没有注意到工具重要性的朋友,可以关注一下,看看是否有所借鉴。

  1. 关于GTD:去年看了不少退墨的文章,我深感这种意为减轻压力的“Todo list“对我的重要。最早我使用了文本文件来记录,每天一个文件。但是后来发现跨天完成的任务使用这种方式不好,需要手工拷贝。所以后来按照每个Context(家、单位、电脑、手机…)放一个文件,然后使用日期作为风格,跨天的任务我就拷贝一下,这个文件本身放在EverNote里面实现多平台共享。但是后来我发现这样也不好,因为不明显,也不好做计划。再后来我开始使用iGTD,发现似乎不错,它的结构比较简单,而且它分开了context和project两个概念,所以像“OpenParty、Mingle、Cruise、梦想”也有了自己的归宿。GTD的做法,please google之。
  2. 关于工作和休息的切换:一开始我惊艳于Livid修改过的TimeOut这个软件,但是它运行的经常很慢。后来我使用了原版的AntiRSI这个抗劳损软件,它的原理就是根据你设定的时间提醒你做短休息(一般是15分钟,站起来休息30秒),还有长休息(一般是45分钟,站起来休息5分钟)。再做结对编程的时候弹出它可能你的pair会有意见,但是你需要通过它的实际效果来感动他们。结果是Mingle的队友已经基本上都在使用它了。
  3. 分布式版本控制工具:DVCS可以帮助你更好的管理本地分支,让分支变得轻量,而且它还可以帮助较大的分布式团队更好的管理自己的本地主干。而且他们里面还有很多帮你管理提交习惯的工具,比如前面提到的提交队列工具,可以鼓励你使用更加频繁的本地提交。当然使用分布式版本控制工具的前提就是你要仔细阅读一下hand book,学习一下他们的基本概念和原理,这样才能达到更好的效果。
  4. Feeds工具:我使用Google Reader阅读文字型RSS Feeds,使用iTunes订阅Podcast。
    • 阅读工具多了去了,你的选择很多。但是要做的是学会更好的使用这些工具。今年从Patrik lightbody那里学会了重构Rss Feed订阅的重要性,要减少一个feed使用多个tag进行管理,因为一般鼓励在一定时间段里面保持未读feed不要积攒太多(这就失去了持续阅读的能力),但是如果使用多个Tag标记feed,那么在统计未读条目的时候往往会重复统计,会造成很大的阅读压力,而且对于给自己的不同feed组定不同的优先级也不利。
    • 所以我首先做的是将所有的订阅单一化,分类清晰了很多。分类有一个小技巧,不要对个人博客按照主题打标签,比如以前我给robbin的博客打上java的标签,而livid打上了apple的标签,那么在我决定要看哪个标签下的主题的时候就会感觉很迷惑,因为个人博客都没有固定主题,所以这些标签就编程没有意义的误导了,所以我现在对于这类feed直接标记为“Interesting Person(有意思的人)”,我可以给这些人很高的优先级。
    • 另一类是如GizmodoLifehacker这种信息门户型,他们每天要更新50+的新条目,所以我把他们放到一个单独的如news portal这样的分类里面,我可以给他们很低的阅读优先级。
    • 不同优先级的条目在Google reader里面还可以对应列表/展开的方式查看,可以很好的提高使用效率。再有就是Google Reader的快捷键,在吃午饭的时候,右手用来吃饭,左手可以通过一个空格健来实现滚动和查看下一条,s是标星,Shift+S是共享,这个基本上就可以实现单手阅读了,很方便。
    • Podcast是坐地铁上班时很重要的学习工具:因为地铁和很多交通工具非常拥挤,即使带上书也没有空间看(尤其时备上电脑上班的我们)。所以在非常拥挤的时候我会选择听音频的Podcast,如锵锵三人行(了解时事)开卷八分钟(了解好书,不过越来越没意思了)、Ruby on Rails Podcast(Rails的)、RailsEnvyTackSharpJDD主讲的关于摄影)等等。在不是那么拥挤,也就是胸前有10厘米以上空间的时候,我会选择看视频Podcast,最精彩的是TED Talks的演讲,不错的有Apple Quick TipsX-Play Game Previews等。用这种方式消磨时间比用PSP好很多。这是一个购买iPod touch 2的理由^__^
  5. 信息分享服务:这个又是一个很大的话题。大家在聊天的时候经常感觉很有收获,原因是兴趣相投的人在互通有无可以带来很多的有用信息,而不是像电视的新闻节目或者报纸那样给你带来没有针对性的噪音。社会化网络SNS实际上是个很好的分享有用信息的平台,可是我不是很喜欢facebook等给我带来的参与压力,所以我一般通过一些通用的分享服务来满足自己的需求。
    • 我一般通过Last.fm来实现音乐播放历史的跟踪,通过它的推荐服务来发现一些我喜欢的音乐。这实际是一个相关度算法的应用场景,它不同于简单的试听型的网站(现在国内的xiami.comkedou.com我觉得基本上属于这种类型),它的目的不是给你知道的音乐听,而是根据你听过的音乐推荐你一些音乐听,收集音乐品味的过程叫scrobbler,我在使用iTunes放音乐以后会被自动同步到last.fm并用来做数据挖掘。使用Last.fm服务需要注意的就是要及时更正你的mp3-tag信息,这样你提交的数据就不会是垃圾,这对未来享用推荐服务非常重要。但是现在我发现的一个问题是,由于中文有简体和繁体,所以很和多时候Last.fm的亚洲歌手的名字都会出现多个版本,这给推荐带来了难度,也许国内的服务上可以帮我们解决这个问题吧。使用iTunes的朋友可能苦恼于mp3-tag信息乱码,那么使用Glider开发的ID3Mod2这个软件。
    • 看电影和看书通过豆瓣就很爽了,我对它使用的很初级,但是豆单等已经聚合过的相关分组已经可以给我看电影很多启发了。使用豆瓣这样的工具我们要做的就是尽量及时的更新你的阅读列表,这样豆瓣得到你的更多数据,那么推荐也会更加准确。
    • 我非常珍惜Google Reader的share功能,尤其是share with note。因为这个几乎是最好的和靠谱的朋友分享信息的手段,我一直认为这个是最好的一个人肉过滤器,你的朋友圈子越准确,得到的share也就更符合你的品味。自己在share的同时,可以看到你的share的朋友就和你做了非面对面的交流。而且有的时候如果你1个月没有读feed,已经无从看起的时候,完全可以把他们置为已读,然后去看朋友的分享。这减少了很多信息过滤的成本。
    • 最后一个重要的分享服务就是Twitter了。Twitter解决了你不能和所有的你想交朋友的人聊天的缺憾,这样你可以轻松的follow业界大牛,如d2hkent beck等。它也是一些重要信息的最快速发布场所,同时也是一个重要的社交场所。在使用Twitter以后我发现我甚至越来越少的在使用IM软件了。使用Twitter这个工具你需要做的就是有节奏的发信息,而不是三天打鱼两天晒网,这样大家不会因为你太贫而退订你,也不会因为常年见不到你的twitt而忘记你。
  6. 信息存储服务:网上看到好东西我们经常想收藏,这种行为叫做网摘,最早我使用CyberArticle(荣幸的买了正版,用的很High),而后用了Linux,所以改用Scrapbook,作为firefox的插件它是跨平台的。此时我的同时推荐我使用在线的Google记事本,这几个软件都能很好的做网摘。但是这几个软件的缺点是缺少协作,那么后来最常见的就是社会化书签应用,delicious,在浏览器装个插件以后它可以帮你用tag管理书签,好处是还顺便帮你做推荐服务,很方便。后来我发现并非只有这些数据需要存储,我们还需要网络磁盘服务,这类服务很多,我个人倾向于使用Dropbox,它的好处是各个平台都有客户端(Win、Mac、Linux),而且是用户空间磁盘系统,用起来和本地磁盘一样,它同样可以用来在项目组之间共享一些文档、电子书等。最后,我还推荐一个类似M$的OneNote的免费在线文档、及数据存储服务EverNote,我用它来存储一些简单的文本文档,还有用它写一些视频note,因为它有一些方便的工具帮你来做音频或者视频的记录。(对了,还有梦断代码里面描述的难产的软件Chandler,它是一个本地的数据中心软件)
  7. 快速启动服务:就是使用键盘快捷索引的启动工具,有代表性的是QuickSilver(是Mac下的,详情看Robbinlu的这篇blog),它显然比Mac自己的Spotlight好用(而它又比win下的很多桌面搜索强很多很多)。通过培养这样的软件可以帮你极大的提高效率。Windows下有launchy也很不错。
  8. 还有很多,但是我没有必要一次全部说完……

下面要分析一下我做的不好的地方,迎来跟踪我的改进:

  • 没有认真的学习Git和HG的用法,没有很好的贯彻他们的最佳实践。
  • 没有很好的学习shell。很少给自己写脚本来提高每天工作的效率。对很多*nix命令还很不了解,如wc、du……,对于微语言awk等不了解,这就限制了我制造自己的组合工具的能力。
  • 没有学习如何使用Mac的automator和appleScript。
  • 对于C语言的了解太初级,还是大学上课的水平,而它又是读懂很多code的关键(我并不想成为c程序员)。
  • 没有很好的整理好自己在各个网站的帐号。所以经常忘记去使用这些服务。
  • 没有很好的整理自己家的硬盘,没有对里面的电影和音乐进行过删减。因为数据也会过期,如果总是舍不得那么它们都被积累为工作噪音。所以要勇于与过去告别。
  • 没有好好学习Photoshop和Fireworks的使用,总是在使用低效的重复劳动。
  • 没有管理好自己的博客。我今年做了的事情就是把blog从BlogJavaLive Space移动到了朋友的机器上的wordpress上,但是由于访问速度比较慢,而且离线的时候写东西不方便,我今年也很少写blog post。
  • 没有学会使用一个有效的照片库软件,iPhoto的分库功能我最近才知道,不过没有认真整理(要减少单个iPhoto Lib的大小,这算个最佳实践)。我也应该学会使用一个LightRoom或者Apeture那样的面向摄影的后期软件。
  • 没有学会使用图片分享服务,我游离于flickr、picasa web和好看簿之间,前两者现在都有了iPhoto客户端,但是我还没有很好的使用。在9的内容做好后,我要更好的利用图片分享服务。
  • 没有很好的学习Ruby on rails,虽然一开始仔细阅读并且也用1.0的rails写了些小应用,但是我的知识没有及时更新。
  • 没有很好的清理自己的数据遗迹,我这个人很注意备份,但是没有注意清理过期的备份,想个好的工具来解决它,如TimeMachine。
  • 没有使用好Facebook和Linkedin这两种SNS,它们实际上能够帮助我很多
  • 没有利用好我买的图书,书是学习工具,而不是收藏品,我没能很好的阅读它们。

暂时先准备写到这里,其它的关于工具的话题我会另开post来总结。(最后更新于2008年12越21日)

[转载]Ruby的并发的一些基本限制

因为是feedburner的feeds,所以我就转过来。

Concurrency is a Myth in Ruby


Concurrency introduces parallelism into our applications, and threading is, of course, one way to achieve concurrency. But it turns out that in Ruby, this relation is not transitive: execution parallelism is not the same thing as threading. In fact, if you’re looking for parallelism in your Ruby application, you should be looking at process parallelism instead. So why is that?

Ruby under the covers: Global Interpreter Lock

To understand what’s going on, we need to take a closer look at the Ruby runtime. Whenever you launch a Ruby application, an instance of a Ruby interpreter is launched to parse your code, build an AST tree, and then execute the application you’ve requested – thankfully, all of this is transparent to the user. However, as part of this runtime, the interpreter also instantiates an instance of a Global Interpreter Lock (or more affectionately known as GIL), which is the culprit of our lack of concurrency:

Global Interpreter Lock is a mutual exclusion lock held by a programming language interpreter thread to avoid sharing code that is not thread-safe with other threads. There is always one GIL for one interpreter process.Usage of a Global Interpreter Lock in a language effectively limits concurrency of a single interpreter process with multiple threads — there is no or very little increase in speed when running the process on a multiprocessor machine.

Deciphering the Global Interpreter Lock

To make this a little less abstract, let’s first look at Ruby 1.8. First, a single OS thread is allocated for the Ruby interpreter, a GIL lock is instantiated, and Ruby threads (‘Green Threads‘), are spooled up by our program. As you may have guessed, there is no way for this Ruby process to take advantage of multiple cores: there is only one kernel thread available, hence only one Ruby thread can execute at a time.

Ruby 1.9 looks much more promising! Now we have many native threads attached to our Ruby interpreter, but now the GIL is the bottleneck. The interpreter guards itself against non thread-safe code (your code, and native extensions) by only allowing a single thread to execute at a time. End effect: Ruby MRI process, or any other language which has a Global Interpreter Lock (Python, for example, has a very similar threading model to Ruby 1.9) will never take advantage of multiple cores! If you have a dual core CPU, you’ll have to run two separate processes.

JRuby is, in fact, the only Ruby implementation that will allow you to natively scale your Ruby code across multiple cores. By compiling Ruby to bytecode and executing it on the JVM, Ruby threads are mapped to OS threads without a GIL in between – that’s at least one reason to look into JRuby.

Process parallelism

The implications of the GIL are surprising at first, but it turns out the solution to this problem is not all that complex: instead of thinking in threads, think how you could split the workload between different processes. Not only will you bypass an entire class of problems associated with concurrent programming (it’s hard!), but you are also much more likely to end up with a horizontally scalable architecture for your application. Here are the steps:

  1. Partition the work, or decompose your application
  2. Add a communications / work queue (Starling, Beanstalkd, RabbitMQ)
  3. Fork, or run multiple instances of you application
  4. Not surprisingly, many of the Ruby applications have already adopted this strategy: a typical Rails deployments is powered by a cluster of app servers (Mongrel, Ebb, Thin), and alternative strategies like EventMachine, and Revactor (equivalents of Twisted in Python) are gaining ground as a simple way to defer and parallelize your network IO without introducing threads into your application.

虽然本文是介绍Ruby1.8、1.9和JRuby对线程的不同实现。但是却清晰的解释了线程安全的意义,还有为什么MRI(或者同样使用GIL的CPython)需要使用多进程模型部署。再延伸我们可以知道Apach上面的Mod_rails(Passenger和Ruby Enterprise Edition)还有Mod_python的神奇之处,他们都hack并实现了使用fork让进程共享内存。最后本文还同样引出了为什么传统Ruby和Python应用只有使用多进程才可以利用多个CPU,还有为什么Twisted和EventMachine使用了单进程单线程+event IO的模型。

找到了我的Mac下的git-svn不工作的问题

前一段时间把Mingle的svn用git-svn在本地clone了一个git repository,不过后来非常奇怪的是git svn的时候提示命令找不到了。没有在意。

今天需要用git svn rebase一下这个repository,所以到处搜索为什么?最后发现了问题在于我使用macports安装的git-svn,但是升级的时候却使用了git install,结果造成了系统中安装了两个配置不同的git-core包,而包含git-svn的却没有被激活。

执行

tin@tw-dell:git_mingle >port installed The following ports are currently installed: … git-core @1.6.0.2_0+bash_completion+doc+svn git-core @1.6.0.2_0+doc (active) …

就是说+svn的git-core目前没有激活,那么好办了。

tin@tw-dell:git_mingle >sudo port deactivate git-core @1.6.0.2_0+doc —> Deactivating git-core 1.6.0.2_0+doc tin@tw-dell:git_mingle >sudo port activate git-core @1.6.0.2_0+bash_completion+doc+svn —> Activating git-core 1.6.0.2_0+bash_completion+doc+svn

其中先deactivate现在激活的git-core,再activate+svn版本的git就OK了。 如果你还没有安装,这样安装:

sudo port install git-core+svn+bash_completion+doc

–EOM–

InfoQ“构建的可伸缩性”文摘

InfoQ上面的一篇文章《构建的可伸缩性和达到的性能:一个虚拟座谈会》
http://www.infoq.com/cn/articles/scalability-panel
这篇文章很好,给了你很多做可伸缩性的线索,记录下这些点滴。推荐感兴趣的人去InfoQ阅读原文。

  • ab & httperf: 它给我们提供了一些自动化的负载测试,因此对比于我们从firebug中获得页面级的计时,使用这个工具可以获得会话级的计时。
  • firebug:
  • Ganglia是非常优秀的。同时Nagios或Zabbix(举个例子)将告诉你何时资料遭到破坏,使用少量加工你就能够让ganglia给你提供任何东西。
  • 对于MySQL,Innotop + slow query log 帮了大忙
  • GDB和DTrace是用于C++的基础架构。core或 pstack是个颇有价值的工具
  • 我们使用各种工具来重现问题并调试它们(包括栈的问题)——Visual Studio、 Eclipse、WinDbg、cdb、Purify、Fortify、dtrace以及许多定制的东西,为我们的架构所构建的东西
  • 从某点上讲,伸缩性已经从领域问题(即,如果你不使用内存缓存或者一个等价的分布式哈希表和基于内存的缓存)转移了,而你仍然处于“领域”范围
  • 当今静态内容的可伸缩性已不那么重要了,那只是花钱的问题并需要公司有好的社会组织的问题
  • 不要试图在部署之前就捕获性能问题。你不可能重建真实环境中的条件,因此你不可能得到真实可靠的测量结果
  • 监测。非常仔细的监测
  • 墨菲法则(一种幽默的规则,它认为任何可能出错的事终将出错)确保了你没有严密跟踪的衡量标准就是那个对你不利的标准!
  • 除非你知道当时正在执行什么业务功能,否则一个CPU测量是无意义的
  • 你只能通过使用软件实现伸缩性。“语言是不能伸缩的。框架是不能伸缩的。而架构是可以伸缩的。”