——《编程珠玑》引发的编程竞赛

原文链接:http://reprog.wordpress.com/2010/04/19/are-you-one-of-the-10-percent/
迈克·泰勒(Mike Taylor),2010年4月19日
翻译完成:2010年4月20日

有一些讲编程的图书,我会从头到尾、一字不落地反复研读;还有一些讲编程的图书,我已经看过好几遍了,但每次差不多都是只看其中的一章。乔恩·本特利(Jon Bentley)1986年的经典名著《编程珠玑》(Programming Pearls)则是少数几本能同时归入上述两类的编程图书之一,我手里这本书的封面已经严重磨损,下图可以为证(点击看大图,注意左下角。——译者注)。

(我有这本书的第1版[amazon.comamazon.co.uk],上面就是扫描的这一版的封面,好像我该买一本又新又便宜的第2版了[amazon.comamazon.co.uk],第2版比第1版多了3章内容。)

我打算最近再专门写一篇关于这本书的文章(我已经为Coders at WorkThe Elements of Programming StyleProgramming the Commodore 64 The C Programming Language专门写了几篇书评),但今天我只想就这本书中的几段话谈谈自己的想法。这几段内容有点骇人听闻。

只有10%的程序员可以写出二分查找

每次翻开《编程珠玑》,我都会先看一看下面这几段文字:

二分查找可以解决(预排序数组的查找)问题:只要数组中包含T(即要查找的值),那么通过不断缩小包含T的范围,最终就可以找到它。一开始,范围覆盖整个数组。将数组的中间项与T进行比较,可以排除一半元素,范围缩小一半。就这样反复比较,反复缩小范围,最终就会在数组中找到T,或者确定原以为T所在的范围实际为空。对于包含N个元素的表,整个查找过程大约要经过log(2)N次比较。

多数程序员都觉得只要理解了上面的描述,写出代码就不难了;但事实并非如此。如果你不认同这一点,最好的办法就是放下书本,自己动手写一写。试试吧。

我在贝尔实验室和IBM的时候都出过这道考题。那些专业的程序员有几个小时的时间,可以用他们选择的语言把上面的描述写出来;写出高级伪代码也可以。考试结束后,差不多所有程序员都认为自己写出了正确的程序。于是,我们花了半个钟头来看他们编写的代码经过测试用例验证的结果。几次课,一百多人的结果相差无几:90%的程序员写的程序中有bug(我并不认为没有bug的代码就正确)。

我很惊讶:在足够的时间内,只有大约10%的专业程序员可以把这个小程序写对。但写不对这个小程序的还不止这些人:高德纳在《计算机程序设计的艺术 第3卷 排序和查找》第6.2.1节的“历史与参考文献”部分指出,虽然早在1946年就有人将二分查找的方法公诸于世,但直到1962年才有人写出没有bug的二分查找程序。

——乔恩·本特利,《编程珠玑(第1版)》第35-36页

几个小时!90%!老兄,严肃点!难道这还不够骇人听闻吗?

之所以想看这本书的第2版,原因之一就是想看看这几段文字有没有修订过,看看从1986年到1999年出第2版,这个数字有没有变化。直觉告诉我,这个数字一定向好的方向变化了,事物都是向好的方向发展的嘛。但理性却告诉我,在一个程序员把更多的时间都花在摆弄库上,而不是编写实际代码的时代,重现核心算法的能力即使有也一定会弱化。别忘了,本特利提到的那些家伙可都不是等闲之辈,他们都是贝尔实验室和IBM的专业人员。所以,我们有理由相信他们的成绩实际上已经是最好的了。

好,下面就做一个二分查找的测验

我跟你一样(如果你是这么想的),想马上就试一试。(好啦,不是马上。先看完这篇文章!)我相信看这篇文章的人都知道什么是二分查找算法,即使你不知道,上面引用的本特利的描述也应该够了。请你打开编辑器,编写一个二分查找例程。什么时候觉得没有任何问题了,保留那个版本。然后测试,然后通过在下面留言的方式告诉我你是不是第一次就做对了。我们肯定能打破本特利10%的纪录吗?

规则如下。

  1. 使用你喜欢的任何编程语言。
  2. 不要剪切粘贴或以任何方式复制别人的代码。甚至在你写完之前,都不要参考其他的二分查找代码。
  3. 甚至于我不得不强调,别调用bsearch(),或使用其他瞒天过海的手法 :-)
  4. 时间自己来定:5分钟不短——只要你能保证写完写对;8小时不长——只要你愿意(而且有那么多闲工夫)。
  5. 可以使用编译器消除一些无意识的错误,如语法错误或变量初始化失败,但……
  6. 在确定程序正确之前不要测试
  7. 最后,也是最重要的:如果决定参与这次测验,就必须报告。成功也好,失败也罢,甚至半途而废也要给我个话儿。否则,就无法保证测验结果的准确性了。

(考虑到这只是一次测验,可以忽略计算索引时导致的数值溢出。这里描述了相应的情形,但打算参加这次测验的人在编完程序之前不要看,因为那篇文章里包含一个正确的二分查找的实现,想洁身自好的朋友一定是不屑为之的。)

如果你的代码经验证确实正确,那么如果你愿意的话,欢迎你在留言里贴出自己的代码。不过,假如你这样做了,而后来的留言给你挑出了bug,请你一定想好怎样为维护自己的形象而自圆其说 :-)

更酷的玩法:对于那些信心十足的人,如果你真敢肯定自己的程序没有问题,可以先把代码贴在留言里,然后再测试。当然,你必须要在留言里说明这一点,以便大家发现你的bug时,会考虑多少给你留些情面。

我会在某个时间总结一下这次测试的结果——比如说,一周以后。

行动吧!

第一次更新(一个半小时后)

感谢朋友们的积极响应,这么快就有那么多留言!我得提醒大家,WordPress的留言系统会解释HTML,因此会吞掉类似下面的代码段

if a[mid] < value

最好的办法就是把源代码放在{source}…{source}标签之间,注意用方括号代替这里的花括号。(我第一次想告诉大家这一点时,使用的是方括号,结果我写的规避标记的说明,反而被当成了标记——悲哀呀!)这样做还可以保留缩进,否则我还不知道有什么办法可以做到这一点。

替WordPress向大家致歉:我真的希望这个平台允许留言者预览留言和/或在发表后还能编辑留言,这样就可以避免出现乱七八糟的代码了。我也想了办法自己动手解决这个问题,但WordPress不仅会错误地显示带有<符号的代码,它实际上会丢弃该符号后面的所有内容,唉,我想我是没折了。

第二次更新(在原文章发表4个小时后)

哈哈,你们这些家伙太出人意料了。仅仅4个小时,这篇文章的留言数就超过了以前的一篇文章保持的纪录(Whatever Happened to Programming此时的留言有206条)。

如果想看到相关的更多讨论,Hacker News中有不少不错的留言,另外Reddit的留言质量虽然差一点,但也值得一看。这些讨论把实际地编写代码看成只有精英程序员才会干的事。

译后记:看了几眼,能认出来的加上认不出来的:C、PHP、Ruby、Python、Common Lisp、VB.NET 、C#、Java、Javascript、Delphi、Haskell、Scheme、Clojure、Perl、Smalltalk、FORTRAN、Lua、Objective-C、ColdFusion……各种各样语言的实现齐聚一堂。

有心人乔尔·甘勒(Joe Ganley)对前100个留言作了统计,结果如下:

Python 40
C/C++ 36
Unknown/pseudocode 6
Lisp/Clojure/Scheme 5
PHP 4
Three each: Java, Perl, C#, JavaScript
Haskell 2
One each: VB, Delphi, Smalltalk, FORTRAN, Lua, Objective-C, ColdFusion

Conclusion: Almost everyone (who cares about implementing binary search, anyway) uses C/C++ or Python.

PS:专注前端开发的程序员们,可以参考《JavaScript高级程序设计》的作者Nicholas C. Zakas使用JavaScript实现的一些基本算法,链接地址如下http://www.nczonline.net/blog/tag/computer-science/。其中,对本文提到的二分查找算法的实现如下:

  1. //Copyright 2009 Nicholas C. Zakas. All rights reserved.
  2. //MIT-Licensed, see source file
  3. function binarySearch(items, value){
  4.  
  5.     var startIndex  = 0,
  6.         stopIndex   = items.length - 1,
  7.         middle      = Math.floor((stopIndex + startIndex)/2);
  8.  
  9.     while(items[middle] != value && startIndex < stopIndex){
  10.  
  11.         //adjust search area(调整查找范围)
  12.         if (value < items[middle]){
  13.             stopIndex = middle - 1;
  14.         } else if (value > items[middle]){
  15.             startIndex = middle + 1;
  16.         }
  17.  
  18.         //recalculate middle(重新计算中项索引)
  19.         middle = Math.floor((stopIndex + startIndex)/2);
  20.     }
  21.  
  22.     //make sure it's the right value(确保返回正确的值)
  23.     return (items[middle] != value) ? -1 : middle;
  24. }

配置完Android开发环境后,遇到两个问题,一个属于非技术问题,另一个属于技术问题。

先说非技术问题。

很简单,启动Android模拟器(需要先创建AVD)时,先看到的是一个文本界面,我一开始以为自己的配置出了什么问题。迷惑了大半天,晚上从外面吃饭回来,突然想起来《Android基础教程》(人民邮电出版社,2009年11月)中有一段提示:“启动模拟器需要花较长时间。可以这样想象一下——首次开机时,手机也需要启动,就像任何计算机系统一样。关闭模拟器就像是关闭手机或取出手机电池一样。”会不会是我太着急了?应该有点耐心才好。于是,我重新启动模拟器,耐心等待……大约3分钟后,终于看到Android的图形用户界面,OK。

正好《Beginning Android 2》这本书中也有一段相关的话:NOTE: The first time you use an AVD with the emulator, it will take substantially longer to start than it will subsequent times.(注意:第一次使用AVD来启动模拟器的时间会比较长,后续的启动速度会有所提升。)

再说技术问题。

前面只是解决了启动模拟器的问题,接下来就是要在模拟器中实际地加载新应用程序并进行测试。但是,我新创建了FirstApp应用程序,在通过Eclipse运行该项目时(也可以在命令行中使用ant构建项目,然后运行android命令,再启动模拟器;不过,这需要再下载其他软件包),提示出错,错误信息如下:

1. Project “FirstApp” is missing required source folder: ‘gen’
2. The project could not be built until buid path errors are resolved.

在网上搜索到几个解决方案(列在下面,供朋友们参考)。但奇怪的是,在刚搜索到第一个方案时,还没等到采取任何措施,Eclipse中的错误居然自动消失了(FirstApp项目下方的红叉也不见了),再Run as Android Application,一切正常了。我想,也许正如第三个方案中某人所说的,Eclipse并不能实时检测到OS文件系统的变化(编译项目时,会生成新文件),这也许就是导致这个技术问题的原因——至于是不是这个原因,还有待于进一步求证。

一、右击项目,选择preferences->builder,在右边的configure一栏中将Android Packege Builder一项提到Java Builer之前
出处:http://www.androidin.net/bbs/thread-708-11-1.html

二、将Eclipse自动生成的R.java删掉,刷新项目,R.java便会重新生成
出处:http://www.blogjava.net/crazycoding/archive/2010/03/27/316701.html

三、在项目文件夹中新创建一个Java类或者直接修改自动生成的类文件
出处:http://www.coderanch.com/t/466092/Android/Mobile/android-eclipse

以下是几个人的回复,感觉这种讨论的技术氛围很不错。今天太晚了,明天天亮还要去平谷,回来再翻译。

James Dixon的回复
Hi Divya
I’ve had the same problem as well. I think the issue is that the project creation does not initiate a build when it finishes, so you need to make a change, and save for it to generate the gen folder.
For me creating a new java class seemed to do the trick, but I’d imagine just making a change to a file and saving should work too.

Robert F. Howard的回复
I just ran into this, too. I am following the example in Hello Android, which I assume is what the others in this thread were doing. James’s solution (editing the source file) worked for me, so thank you for that.
So your solution is good, but I don’t think I totally believe the diagnosis. The thing is, the directory actually did exist before I edited the file and rebuilt. This is my first time using Eclipse, and it’s very disappointing. The error message should specify the full path of the directory it wants, and then it should be possible to create the directory and re-build, but it doesn’t work until the source file is edited. It makes me wonder what is really going on inside Eclipse.

Tim Holloway的回复
This seems to be a small glitch courtesy of Eclipse’s distancing itself from the OS filesystem (which is why Eclipse has an explicit Refresh command).
The gen folder and the “R.java” file are built by one of the Android utilities. The Eclipse Android plugin invokes this app, but it doesn’t always know when it needs to. I have similar problems when I want to define a new resource ID. Since I can’t seem to get the GUI resource ID definer to enable itself, I just create new IDs in the resource files themselves. But unless I trigger the android resource generator, they don’t get inserted into “R.java”.
And you don’t want to manually insert into “R.java”, because when the resource compiler does fire off, your code mods will be overwritten.
One way to force the issue is to select the Project/Clean menu command. If you have the automatic build switched off, you’ll then have to initiate a build. Otherwise the clean will fire off the auto-build process.

在本文写作时,Android SDK的最新版本是2.1。现在,我们来看一看如何在Windows平台下构建Android 2.1开发环境。

先期需要下载的软件包如下:

1、JDK 1.6+
2、Android SDK 1.6
3、Android SDK Setup
4、Eclipse IDE for Java Developers

看到这些,可能心急的朋友会禁不住问:“不是要构建Android 2.1开发环境吗?怎么还要下载Android SDK 1.6而不是2.1呢?”

没错,是要讲怎么构建Android 2.1开发环境。但是,经过几次尝试,我发现直接下载安装Android SDK 2.0和2.1有问题。什么问题?简单地说,就是这两个最新版本的SDK包中都不包含adb.exe文件,无法在Eclipse中指定Android SDK的位置(也就意味着没法使用Eclipse来开发)。因此,这才走了一条曲线救国的道路;也许,正如我自己的尝试所证实的:Android SDK 2.0和2.1实际上都是升级包,而不是完整的开发包。我比较了一下,Android SDK 2.0和2.1的大小分别是76.6MB和77.3MB,而Android SDK 1.6的大小则是248MB,相差还是很悬殊的,这一点似乎也佐证了我的判断。但是,不管怎样,先下载Android SDK 1.6,然后再通过ADT(Android Developer Tools,Android开发人员工具)和Android SDK Setup程序来下载和更新Android SDK 2.0和2.1,是成功了。

闲话少说,言归正传。

首先,访问http://java.sun.com/javase/downloads/widget/jdk6.jsp
下载Java SE Development Kit 6u20(jdk-6u20-windows-i586.exe)
文件大小76.67 MB。

其次,访问http://dl.google.com/android/archives/android-sdk-windows-1.6_r1.zip
下载Android SDK 1.6(android-sdk-windows-1.6_r1.zip)
文件大小248M。

然后,访问http://dl.google.com/android/android-sdk_r04-windows.zip
下载Android SDK Setup(android-sdk_r04-windows.zip)
文件大小22MB。

最后,访问http://www.eclipse.org/downloads/
下载Eclipse IDE for Java Developers(eclipse-java-galileo-SR2-win32.zip)
文件大小92.7MB。

下载完成后,开始安装和配置。

第一步,安装和配置JDK。

下载后,双击运行jdk-6u20-windows-i586.exe,假设选择安装到C:\Java\jdk1.6.0_20目录下(当然,安装到默认路径下也没有问题)。安装完毕后,就是配置环境变量。步骤如下:

(1)设置JAVA路径

在“我的电脑”上点右键,选“属性”,打开“系统属性”对话框,点“高级”选项卡,再点“环境变量”按钮,在打开的对话框中的“系统变量”下方,点“新建”,然后在对话框中的“变量名”中填JAVA_HOME,在“变量值”中填C:\Java\jdk1.6.0_20,点“确定”。

(2)设置CLASS路径

再“新建”一个系统变量,在“变量名”中填CLASSPATH,在“变量值”中填.;%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar。
说明:最开始的.;中的.(点)表示当前路径,;(分号)是路径分隔符。接下来的%JAVA_HOME%引用的是前面刚创建的JAVA安装路径。

(3)设置PATH路径

PATH变量一般都有了,因此选中点“编辑”,然后在“变量值”后面加上;%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin,注意前面的分号。

这样,JDK就安装好。“开始->运行”,输入cmd,然后在命令行提示符中输入:java -version,应该能够看到java version “1.6.0_20″信息;JDK安装成功。

第二步,解压和配置Android SDK 1.6

将下载到的android-sdk-windows-1.6_r1.zip解压缩到C:\android-sdk-windows-1.6_r1目录中(解压到哪个目录都没有问题)。然后,配置环境变量。步骤如下:

(1)设置Android路径

重复第一步的(1),新建一个“系统变量”,在“变量名”中填Android_Home(大小写没有问题),在“变量值”加填C:\android-sdk-windows-1.6_r1。

(2)设置PATH路径

“编辑”PATH变量,在“变量值”后面加上;%Android_Home%\tools,注意前面的分号。

这样,Android SDK 1.6就安装好了。“开始->运行”,输入cmd,然后在命令行提示符中输入:android -help,应该能够看到帮助信息;Android SDK 1.6安装成功。

第三步,解压Eclipse,关联Android SDK,安装ADT

将下载到的eclipse-java-galileo-SR2-win32.zip解压缩到C:\eclipse,然后进入这个文件夹,双击eclipse.exe,启动Eclipse。

关联Adnroid SDK:菜单“Windows->Preferences”,打开Preferences对话框,点击Android,在右侧的Android Reference中,点SDK Location文本框右侧的Browse…按钮,找到C:\android-sdk-windows-1.6_r1,“确定”。

安装ADT:菜单“Help -> Install New Software…”,打开Install对话框,点击Add…按钮,添加站点(Add Site),在Name中填ADT,在Location中填https://dl-ssl.google.com/android/eclipse/。然后,下载安装ADT。

第四步,解压Android SDK Setup,下载更新Android SDK 2.0和2.1

将下载到的android-sdk_r04-windows.zip解压缩到C:\android-sdk-windows,然后进入这个文件夹,双击SDK Setup.exe,启动Android SDK and AVD Manager,选中左侧Settings项,然后在右侧面板选中Force https://… sources to be fetched using http://,然后选择Save & Apply。然后,参见这里的图解:

如何使用Android SDK Setup? http://www.android123.com.cn/zhongwensdk/366.html

我选择了所有需要更新的内容,包括:

  • Android SDK Tools, revision 5
  • Documentation for Android SDK, API 7, revision 1
  • SDK Platform Android 2.1, API 7 revision 1
  • Sapmles for SDK API 7, revision 1
  • SDK Platform Android 2.0.1, API 6, revision 1

耐心等待吧——注意,如果更新过程有提示,可能是因为你正在使用C:\android-sdk-windows-1.6_r1目录,或者杀毒软件不允许改写其中的文件,此时需要退出所有程序或暂时关闭杀毒软件。

一切顺利的话,到此Android 2.1开发环境(或者说,Android 1.6、2.0和2.1的开发环境)就构建好了。

附录:

Android开发包及相关软件下载地址
http://www.android123.com.cn/android_kit.html

鸣谢:http://www.android123.com.cn/

查看全文 »

Tags: , ,

译者按:3月17日,Joel Spolsky在他影响了全球数百万程序员的著名博客Joel on Software中发表了最后一篇文章Distributed Version Control is here to stay, baby。特翻译这篇文章,以为纪念。另外,推荐他的博客文集《软件随想录》(More Joel on Software中文版)。

Joel Spolsky is the founder and CEO of Fog Creek Software in New York City.

前不久,杰夫、我,还有埃里克一块参加Stack Overflow Podcast的在线聊天。哥几个针对版本控制问题,狠狠地发了一通牢骚。特别是大批特批了以MercurialGit为代表的、新潮的DVCS(Distributed Version Control System,分布式版本控制系统)。

聊天中,我说:“我觉得,用它们来做分支和合并更简单,恰恰说明了你的同事可能会做更多的分支和合并。结果呢,就是你会把自己绕进去,最后非晕菜不可。”

说实话,你们也猜得到,参加那种聊天活动,不需要事先准备什么,不过是几个人东拉西扯地闲聊天而已。既然是闲聊天嘛,就免不了说错话,或者用技术术语来说就是——犯错误。要么哪句话里有错误,要么出发点有错误,要么就是出发点和话里都有错误。但这一次,我犯了一个低级错误。就像草莓配比萨、辣椒配面包,属于那种低级得不能再低级的错误。

在这次聊天之前,我们团队已经切换到Mercurial很长时间了,但这次切换真的把我搞晕了,我不得不花钱请人替我check in代码(开个玩笑)。不过,有一段日子我确实不好过,因为我得记住几个关键的命令,想象着自己是在Subversion中使用它们,期待能看到熟悉的结果。可是,一旦碰到结果跟我想象得不一样,我就会大惑不解。为此,我经常得颠儿颠儿地跑到楼下大房间里,请教本杰明或者雅各布。

你猜我的团队怎么说,“哎,乔总,这‘水银果汁’[注1]太神了,我们打算用实际的产品代码来测试一下它。另外,还有,这一点更重要,我们发现了一个大市场,我们可以为它提供有偿技术支持和托管服务。”(Mercurial是基于GPL的自由软件,但有不少公司在决定使用什么之前,总会需要某种支持。)

我心里想,你们问我,我问谁?你们都知道,我在公司并不真正作主,因为“管理的职能就是提供支持”嘛。然后,他们就把所有6名实习生都组织起来,动手开发基于Mercurial的产品

真不能再拖下去了,我必须得尽快弄明白,所谓的“分布式版本控制”到底咋回事。免得我们公司的产品都上市开卖了,人家让我介绍产品,我自己都说不出个子丑寅卯来。那样的话,博客圈里又会有人跳出来,对我指手画脚,说我糟蹋好东西了(junking the sharp)。

于是,我学呀,学呀,最后终于闹明白了。今天,我想跟大家在这里分享一下。

在分布式版本控制系统中,所谓的“分布式”其实不是最关键的。

最关键的是在使用这些系统时,你时刻要想着“更改”,而不是“版本”。

我明白,这里边其实有几分“道可道,非常道”的意味。在使用传统的版本控制系统时,你会想:嗯,这是版本1,这是版本2,这是版本3。

而在使用分布式版本控制系统时,其实我不用想版本。我只要想,我做了这些更改,我又做了另一些更改。

程序模型”变了,“用户模型”也得跟着变。

在Subversion中,你可能会想,“要保证我的版本跟主版本随时一致”,或者“恢复到前一个版本”。

在Mercurial中,你会这样想,“看看雅各布的更改”,或者“我们先不用考虑那些更改”。

如果你在使用Mercurial时,心里想的是Subversion,多数情况下倒也问题不大;但是,万一出了问题,你就会找不着北、会不高兴,最后因为无计可施而恨上Mercurial。

可是,如果你能够解放思想,换一个角度来看版本控制,就能悟出管理“版本”与管理“变更”的差异所在。你会觉得豁然开朗,由衷地感叹这才是控制版本的最佳方式。

没错,是有点异样的感觉——从1972年至今,所有人关注的都是怎么管理版本,而今天,人们突然要去关注更改本身了,能不感觉异样吗?而且,关注更改解决了一个非常重要的问题:合并分支代码。

这一点最重要了。没错,在长达10年的时间里,我们深刻地体会到,这一点对提高开发效率最为重要。重要到了什么程度呢?重要到在我今天最后一次谈软件时,必须要反复强调它。好了,如果你只想记住一句话,那就记住下面这句:

在管理更改而非管理版本时,合并很容易做到,你可以根据工作需要随时创建分支,因为合并已经是小菜一碟了。

记不清有多少个使用Subversion的用户,曾对我说过下面这番话:“用它创建分支代码的时候,没什么问题。但是,等到要把分支合并到一块时,那个费劲啊,我们不得不手工重新应用每一次更改。我们发誓,这种蠢事一辈子也不会再干了。结果,我们想出了一个开发软件的新主意,就是用if语句,不用分支。”

有时候,他们在提到自己发明的这种一个主干的做法时,甚至还有几分得意。好像弥补了自己版本控制工具的不足,就可以流芳百世了。

使用分布式版本控制系统,合并简单,还不会出错。所以,你可以创建一个稳定的分支、一个开发分支,还可以为QA团队创建一个长期使用的分支,以便在实际部署之前进行测试。当然,还可以创建一个临时分支,用它来验证各种想法,观察结果。

这一点太重要了,怎么强调它都不算过分。自从我10年前开始写博客以来,这恐怕是我笔下的软件开发技术领域中最大的进步了。

或者,可以换一种说法,如果我要放弃Mercurial,除非是我想再使用C++。

如果你还在使用Subversion,停止使用。马上停止使用。Subversion=水蛭。Mercurial=抗生素。我们现在有更好的技术了。

很多人在没有完全理解这种新程序模型的情况下,往往会盲目地使用Mercurial,而这容易让人觉得它有问题,不可靠。为此,我专门写了一套Mercurial教程,叫做HgInit[注2]

如今,要是有人问我那次聊DVCS时为什么要贬低DVCS,我会告诉他们那是我精心设计一个圈套,我是在放烟雾弹,目的是要迷惑我的老朋友和老竞争对手埃里克——他在开发一个非分布式的版本控制系统。就像上一次他要卖bug追踪软件一样。那一次,为了惩罚他,我们用一个特制的信封寄给他一个非常值钱的Fog Creek双肩背包。让他觉得我们会在圣诞节的时候,也会把这么值钱的背包作为圣诞礼物,送给所有FogBugz软件的客户。

我的博客写到今天,时间已经够长了。10年来,大家能够坚持阅读我写的文章,是我莫大的荣幸。这个博客的读者群能达到今天这个规模,是我当初做梦也想不到的。无论你是谁,是花自己的时间把我的文章翻译成40多种语言的那几百位志愿者中的一员,是给我写过电子邮件的22 894位朋友中的一位,是订阅了我的邮件简报的50 838名订阅者之一,还是每年2 262 384位访问这个站点并阅读了我写的1 067篇文章中哪怕只言片语的读者中的一位,我都要由衷地感谢你,感谢你对我的关注。