包管理器杂谈

前言

今天我想思维跳跃一下,讲讲包管理器,这是一个相当有趣的话题。因为程序员年复一年的写程序,大多是为了娱乐他人,好吧,有的人管那叫创造价值,有的人叫养家糊口。其实没所谓了,本质上来说大部分程序员并不是自己程序的受害者,所以你知道为什么这个世界上有那么多烂程序了吧。让我们回来,聚焦在那些极少的程序员写给自己的程序,除了编译器,版本控制工具以外还有一种非常非常重要,那就是包管理器。

你知道的这个世界上真正了解编译器的人据说坐不满一间教室。我想了解包管理器得人也多不到哪去。首先我们要看看今天要出场讨论的一些候选人。

  • apt 具有超级牛力Debian系猛男
  • yum 为Redhat延寿20年的黄狗
  • homebrew Mac下的青年才俊
  • rubygems Ruby下的魔法大师
  • npm Node.js的超级保镖
  • elpa Emacs的小宝宝

我今天要忽略一些内容,很可能引起某些人的不满。比如像Perl,Python,PHP,Haskell,Lua,R都有一些类似的设施,所以就不一一讨论了。明眼人也许看出来了,六个男嘉宾可以分为两组。一组是系统级别的(system-level),一组是应用级别的(application-level)。维基百科基本上对系统级别的包管理器做了一些介绍,应用级别的仅仅是列举了几个,并没有详细的介绍。但我认为包管理器都是完成类似的工作所以放到一起来讨论。

验证

从单个包的角度来说,一定要确保其来源,否则会轻易受到中间人攻击。所以一般的包管理器都具备简单的验证环节。常见的手法是MD5校验,或者其他Hash校验,homebrew提供的大部分安装包都是用这样的方式校验的。较为严格的应做签名验证,apt和yum都有相应的机制来验证软件包是否来自可信的源。综合来讲Hash的方式加密强度较低,而且严格说来这种校验只应作为下载的完整性检查,并属于授信操作。

依赖性

可以说包管理器解决最为重要的问题就是依赖性关系的问题。我相信在没有yum的RedHat中世纪,大家需要参考n多资料才能正确编译内核。那个时候他们是真心羡慕Debian的。在elpa出现之前,配置一个贴心的emacs环境简直就被视为高手的验证标准。依赖性关系其实并不像看上去的那样容易解决。很多年来make为了解决编译依赖性关系遭受不少的冷嘲热讽。尤其是这种依赖性关系比较松散的时候,看上去就不那么好解决。A依赖于B的3.2.1以上但不超过3.3的版本,这种有时候行有时候不行的条件判断构成了一个非常复杂的逻辑关系。但包管理器必须处理好这个关系,知道哪些依赖条件没有得到满足。依赖性关系的管理是一个生态系统的核心价值。Perl有了CPAN所以带来了一个非常美好的世界,甚至有人说CPAN比Perl的语法更吸引他。依赖性可以让程序员不那么纠结去手工寻找所需要的包,而这个过程可能是相当费时,步骤非常繁琐,而且极容易出错的。对,就好比不使用make工具来编译内核,不是不可能,但阿汤哥会做一些更有利于世界和平的事情。依赖性带来的好处就是开包即用,开袋即食,完全不必担心由于依赖性造成的破损。我猜测由于包管理器提供了一个可信的,可重复的,健壮的依赖性管理,每年程序员节省下来更多时间用于创造新的垃圾代码。

多版本

传统上的包管理器的互斥关系管理有点粗放,apt和yum在处理升级之类的问题时基本就是粗暴地将老的版本替换掉。当然这样设计是比较简单的,可是我们的系统并不美好,经常会有一些遗留软件需要老版本的库。而且从实践的角度来讲这也是一个不太难解决的问题,很多人的机器上都有各种版本的软件,所以后来设计的包管理器就注意了这方面的改进,比如homebrew和rubygems都可以支持同一个软件的多个版本,相互不影响,用户可以随意指定使用软件的版本。多版本是松散型依赖关系必然会出现的特性,也是简单粗暴转向优雅设计的拐点。一个随之而来的问题就是清理不用的版本。这是原来简单粗暴方式比较好解决的一个问题。将原来的是非判断变成了一个寻求最优解的优化问题了。

相对独立的环境

有的时候我们希望严格限制程序的运行环境,但由于包管理器为了便于升级和追新设定了比较宽松的限定条件,使得构建相同的运行环境在相当长的一段时间都是一个非常困难的任务。随着云计算的兴起,基础设施代码化这种思潮逐渐深入实践,诸如bundler这样精巧的工具诞生了。环境配置再也没有手工操作了,而且可以确保所有系统完全一样,简直帅呆了。如果你不觉得帅,那你定没有半夜被狗血电话叫起来去修复线上bug,结果发现这是某个库包与开发者的环境不一样导致的。相对独立的环境在开发者之间也非常重要,任何差异都可能导致惨痛的教训,真金白银的教训啊。相信越来越多的开发者会在云端部署自己的应用,构建相同的环境今后会成为开发者的基本要求的。

发布

有的包管理工具还提供非常便利的构建工具,可以快速构建自己的软件包,并将其发布。开发者可以随时贡献自己的智慧。rubygems就是这样的典型。homebrew可以本地构建一个配方,然后发起pull request,一旦获准别人就能使用了。这个对于未来的开发模式非常重要。Node.js社区的蓬勃发展就是很好的例证。实践证明降低参与者的参与成本特别有利于大家为社区做贡献。

源码还是二进制

我倾向于homebrew的源码编译方式,虽然有点慢,遭到一些诟病,不过我觉得看着代码打补丁,编译是我的个人乐趣。

传输问题

考虑到中国网络的多样性问题,在此我讨论四个方面:网速测试,断点续传,多点传输,下载调度。无疑elpa在这几方面做得奇差无比,简直就是各个方面的反面教材。yum提供插件可以检测最快的镜像源,apt做得也还可以。但都不能同时从多个源下载同一个包,有时候我们还是很需要迅雷或者BT的功能的。断点续传不用多说了,算是一个基本功能。同时开启多少个并发就不能智能点么,非得一个或者n个,就不能自动调节么。

甚至我觉得包管理器应该构建于BT或者电驴之上。

关于源

私自搭建一个源应得到鼓励,应该几乎没有成本地加入到整个全球分布式的系统中,源之间的同步应该也是开箱即用的。这方面做得最好的我认为是全球的公钥分发系统,BT和eDonkey次之。

结语

生态系统无论对一门语言还是对一个系统来说都是非常重要的,人们不会凭着一门语言良好的语法就蜂拥而至的。良好的生态系统为他们提供可靠而丰富的工具链,库包,最佳实践。而位于生态系统核心的正式管理依赖性关系的包管理器。本人杂乱地讲述了对各种包管理器一些思考,希望能“抛砖引砖拍”!

火星程序员带人指南

本来我是想写一本JavaScript方面的书,介绍一些这个领域内关于编程方法学和整体生态环境进展的书。但是去年与图灵的编辑们探讨过后,他们一致认为我应该先写出来一点,看看市场的反应。虽然建议不怎么好听,但毕竟只有真心说实话的人才会赢得我的尊敬。他们的担心体现在了两点,第一就是我作为一个在JavaScript领域并没有什么影响的人写出来的东西到底能不能卖,第二考虑到我妻子临产,我是否有充足的时间完成所规划的内容。至于内容方面我也是有些担心的,主要是貌似国人关心语言生态圈的并不多,他们把语言简单地当做一门工具,无论是赚钱的工具还是娱乐的工具,所以几乎看不到人谈论一门编程语言的流派,演进,思潮,展望。这些字眼儿也许过于风花雪月,但我觉得其实并没有那么地不切实际。在大家都在谈论某一具体的库,某一个具体的网站,某一种具体的新技术时,我总是感觉缺少些什么。似乎在这些疯狂逐利的群氓中,我更希望看到的是一个能沉静下来,多问几个为什么的人。

我最近带了两个新人,他们不是初学编程,基础也比较好。带的过程中我一直在想如何才能不误人子弟,如何能让他们获得内心的平静与强大。考虑再三,我决定让他们通过阅读一些经典代码,然后我提问题和演示的方式展开一开始的学习。理由如下:

第一,阅读源码是绝对必要的。虽然编程是创造性工作,但实际所有创造性工作的绝大部分都不怎么有创造性。这和艺术创作是类似的,大部分艺术家要数十年如一日地修炼自己的各种基本技巧,而这类基本技巧的训练经常是极度乏味,毫无创造性可言的。但是程序员往往以为自己跟别人不一样,想当然地认为大部分工作都是创造性的。说句实在话,我看到的大部分程序员都是缺少基本技巧的训练的,有的甚至说极度缺乏也不为过。最令人不解的是,很多人不愿承认这一点,或者即便承认也对此丝毫不以为意。其中我觉得代码阅读就是基础中的基础,一个看不懂别人写的代码的人,自己的写代码水平也必定有限。这个道理很好证明,一个人可以读懂自己写的任何代码,所以说他对代码的理解力一定大于自身的创造力,反过来说一个人的创造力的上限也就是他的理解力了。写代码和写文章非常类似,我以前也说过,就不罗嗦了。这里只是再一次重申代码阅读能力的重要性非常之高。所以我看程序员好坏,除了让他写一段程序,还可以让他读一段程序,甚至我更倾向于后者。读这个基础打好了,才能为写做一个良好的基础。

第二,要读经典才能学得更多。这简直就是废话。听音乐的要听经典的,读书也要名家名作,临摹字帖得是千古流传的……但程序员大部分时间都在读质量并不怎么高的代码。就好比我们读到的和我们息息相关的文字多数也没有什么美感一样。一定要刻意地找寻经典,话又说回来了,这就需要对一门语言的生态圈十分了解才可以。不但要知道那些产品非常有名,而且要知道为什么有名,谁在用这个产品,怎么用的。经典的代码和经典的音乐有点不一样,经典的代码一般还都处于活跃的维护期,不像音乐好多已经上百年没人更新了(呵呵,有点大不敬啊)。所以经典代码是活的范例,解决的是具体问题,不但可以学到编程的各种规范和技巧,也能学习到比人是如何思考改进代码的。好的代码更易于读懂,更清晰,有利于学习清晰的设计思想。这些都是普通教科书或者一般技术书籍所无法比拟的。学会跟踪趋势,知道流行也是程序员基本技能,况且额外的还可以通过读代码知道很多圈内八卦,这个是一般人不知道的乐趣。

第三,问题可以查看细节的理解是否到位。首先要说明的是无论是提问还是回答问题都是非常鼓励的。我一般会事先布置一些问题,然后让他们一起去研究,然后回答也可以问我新的问题。这种方式经过实践证明是非常有效的。学徒能够更集中精力,对问题的理解也会更加深入。透过他们的回答,我还能更清楚地判断哪些细节掌握的欠佳,我会毫不留情地抛出更多的问题。回答出所有问题只能得到及格,要提出问题才能获得高分。鼓励他们在提问的同时设计实验来检验自己的命题。这种苏格拉底式的修炼,一开始着实让新同学吃不消。因为我的问题无处不在,他们似乎第一次面对一个如此不会掩饰自己无知的家伙。这种方式使得他们渐渐抛弃了那些我们习以为常,却丝毫经不起验证的各种假设和误解。他们渐渐试着怀疑权威的观点,他们也会主动去验证自己的观点。编程是门实用艺术,一定要经得起别人问。

第四,演示促进理解和沟通。我发现大部分人对于把问题说明白这件事儿看得并不是很重要,尤其是工作经验比较少的同学。作为训练的一个科目,我要求不能只讲给我听,要演示给我看,要让我不经意间就能相信你说的都是对的。一开始有的同学觉得我比较扯,什么都演示多浪费时间啊。但如果你看过《完美软件》或者《人月神话》就会明白,就留沟通不行,问题都说不清楚,项目的失败只是时间问题,并没有回天的余地。程序员都觉得以“宅”为美,这就是狗屁好莱坞大片看多了的结果。我们不能相信好莱坞大片中的技术宅男,就好比我们不能相信国产电视剧中的八路军一样。我接触过很多大牛程序员,没见过哪个宅的。在一个团队,就是不能有信息的孤岛。在这个过程中我也发现了新手的一些常见问题,列举一些:

  • 倾向于说服,而不是证明。如果你要说明别人是错的,最好的办法就是举一个反例。如果你要说明你是对的,请回忆一下中学老师关于说明文的各种技巧。其中包括举例子,作类比,打比方等等。记住重复阐述自己的观点对理解几乎没有任何帮助。
  • 证明过程跳跃不完整。你说这两个对象是同一个的时候,就要演示一下是否全等,长得一样是远远不行的。
  • 思路不清晰,经常把自己绕进去了。课下的功夫做得不够。
  • 不cool。很多人说什么?!这也算是缺点!?当然,记得大学里上过的那些死气沉沉政治课吧。很多人上学的时候都对乏味的课程大放厥词,但是轮到自己演示的时候却是一个模样。我为什么要听你讲?你得有趣,人要有趣,讲的东西要有趣,要酷才行。
  • 不能即兴演示。对于观众提出的突发问题,没有即刻的反应。互动效果差。

好了,这些就是我对带人的一些实践。今后我会写一个专题,把我和他们之间讨论的问题记录下来(对,有可能是那种《论语》风格的),名字就暂定为《火星人JavaScript问题集锦》。起初几期讨论一下underscore和backbone的源码,之后会讨论jquery,coffeescript,less,欢迎大家参与讨论。

我们做了一个操蛋的网站

昨天公司内部发了一个邮件让做一个调查。考虑到这个调查系统是我们自己开发
的,而且我还没有使用过,便兴致勃勃地开始一段特别苦恼的旅程。

我不断地问自己问题:一个在线调查系统的目的是什么。在我备受煎熬,不得不
依靠自己强大的内心才完成了这次调查之后。我极其郁闷地将开发同学和产品同
学召集起来,将问题抛给了他们:“请用一句话回答:在一个被调查者眼中怎样才
算是一个好的调查网站呢?”

“需要有其他选项,不想被限定在某几个选项中。”

“易于学习,便于掌握,好操作。”

“引导用户说出自己真实的想法。”

“⋯⋯”

我深深地叹了口气,摇了摇头。我对这些一点儿都不着边际的话并不感到意外,
但我依然抑制不住自己失望。我提示大家:“你们猜我在做调查的时候是一种什么
样心情和想法?”所有人都有点愣住了,似乎从来没考虑过这个问题。

“做这个调查时,我唯一的想法就是:怎么TMD还没做完?!”

很多人笑了,看来这种经历并不是专属于我个人的。还有的人提示我说:“哦,这
个还算简单的呢!”

我继续问道:

“谁会来我们的网站接受调查?他们的目的是什么?我们的产品给他

们带来了怎样的价值?”

所有的人都静下来了。我一点一点的展开:

要知道我们其实做了一个非常操蛋的网站。因为所有来我们这里的用户都非常讨
厌我们的产品,没有,绝对没有任何一个被调查者会喜欢我们网站。因为他们不
是调查公司施以利诱骗来的,就是受人所托,或者是被要求(被逼也说不定)必
须完成调查。没有人是自愿的。他们从我们的产品不能获得一丁点儿价值。他们
想要的是什么?无非是尽早结束,这样调查公司骗来的用户就能获得那些虚无缥
缈的积分,受人所托的就能对别人有个交代,强迫完成的也总算能交差了事。

“一个用户无法获得价值,一分钟也不想多呆的网站肯定是个非常操蛋的网站了吧。
我们唯一能做的就是让其少操蛋一点,配合用户最快速地完成调查。好吧,这就
是用户眼中好得调查网站的标准:最快速地配合用户完成调查。”

所以,交互上要实行最简原则:

一个狗屁单选题绝对不要让用户再确认一次,对于单选题来说“下一题”的这个按
钮也完全没有必要。少一次点击对于程序员来说似乎是一个“死不了人”的问题,
但对于单选效率则会提高100%,这是别的优化望尘莫及的。有反对意见的同学可
以参考google首页,这是一个跳出率极高,粘滞时间超短的页面,难道我们的页
面不应该这样么。

扩大点击范围,整个选项都应该是可以点击的,而不仅仅只是有个选项框可以点
击,极力减少用户在操作过程中的鼠标滑动。邀请选择的暗示要足够强烈。

根本不需要后退(或者“上一题”)按钮,用户一心想往下进行,根本没有心思后退。
如果需要后退的话,那一定是某处逻辑设计失误(比如互斥条件)。如果是这样的
话,一定要立即解决逻辑设计的问题。后退这个按钮掩盖的都是肮脏的浪费。

支持键盘操作。要知道,虽然答题的人不想答题,但经常答题的人群确是非常稳
定的,一旦他发现键盘可用,则会兴奋起来,对于职业答题者非常必要的。

尽量避免让用户录入文字。“其他”就足够了。

尽量将问卷一次加载到前台,由相应的javascript来完成前台逻辑校验
(backbone.js就是不错的技术方案)。
后记

我听说了很多关于调查问卷的奇闻轶事。

有的客户要求做的调查有100多道题目。我不知道制作题目的人是不是仅仅是为了
完成任务。100多道题目太多了。人类的注意力集中时间大概只有20分钟左右,所
以必须在这之前完成所有调查。否则用户会倾向于敷衍,或者欺骗调查系统。

有的客户要求题目的逻辑异常复杂。你做到最后几个题目时不让你继续,除非你
把之前的20道题目都改成他们认为合理的取值范围内。我也是玩过有偿点差的人,
后来放弃了。全因为这些调查不仅是对你智商的侮辱,也是对你耐心和体力的双
重考验。这就是特别典型的逻辑互斥设计缺陷。

有的客户要求当用户对某个题目分数比较异常时给出理由。理个屁啊?会有人看
么??既然然人家选,就不要问人家为什么。所有选项间的继续进行难度应该是
一样的。人为造成的交互难度不一致会使得用户倾向于选择交互容易的选项。所
以客户看到了他们想要看到的结果,问题是那TMD还做什么市场调查啊?

有的客户设计了特别变态的逻辑题目,让用户完成一张我们都认为连阿汤哥都无
法完成的表格。拜托,用户要是都能做完,阿汤哥不就失业了。调查表格的设计
前提就是填写者没有义务填写。一个直接推论就是填写调查表格时,用户不需要
借助辅助思考或者计算h。我真的不知道,调查表的设计者学没学过《市场调查》
之类的课程。有没有老师认真地告诉他们,其实填表的都是大爷。

好了,就权当娱乐了。

MongoDB 2.0的亮点

亮点一 数据压缩

跑过MongoDB一段时间的管理员都会奇怪,这个家伙怎么这么吃硬盘。大家在各自 的实践中总结了各种最佳实践来应对这种永无止境的硬盘吞噬。比如手工的导入 导出,或者利用复制组的自动恢复特性,定期人为制造故障,来强迫系统进行故 障恢复,来达到导入导出的目的。MongoDB对于硬盘的利用率的确不高,这也是广 泛遭到诟病的一点。新的MongoDB 2.0有了campact命令,用来解决这一问题。看 上去有点像做磁盘碎片整理的程序。会不会也很慢呢?很不幸,还是会很慢,不过 好在不需要导入导出所要求的那么多的空间。所以还是要在备份节点执行,还得 选择负载不高的时刻执行。不过后来想想,叫做压缩不如叫做碎片整理更加准确。

 

亮点二 索引

索引原来就有,而且数据量少的话,根本感觉不到这东西需要提高性能。呵呵, 开玩笑了,线上的业务哪个数据量能少呢。新版的索引据称效率提高25%,体积减 少25%。这是个相当不错的消息,管理员尽管用就是了,没什么好犹豫的。只是从 原有的系统升级到2.0并不能自动利用新版索引。需要强制重建索引才行。不过, 管理员要是执行了上面的campact命令的话,会附带重建指定的索引。

 

亮点三 复制组节点的优先级

原来很多人都问我,复制组中的某台机器恢复过来了,怎么继续让它成为活跃节 点(primary)。很不幸,以前没啥好办法。优先级的设定非常重要,尤其是对大型 集群,能够避免负载传递这种连锁反应。优先级高的节点一旦与最新的数据同步, 则会触发选举,并在选举中胜出。很实用吧。

 

其他

增加了对多边形区域的支持,以及多个地点的支持。LBS相关的应用会觉得这个功 能非常贴心。

MapReduce性能有大幅提升,去掉了一些不必要中间转换过程。

大红大紫的JavaScript

现在说JavaScript大红大紫估计大家不会有什么反对意见吧。如今学习
JavaScript不但是一种非常保险的策略,甚至是必要的生存之道。不过这门语言
就和他的难兄难弟HTML一样承载了太多本不应该它们来做的事情。发展速度的过
快造成了原有设计上的缺陷被极不合理地放大了,以至于业界大牛Douglas
Crockford出手教人如何正确地利用那些还不错的特性,避免陷入令人恼火的陷阱。

问题的关键是人都是不靠谱的,再怎么教,再怎么强调,再怎么小心,
JavaScript那些罪恶的灵魂依然会渗入你项目的骨髓当中去。似乎是有
JavaScirpt的地方就有那种挥之不去的阴魂,即便使用了JSLint,也是疲于奔命。
CoffeeScript也许是这种噩梦的终结者,它继承了JavaScript好得部分,但也限
制了一些过于随意的地方。看似CoffeeScript是一门全新风格的JavaScript语言,
或者说是Ruby风格的JavaScript,但也没有必要大惊小怪。还是SICP中的那句
话:"解释器(编译器)也是一个程序"。与其为一门语言做些修修补补的操作,不如
另立门户。貌似C++走的就是这样一条路,历史总是很相似啊。CoffeeScript的一
个比较有意思的地方在于编译生成的正是JavaScript,这样就非常好地解决了与
现有系统兼容和集成的问题。OK,你可以放心大胆地用这个新技术,他对你的老板
是透明的,因为他只能看见工作的JavaScript,并不能看见你的源码。当计算机
技术发展到了今天,有趣的事情终于发生了,你以为看见的是源代码,其实不是。

无独有偶,CSS方面也有类似的方案SCSS(SASS),来解决CSS不支持变量,继承等
问题。巧合的是这两个方案都将作为Ruby on Rails近期即将发布的3.1版本的默
认方案。世界变了,你拿的武器变了么?

翻墙备忘 从bluehost的虚拟主机上打洞访问twitter及facebook

从前从bluehost上面打洞的时候总是不稳定,有时候能成功,有时候不能成功,后来因为有其他的工具,也就一直没深究。
不过隐隐觉得,是否是访问twitter及facebook的流量太高以至于被bluehost封了?

今天发现在 bluehost 上面 curl twitter.com 能抓会twitter 的首页,也就是说,从bluehost访问twitter是没问题的。
那么为什么打洞之后无法访问呢?
问题一定出在本地的DNS上。

好吧,让我绕过DNS,直接把正确的地址填进hosts文件中好了。

获得某地址对应ip:
bluehost上没给发icmp包的权限,所以ping是不成的,用python的socket模块获取。

?View Code PYTHON
import socket
print socket.gethostbyname('twitter.com')

后来发现直接用shell命令

gethostip twitter.com

就行了

将下面的地址加入/etc/hosts

#twitter
128.242.245.84  twitter.com
128.242.245.125 api.twitter.com
128.242.245.116 www.twitter.com
 
#facebook
66.220.149.25   www.facebook.com
66.220.147.42   login.facebook.com

然后再试试用 bluehost 打的洞,灰常顺畅。

Ruby的测试一些记录

最近在写一些ruby程序,自然了,要做一些测试什么的,RSpec无疑是一个非常好的帮手。但是很多人都以为RSpec是用来测试Rails程序的,其实RSpec不止局限于Rails程序,它是一个非常通用的测试框架,不过网上大部分例子都是围绕Rails的,所以给大家带来了一些误解。最近呢,RSpec发布了新版本,2.n,目前已经到了2.3。发布了大版本自然有很多改进,少不了也有许多令人不愉快的变化,尤其是对第三方的不思进取的其他工具的兼容性上就有些问题了。

首先是RSpec和aotutest结合,这个是使用RSpec的第一步,当然并不是所有人都会这么告诉你,但是基本上保留秘密的那些人就是这么用的。RSpec 2需要配置一个./autotest/discover.rb:

Autotest.add_discovery { "rspec2" }

你可以自己写一个,也可以让RSpec自己生成

rspec --configure autotest

效果是一样一样的。这样便可以使用RSpec了,无痛而且高效。

第二,我们要搞一个rr集成到RSpec中去,至于rr是什么,以及为什么要rr,这里简单说一下。rr是一个通用的Test Double框架,这里可能有点不太好懂,因为就算是自认为很了解Unit Test的人也未必真的知道这个词。不过好多童鞋已经知道了RSpec的mock,或者stub了,简单的来说:rr能够提供更好地mock和stub。更好意味着可以更加方便地解耦我们要测试的目标模块,这样意味着能够更细粒度的定位问题,从而获得更加有效的测试效果。

rr集成到RSpec,貌似也不是很难,不过这里要注意,RSpec的整体命名空间有所变化,现在都是以RSpec开头了,原来的那种以Spec开头的会得到警告信息。

RSpec.configure do |config|
  config.mock_with :rr
end

但是这里会稍微有个问题,autotest的时候,在一些情况下autotest不会加载这个spec_helper.rb文件,或者是加载的顺序有些问题,就会导致一些rr方法不能使用。处理办法就是在spec文件前面加入

require "spec_helper"

目前我还没有找到更好的方法,不过估计以后的ZenTest会处理好这个问题吧。或者是启动ruby解释器的时候加入-r这样的参数。

第三个,就是将Rcov结合进去了,做法也比较简单,但是要注意使用RSpec 2的命名。

require "rspec/core/rake_task"
 
RSpec::Core::RakeTask.new :cov do |task|
  sh 'rm -rf ./coverage/*'
  task.rspec_path = "rspec"
  task.rcov = true
  task.rcov_opts = %w{--exclude spec,rubygems}
  task.ruby_opts = %w{-rrubygems}
end

不过这个并不像想像的那么顺利,rcov调用这些例子的时候没有加载RSpec库,真是不幸,所以我们可爱的spec文件一般都会额外多加两行

require "rspec"
require "spec_helper"

这样基本能暂时解决目前的所有不适,可以轻松享用RSpec的好处。

另外我要说的就是,这些修修补补的工作本来不应该存在,这几个工具在今后应该考虑整合一下,友好地集成,毕竟像我这样愿意花时间配置的人不太多。尤其是Rcov,对RSpec2的支持显得有点跟不上了。

Flyspell的错误修复

至于具体怎么用flyspell搭配emacs参看下面这篇文章。

Linux 技巧:活用 Emacs 的单词拼写检查功能

我遇到的问题是flyspell不能正常启动,老是提示该死的

Enabling Flyspell mode gave an error

别提有多欠揍了。网上的说法基本都不对。为了验证我这aspell能工作,要这么着:

mars@mars-laptop:~$ echo "hello, woold" | aspell -a -l en
@(#) International Ispell Version 3.1.20 (but really Aspell 0.60.6)
*
& woold 14 7: wold, world, would, wild, Woolf, wools, Wood, wield, wood, wool, Wald, weld, wooed, wool's

貌似也没什么问题,关键就在这一步,要是我们不加“-l en”会怎么样呢?

mars@mars-laptop:~$ echo "hello, woold" | aspell -a 
Error: No word lists can be found for the language "zh_CN".

基本断定问题就出在这了,添加“lang en”到/etc/aspell.conf中,正常工作哈哈。问题就出在aspell默认是读取LANG作为默认语言的,对于使用中文作为默认语言的系统大家还是要多多注意啊。

MongoDB的备份和恢复

话说怎么备份本身就是一个非常值得深入探讨的问题。能把数据放置到别的地方,而后再拿回来使用,看似很简单,但实际应用中却是非常令人恼火的一件事儿。因为实际运行中,所有的数据都是流动的,以刻舟求剑的方式来作数据的备份和恢复就很不靠谱了。但同时,任何应用于生产环境的数据存储方案首先要考虑的就是备份融灾问题。可能你的机房里不会有大象,但是说不定会有老鼠呢。可能你的操作人员不小心拉错了闸。这些事情貌似都不太可能发生。但是以我的实际经验来看,如果你没有备份的话,倒霉的事儿发生的几率就会成几何级数增长。也就是说备份了就备份了,要是不备份,倒霉的事儿总会发生在你头上。所以还是小心一些。另外说一句,备份是非常不符合精益思想的,起码原生态的简单备份有着明显的浪费,而且若是做不好监控的话,出故障的几率并不低,所以千万不要觉得备份就万事大吉,仅仅是运维的第一步而已。

有两种比较简单的备份方法(直接copy数据库文件,mongodump),不太能单独在生产环境中使用。比较建议的做法是构建Master-Slave,在Slave上做些备份,slavedelay是个非常有用参数,要是不想搞得很麻烦,就可以设置几个不同的slavedelay值的slave,这样就可以应对很多情况了。有人问了,如果有些延时,那么岂不是会丢失一些数据。说对了。首先备份并不能保证完全不丢失数据,任何地球上已知的方法都不能保障这一点。其次,备份数据也要考虑备份的目的。其实并不是所有情况都是要回复到最新的数据的,想一想有人用大量垃圾数据填充你的数据库你怎么办。应对这样的情况就不能简单地恢复到最新的备份了是吧。

在slave上,可以定期地加锁,备份,然后解锁。总之了,要在slave展开热备份的一切操作,甚至为备份建立专门的slave。比如视觉中国的图片存储方案中的备份就是这么做的。

今天学到的几个shell工具

大部分来自 25个ssh技巧,不过我就纳闷了copy-id算是技巧么。
pv 用来查看pipe的速度。
yes 不停地返回某个字符串,其实我觉得这个应该是写Unix程序模仿的第一个对象。
当然了yes和pv搭配起来就能看看某种管道的速度是多少。尤其是远程的情况,比如搭配了ssh。

cstream 可以限制流量的好东西

echo w00t, i’m 733+ | cstream -b1 -t2

另外,tcpdump有个替代品啊tshark,也是很不错的。不知道现在的libpcap,有没有用到mmap这样的技术,有个牛人弄了libcap-mmap在08年的时候就能在10G网络工作,真是牛的一塌糊涂啊。哪天听听ifconfig讲一下这个。

ack 是一种更好的 grep, 完整perl风格的正则支持。