Chinese (Simplified)

From The Joel on Software Translation Project

Jump to: navigation, search

Contents

开发人员、市场及销售人员

(第二稿)

作者:周思博

译者:Ren Yufei

原作日期:2010年2月11日

当你的科技公司在早期成长过程中,你会打算有很多软件开发人员,并且可能觉得永远没个够。如果你过早的雇佣销售和市场人员,而他们实际上没有多少作用,那么你可能认为雇佣了销售和市场就是在浪费时间。早些年,这使我认为一个好的软件公司需要的是许多真正的软件开发人员,而并不是销售和市场人员。

我曾经一度持有一个堂吉诃德式的、愚蠢的想法:要求每个Fog Creek的员工都是程序员…即使是前台小姐都必须具有合格的BASIC编程经验。在美国海军服役的每一个人也必须会耍枪,即使他只是厨师。当然,这是因为厨师在阿富汗可能中枪,所以他们最好会耍枪,然而,我们的前台小姐永远不会沉浸于代码中并且匆匆构造一个类。永远也不会这样。

时光如水,随着你的产品变得越来越好,你雇佣的销售和市场人员越多,你就卖的越多。

那是因为销售额依赖于程序员与销售人员的能力乘积,反之亦然。

我只是个书呆子,因此我对此感觉非常神奇。假设你的软件质量可以用介于0和1之间的刻度来衡量。

0代表你的产品没有为任何人解决任何问题,所以没有人会掏钱买它。比如微软的BOB产品。(BOB是微软上世纪90年代的一款失败的产品,详见[[1]])

1代表这个星球上的每个人,如果她买了你的软件,那么她将得到纯粹的快乐,即使她为此付钞票了。

你的软件从0开始,并且慢慢地往上爬。

如果这个世界上的每个人都知道你的软件,并且鼓励他们对你的软件估价,那么可能会掏钱买软件的人数为地球上的人数与软件质量的乘积。

销售和市场人员的作用在于鼓励地球人都知道你的软件并且对它有个估价。如果软件质量过低,那么销售和市场人员就对销售额也就无能为力了。但是当软件质量提高了以后,销售和市场人员的价值也会相应的提高。在同等的市场投入的情况下,软件质量翻倍可以使销售额翻倍。

地球的人口数量实在庞大,销售和市场人员的影响很难评估,当你的产品足够伟大的时候,程序员和销售人员的最佳比率可能很容易向市场和销售人员倾斜。大规模软件公司的销售和市场人员可能是开发人员的5倍、10倍,甚至20倍。

这就解释了为什么美国的软件公司不能指望持续的利用去人力成本便宜的国家进行离岸外包软件开发来降低公司的运营成本。如果俄罗斯、印度、中国等国的开发人员工资水平仅为西雅图、旧金山、波士顿地区工资水平的50%,而你的产品开发成本仅占了你的公司运营成本的10%,那么离岸软件开发只能使你获得5%成本缩减。只有当进行客户化软件开发的时候,即为某个特定人的需求进行设计,离岸软件开发才是有用的,因为这时候需要的是更多的开发人员而非市场和销售。

市场无法替代代码质量(书呆子坚信市场可以替代代码)。世界上最牛叉的市场永远无法强迫人们去为没用的产品付钱。

易用的界面,简单的一步

( 第一稿 )


作者:周思博

译者:Shao Fan

原作日期:2006年3月9日


在飞机控制的设计中,糟糕的可用性会致使飞机发生CFIT:可控飞行撞地。

可能可用性在你的产品中不是那么关键。如果幸运的话,你在可用性设计中的错误可能只会使人失去四肢,或甚至只是拇指。没什么更糟的了。

事实上,如果极端幸运,那么糟糕的可用性设计除了会使人难受,没有其他后果。用户试着去做一些事情,或者失败,或者挣扎着去用,很直接的后果就是他们会为此感到不悦。在将来的文章里,我会讲讲此事在心理上的原因,但现在,这样说就足够了:使用户不悦的原因,很可能并非完全如你所想。

可用性,确实是一个“好”设计的核心。在将来,我会花很多时间来讲述这个问题。

好消息是:我可以很轻松地教你关于可用性设计的话题。让我们开始吧:

当一件东西能够以被期待的方式运行,那它就是易用的。

就是这样!这就是关于可用性的一切!像Hillel所说,其它的一切都是解说词。

让我们来看一个简单的例子。


哪个更好用:Windows还是Mac?


在为人们设计产品时,有一个假想用户是很有帮助的。所设想的用户越是实际,提供的帮助越大。

我的假想用户就是彼特。

有一天,彼特的朋友,吉娜叫他来帮忙。吉娜有一台Macintosh的iBook,因为她喜欢白色的电脑。当彼特坐下开始试着用吉娜的Macintosh时,他很快就感到有点沮丧了。“我讨厌这些东西,”他说。虽然最后成功地帮吉娜解决了问题,他却觉得高兴不起来。“Macintosh的用户界面真是笨拙至极。”

笨拙?为什么会这样说呢?每个人都知道,Macintosh有着优雅易用的用户界面,对不对?难道它不是那种易用性的范例吗?

好吧。让我们来看看。

在Macintosh上,如果你想改变窗口的大小,你必须拖它的右下角。而在Windows上,在任何一个边上拖动鼠标,都可以改变窗口大小。当彼特帮吉娜时,他试着拖右侧的边来让窗口变宽。结果,整个窗口都跟着动了,而不是他想要的“改变大小”。

在Windows上,当出现一个消息框时,你只要按tab键移动焦点到所需的按钮上,然后按一下空格键就可以按到那个按钮。但在Mac上,空格键不起那样的作用。当彼特得到一个警告,他就试着像他过去六年里下意识的做的那样,按空格键来关掉消息框。第一次,机器没有任何反应,他以为是键盘有问题,于是更大力地又按了一次。结果还是一样。最后他只能用鼠标了。这是另一个小小的挫折。

彼特还习惯用Alt+F4来关闭窗口。在Mac上,这恰恰是用来调整声音音量的。这次,彼特想点击桌面上的IE图标,而这个图标刚好被另一个窗口遮住了一部份。于是他按Alt+F4关闭窗口的同时立即双击图标所在的位置。结果是声音音量变大了,而窗口并未被关掉。而他的双击点在了他想关掉的那个窗口的帮助按钮上,把帮助窗口打开了。好了,他现在需要关闭两个窗口了。

这也是一个小小的挫折吧,但是,这确实让彼特更加郁闷了。这天结束的时候,彼特的脾气很不好。他试着控制那些东西,却都没有反应。空格键和Alt+F4都“不起作用”----就像它们坏了一样。窗口也不听话,连调整大小都不行。真差劲。就算这些想法都是下意识的,这些“失去控制”的细微感受也最终使他感到不快。“我还是喜欢我自己的电脑”,彼特想,“它被我设置的完美无缺,总能按照我想的方式去运行。而这些Mac真是难用。真是让人不爽。如果Apple这些年多花些心思在MacOS上,而不是搞iPod那些玩意,他们的操作系统也不会这么糟糕了。”

好了。我们比彼特清楚。他虽然有这些种种感受,但事实上对Mac用户来说,Mac确实很好用。完全可以用任意键来关闭窗口。微软的程序员很可能觉得,让用户拖动任意边都可以调整窗口大小的功能真的很不错。而Apple程序员很可能认为,拖动任意边来移动窗口位置的功能很有创意。

那些盲目信仰某种OS的网站上的关于用户界面的争论,都没有说到点子上。Windows更好,是因为给你更多手段来调整窗口大小。那又怎样?这并不是问题所在。真正的问题是,UI是否以用户预期的方式来响应他们的操作。如果不是,那么用户就会觉得他们无法控制它,并觉得自己会难以达成目的。就是这样了。当一件东西能够以被期待的方式运行,那它就是易用的。你可以把这句话反着纹在你的额头上,这样你在镜子里就可以看到它。

如果你继续关注将来的文章,那么你会发现,我所告诉你的关于可用性设计的一切,都可以追溯到这个简单的法则。如果哪天外星人在你的花园里着陆,把你扔到了名叫Kij8zxwrk的星球,在那里你无法连接到地球的互联网,因为数据包传送到地球所花时间太长导致TCP/IP无法正常工作,那么你所知道的东西也足以让你找到一份相当体面的可用性设计师的工作了。

主次分明

2005年10月12日 周思博

我们总算要结束调整FogBugz 4.0而开始开发FogBugz实行5.0了. 我们刚发行了挺大的更新,修复了成千上万的从没人注意过的小错误(当然也加入了几个没人会注意的新的小错误). 现在我们要开发一些超越时代的新功能了.

当我们准备就绪开发5.0的时候,我们已经准备了足够的点子让1700个程序员忙上个几十年. 很可惜,我们只用3个程序员,预定的发行日期又是明年秋天,所以我们一定要分分主次,区分优先.

在我告诉你我们怎么区分优先之前,我先得告诉你两个错误的方法:

第一,如果你发现自己加入一个新功能的唯一的原因是你答应过一个客户,你脑子里立刻得亮起红灯. 如果你只是为了一个客户而操劳,要么你有个说话不家思索的推销员,要么你慢慢的已经变成了咨询服务了.咨询服务没什么不好,也可以过好日子,只是咨询服务没卖包装软件赚的那么多.

包装软件的特色就是要就要,不要就不要.你开发了一个软件,包装起来,客户要么买,要么不买.他们不会讨价说再加一个功能就买. 你不会打电话个微软说:”我很喜欢EXCEL里面能够自动的输出泰文的数字的功能,可不可以弄个英文版的?”. 你如果这么问了,他们会回答:”谢谢你给微软打电话,你如果是广告咨询;按1.如果要技术咨询,按2;如果你想要注册咨询,按3; 如果你知道你想找的人的分机号码,按4.从头开始,按星号.” 看到了吗? 他们根本不给你选择要加一个新的功能.

个人化的开发就是一个客户告诉你加入什么功能, 你说:”你确定要吗?”;他们回答:”确定的”;你立刻写了一个很漂亮的开发计划,问他们:”这样可以吗?”,他们说:”可以的”. 你让他们在合约上签名,或者画个血书,他们也干. 然后你开始完全按着计划一步步的开发,可成品出来他们却大吃一惊.之后一个星期你得和公司律师商量是否有足够的法律保护和这客户打官司,或者就和客户私了了. 运气好的话,你的客户很好说话,他们把这新的东西藏到抽屉里,再也不会拿出来用; 当然他们再也不会当你的客户了.

个人化的软件和包装软件之间还有咨询软件. 咨询软件貌似包装软件,可只给一个客户用. 咨询软件的特色是:

1) 你超级廉价的给一个皮鞋厂写软件.

2) 那皮鞋厂需要一个擦皮鞋的软件.

3) 你用VB 3.0写了个擦皮鞋的软件. 当然中间也加了点JavaScript, 一点Franz Lisip和一个连在一个旧的MAC上的File Maker的数据库.

4) 每个人都有创建自己软件公司,成为下一个Bill Gates或者Larry Ellison的梦想.

5) 你从公司买下了” 擦皮鞋1.0”的版权,找到了几个投资人,创建了”擦鞋软件公司”,

6) 可惜的是没有一个BETA测试人可以运行你的软件,那源程序真是太复杂了.每个客户都得花上你一个月的时间来安装和调试.

7) 你的软件又贵,又有很多千奇百怪的要求,所以你也没什么客户.

8) 你开始给你的销售部门加压.

9) 你的销售部门发现擦皮鞋的软件现在不流行了,不过有一个客户想要一个烫裤子的软件.

10) 销售部门立刻和他签了100,000美元的和约.

11) 你又花了6个月的时间改写” 擦皮鞋1.0”,让它支持烫裤子的功能.

12) 当然了,没有其他客户需要这个新功能.

13) 归根到底,你花了一年的时间成为了那个烫裤子公司的廉价劳动力.

14) 回到(1)

个人来讲,我是强力推荐你只开发包装软件. 卖包装软件给一个新的用户对你来讲没什么额外的开支. 你只是把同样的东西一次次的卖出去,然后赚取利润. 因为客户多了,你可以减低价钱; 而价钱越低,客户也就越多. 大家的日子都很好过.

所以说如果你花时间为一个客户加入什么新功能的话,你基本上就是离开了包装软件而进入个人化的开发和咨询软件的地域了. 当然了,如果你喜好那样,也没什么不对. 只是不管怎样,放在货架上的包装软件是最赚钱的.

我不是说你不该听你客户的意见. 我就认为微软早该把那个自动输出泰文的功能普及到其他文字了.全世界不说泰文的可不少人呢. 也许你认为你应该把开发资源放在让你最大的客户身上; 说到底他们钱最多吗. 可你最终会发现你大多客户和你最大的客户需求不一样. 对Arizona州里一些小客户来讲,自动输出泰文的功能跟本和他们没关系. 帮最大客户开发只和他们有关的东西只有让负责那个客户的销售经理出风头而已.

这条路是不会让你成为Bill Gates的.

好了,现在让我告诉你第二种错误的方法. 不要因为你避不开了才去开发某个功能. “避不开了”不是一个足够好的理由.

在我刚开始Fog Creek的时候,有一天我在整理文件的时候发现蓝色的文件夹用完了. 我整理文件有个系统, 蓝色的文件夹是和客户有关的; 乳白色的是职工的; 红色的是收据; 其他都是黄色的.那天,蓝色的用完了.

我对自己说,蓝色的文件夹总是需要的,我顺便去Staples买一些吧.

真是浪费时间!

我常找借口给花园除草, 补补墙上的洞, 按颜色,语言,号码整理MSDN的光盘. 我可是个刚开始的小公司的人啊,我所有的时间应该就是编写程序和卖我们的产品. 换句话讲,我自欺欺人的告诉自己那些浪费时间的事情也很重要.所以我就主次不分的把那些事情给先做了.

说实话,我只是在拖延时间啊.

我该怎么做呢? 第一,我根本不用按颜色来选文件夹,那真的没什么用. 还有那些MSDN的光盘,找个大盒子装一下就好了.

最主要的是我该认识到重要不是二分的,重要是一种程度,有很多不同的级别.如果你每件事都想做,你什么也做不成.

每日构建(daily build)是你的朋友

作者: 周思博 (Joel Spolsky) 译: Chen Bin 2001年1月27日


1982年,我家定购了IBM的PC机(IBM生产的最早的个人计算机,是现代流行的标准化的个人计算机的祖宗)。我们家可能是以色列最早拥有这种PC机的几个家庭之一。当时我们跑到了仓库等着电脑从港口运过来。事实上,我说服我爸购买的是带有全套附属设备的个人计算机(译者按:有些现在很便宜的附属设备,那时候都是非常昂贵的),这些附属设备包括两个软盘驱动器,128K内存,一个针式点阵打印机(用来快速打印草稿)和一个运转起来发出机关枪扫射声音的兄弟牌的雏菊轮式打印机(译者按:原文为Daisy Wheel printer,是一种已经淘汰的打印机,原理类似于老式的机械打字机,可以产生清晰的英文字符)。附属的软件也很齐全,PC-DOS 1.0(最早的PC操作系统),75美元的参考书册,包括BIOS的完整源代码。 一个汇编语言编译器(Macro Assembler),非常棒的IBM单色显示器,可以显示80列宽的字符,而且支持小写字母显示。整套配置大概花了10000美元。这些钱包括以色列的荒谬的进口税。呵呵,那时候我家可真舍得花钱啊!

因为当时“每个人”都知道BASIC是给小孩玩的语言,用这种语言只能使你写出非结构化的垃圾代码,然后你的的脑子也会被这种语言变成Camembert产的奶酪(Camembert cheese,法国的一种奶酪,实心,圆饼状,灰色,有一个拳头大小)。所以我们又花了600美元买了一个IBM公司PASCAL语言开发包,需要3张软盘才装的下。PASCAL编译器运行分别需要第一号软盘,和第二号软盘,PASCAL链接器需要第三号软盘。我写了一个简单的输出文字“你好,世界”程序然后编译链接这个程序,总共花了8分钟。

嗯,8分钟好像太长了。我写了一个脚本程序来自动化整个过程,把时间缩减为7.5分钟。这样好一点了。但是我想设计一个可以玩奥赛罗的程序。(译者按:奥赛罗原文为Othello,一种棋类游戏,规则见http://www.ugateways.com/bof4.html )这个游戏总是能打动我。我不得不花很多时间等待编译器编译我的程序。“就是这样的,”一个专业程序员告诉我,“我们通常在办公室里房放上sit-up board(译者按:一种健身器材,可以在上面做仰卧起坐或者有氧操什么的) ,当PASCAL编译器开始运行时,我们就开始锻炼。我这样编程了几个月后,我的身材不要太棒喔!”

后来有一天,丹麦程序员写了一个很灵的叫做Compas Pascal的程序。Philippe Kahn(Borland公司的创始人)买下了它,更名为Borland Turbo Pascal。Turbo Pascal好得简直难以想象,因为它能做IBM Pascal能做的所有事情,但是只要33K内存。而且还额外提供一个编辑器。 这还不是最棒的。最棒的是编译一个小程序只需要不到一秒。这就好比一个你从来没有听说过的公司生产了通用公司别克轿车的克隆版,这种克隆车可以每小时行驶一百万英里,但是只消耗了一滴汽油。一只小小的蚂蚁喝下这点汽油也不会撑死。

突然,我的编程效率变得高的多了

那时我开始明白了“REP循环”(Rep loop)这个概念. REP是“读入,求值,打印(Read, Eval, Print)”的缩写。这个概念解释了Lisp(一种编程语言,用于人工智能)解释器的基本原理:它“读入”你的输入,计算你的输入得到结果,打印结果。下面给一个例子:我输入一些东西,Lisp解释器计算,然后输出结果。


在一个稍微大点的规模上,当你写代码时,你也处于一个REP循环的宏版本中,这个循环就是“编码-编译-测试”。你编写代码,把代码编译成可执行的文件,然后测试它,看一下运行起来怎么样。

关键一点是当你写一个程序时,你的工作过程是循环的。一个循环所花时间越短,你的生产力就越高,当然最短时间不会小于编译器运行的时间。 这就是一个程序员为什么总是要一个真正够快的硬件而编译器开发者们总是不断使他们的编译器运行更快的正式的纯计算机科学角度的原因。Visual Basic的办法是当你输入代码时,它就开始进行代码的语法解析,这样程序解释运行时速度很快。Visual C++的办法是增量编译(incremental compiles),预编译头文件(precompiled headers)和增量链接(incremental linking)。

但是一个大型的团队有多个开发人员和测试人员,你碰到了同样的循环,可能不同点就是有更多的文档要写(可是这还只是草稿,天哪!)。一个测试人员发现了bug并报告,然后开发人员修复了这个bug。那么测试人员得到修正后的代码需要多少时间?在一些软件开发机构,这样的报告-修正-再测试循环(Report-Fix-Retest loop)可能需要几个礼拜。如果一个循环需要这么长的时间,通常意味着该机构生产力很低。想让整个开发过程运转得更平滑一点,你必须想方设法使得报告-修正-再测试循环(Report-Fix-Retest loop)花的时间更少。

一个好的办法是每日构建(daily builds)。 每日构建意味着自动地,每天,完整地构建整个代码树、(译者按:“代码树”,原文为source tree,意思是将整个项目源代码的目录,子目录,文件的位置尽可能事先固定下来,这样在开发过程中各个模块间,各个文件间的相对位置都不会混乱。源代码树指的就是一个项目所有的已经组织好的代码文件。通常代码树应该用版本控制软件管理起来。虽然这个概念很基本,但是据我的观察,国内还是有软件公司在这方面做的不够好的,所以有必要解释一下。)

自动地 - 因为你设定代码每天在固定的时间构建。在Unix环境下使用cron,在windows下使用“任务计划”。

每天 - 或者更频繁. 当然每天构建的次数越多越好啦。但是有时候构建次数还是有上限的,原因和版本控制有关系,等会儿我会谈到的。

完整地 -很可能你的代码有多个版本。多语言版本,多操作系统版本,或者高端低端版本。每日构建(daily build)需要构建所有这些版本。并且每个文件都需要从头编译,而不是使用编译器的不完美的增量编译功能。

以下是每日构建(daily build)能带来的好处:

当一个bug被修正了,测试者可以很快得到最新的修正后的版本开始重新测试,以验证bug是否真正地被修复了。 开发人员可以更加确定他们对代码做的修改不会破坏1024个操作系统上的任何一个版本。验证这一点不需要在他们的机器上安装OS/2(IBM公司生产的PC机操作系统)。 那些每天将修改过的代码导入(check in)版本控制服务器的开发人员知道,他们对一个模块导入的修改不会拖别的开发人员的后腿。拖后腿的意思是,那些开发别的模块的程序员使用这个修改过的模块,出了问题,于是他们自己的模块也没有办法开发下去了。每日构建则不会有人拖后腿。如果把一个开发团队比作一台PC机,那么团队中的一个程序员对某个模块的修改导致其他人无法开发别的模块,相当于PC机发生了蓝屏。当一个程序员忘记把他(她)新建立的文件导入到repository(指版本控制服务器上的代码树)时,这种开发过程中的“蓝屏”会经常发生。因为在这个程序员自己的计算机上有这个文件,所以他(她)构建 这个程序没有问题。但是其他程序员是从版本控制服务器上导出(check out)代码的,由于服务器上没有这个文件,他们遇到了链接错误(link error),无法继续工作了。 外部团队(例如市场销售部门,进行beta测试的一些客户)可以获得一个比较稳定的版本,这样对他们开展自己的工作比较有利。 假如你将每日构建出的二进制文件(例如一个可执行程序,一个dll等等)存档管理,那么当你发现一个非常奇怪的,无法解决的bug时,你可以通过对这些文件进行二进制搜索(binary search)来确定什么时候这个bug第一次出现。如果有对代码进行了完善的版本控制,你也可以找出是谁在何时对代码进行的导入(check in)导致了这个bug。 当开发者修正了测试者报告的一个错误时,如果测试者同时报告了发现错误时的构建的版本,开发人员可以直接在那个版本中测试是否bug真正被修复了。(译者按:测试者报告出现了一个bug,只是报告了一个错误症状,而错误的原因可能有多个,每个原因可能在不同的模块中。前文中的方法是为了避免只修正了一个模块中一个原因,别的模块由于在变动,于是掩盖了而不是修复了bug) 以下是如何进行每日构建(daily build)的具体步骤。你需要用最快的电脑建立一个每日构建服务器。写一个脚本,可以自动从版本控制服务器中导出(check out)完整的代码,(你当然使用版本控制,不是吗?),然后对代码从头开始进行构建(build),要构建所有的版本。如果你有一个安装打包程序,也要在脚本中自动运行。所有会卖给最终用户的东西都要包括在构建过程中。把构建出来的版本放在各自的的目录里,不同时间构建的相同版本也应该按日期整理好,不要相互覆盖。每天固定的时间运行这样的脚本。

最关键的是所有这些步骤都应该由脚本自动化完成,从导出(check out)代码到将最终产品放在网上供用户下载(当然在开发阶段,产品是放在一台测试服务器上的)。要保证开发过程中的任何东西的任何记录是由文档记录的而不是由某个人的脑子来记录的,这是唯一的办法。否则你会碰到这样的情况,产品需要发布了,可是只有Shaniqua知道如何将产品打包的,可是他刚刚被巴士撞了。在Juno公司(本文作者工作过的公司之一),要进行每日构建,你唯一需要学会的东西就是双击每日构建服务器桌面上的一个快捷方式。 如果你在发行程序的当天发现了一个小bug,没有问题。修正它,然后重新运行每日构建脚本,现在你可以安安心心的发行程序了。当然,黄金定律是每日构建脚本应该是把所有的事情从头做一遍,遵循这个定律就不会有什么问题。 将你的编译器的警告参数设到最大(在微软的VC中是-W4 ; 在GCC中是-Wall),当遇到任何一个最微小的警告时就应该停下来。 如果每日构建失败了,可能整个开发团队的工作会因此进行不下去。当务之急是立刻找出原因,使得每日构建能成功进行下去。某天也许你会一天运行好几次每日构建脚本的。 每日构建一旦失败,应该自动地将失败用email通知整个团队。提取错误日志中的恰当部分并包括在email正文中也不是很难。每日构建脚本也可以将当前的状态报告整理成一个html文件,自动发布到一个所有人都可以访问的web服务器上,这样测试者可以很快知道那个版本的构建是成功的。 当我在微软的excel团队中工作时,我们的一个有效办法是,谁导致每日构建(daily build)失败,他(她)就得负责照看当日的每日构建(译者按:微软通常每日构建都在半夜),直到有另一个人导致构建失败而接替他(她)。这样做当然可以使每个开发者都小心不要因为自己代码的错误破坏了构建,更重要的是团队中的每个人都可以学会每日构建(daily build)的原理。 如果你的团队在同一个时区工作,在午饭时间进行每日构建(daily build)是个不错的主意。午饭前每个程序员导入(check in)代码,这样当程序员在吃饭时,构建系统在工作。当程序员吃完饭回来时,如果每日构建失败了,所有的人也都在,可以尽快找出失败的原因。当构建系统运作起来时,没有人再会担心别人导入(check in)代码会妨碍自己的工作了。. 如果你的团队同时在两个时区工作,计划好每日构建(daily build)的时间使得一个时区的工作不会影响另一个时区的工作。在Juno公司,纽约程序员在晚上7:00导入(check in)到版本控制服务器。如果他们的导入导致构建失败,印度Hyderabad市(译者按:印度科技重镇)的程序员在纽约时间晚上8:00以后的工作几乎无法进行下去。我们每天进行两次每日构建(daily build),每次构建的时间都在两地的程序员回家之前,这下就没有问题了。 更进一步的阅读:

一些关于每日构建工具的讨论 做每日构建是很重要的,它是 获得高质量代码的12个步骤之一。 Windows NT team G. Pascal Zachary关于微软Windows NT团队每周构建的书中有一些很有趣的东西。超级明星(译者按:原文为showstopper,指特别受人喜爱,杰出之人或之物). Steve McConnell(译者按:著名的软件工程作家,Win2000开发组总负责人,其名著《Writing Solid Code》,《Debugging the Development Process》都有中文译本。) 写的关于每日构建(daily build)的文章在这里.


本文最先用英文出版,题为 Daily Builds Are Your Friend

第四战略篇:膨胀软件与80/20的谣传

作者: 周思博 (Joel Spolsky) 译: Bo Yang 编辑: Wenjing Jiang 2001年3月23日


1993年,微软公司的电子表格软件Excel 5.0出版了。它是一个巨大的软件,需要15兆的硬盘空间。当年我们还记得最早上市(1985年左右)的PC硬盘只有20兆,所以15兆显得很多。


等到Excel 2000出版的时候,它竟需要146兆的硬盘空间,几乎增长到1993年的十倍!微软公司的程序员真是差劲,对不对?


不对。


我敢打赌,你以为我要写一篇令人厌烦的,批评膨胀软件的文章。这种文章因特网上到处都是。批一批,怨一怨,这些庞大臃肿的软件,令我讨厌,还是vi和edlin比Microsoft Word与Emacs强多了,因为前两者很小巧灵活...


哈哈,把你蒙了!我才不会去写一篇那样的文章呢,因为那种说法根本不对。


1993年,根据当时硬盘的价格,Microsoft Excel 5.0占用了$36元的硬盘空间。


2000年,根据当时硬盘的价格,Microsoft Excel 2000占用了$1.03元的硬盘空间。


(这些数字是根据此处的硬盘历史价格数据计算的,以把通货膨胀的效果算进去了。)


从实际经济角度出发,Excel好像变小了!


说真格的,什么叫膨胀软件?Jargon File把它嘲贬地定义为:“提供最低等的功能,同时占用不成比例的磁盘与内存空间的软件。特别是形容应用软件与操作系统升级来用的。此词在Windows/NT上是常见的,Windows/NT也是它的来源。”


我猜这帮人只不过是恨Windows而已。自从虚拟内存在Windows 386(1989年)上出现后,我已经有十多年没有把内存用完过了。再说硬盘价格已经降到$0.0071元一兆,而且越降越快。



也许Linus Åkerlund能把这个问题解释清楚。他在他的网页 上写道:“这些膨胀软件的一个大缺点,就是即使你只想干一件很小的事,你也要负载这个很大的程序。它把你的内存全用掉了…你不是很有效地利用你的系统。它毫无必要地把你系统的效率弄得很低。”



我明白了,原来它把你的内存都用完了。嗯,不对。自从Windows 1.0在1988年出版以后,操作系统只把用到的代码页放在内存中。如果你有一个15兆的可执行文件,但运行时只用到两兆的代码页,操作系统就只把这两兆从磁盘装入内存中。而且如果你用的是比较现代版的Windows的话,操作系统还会自动调整硬盘,把这两兆代码页放在一起,使程序起动得更快。




我想没有人会否定,在今天强大而便宜的计算机上,起动一个大程序比仅仅五年前起动一个小程序还要快。那么那些人在瞎叫唤什么呢?



RA Downes给了我们一个提示。看起来他花了几个钟头,把Microsoft的一个小程序研究了一通,而且因为这个程序有一兆大小,令他十分气愤(他写那篇文章,一兆硬盘只值3.15分)。以他看来,那个程序应该小下去95%才对。可笑的是,他研究的那个程序叫做RegClean,你很可能没听说过。它的作用,是把Windows registry中没用的东西找出来删掉。如果你整天为Windows registry中没用的东西担心的话,你性格上很可能有为事物着迷,难以克制的弱点。所以我怀疑批判膨胀软件是精神病 的体现,不是软件问题。




实际上讲,膨胀软件的存在是有道理的。最起码的,如果程序员不用担心软件的大小,那么软件就可以早点出版。用户可以早点得到更多的功能。这些功能用时有益,不用时无害。假如你的软件商在出版软件之前,花两个月的时间,把它的软件缩小50%,这对你的实际好处来说,几乎是感觉不到。也许,你的硬盘要是快满了的话,你可以多下载一首MP3歌曲。可是你多花两个月的时间,等新软件出版的损失,你就感觉得到了。而且你的软件商会丢掉两个月的销售额,损失更大。





很多搞软件开发的人,被"80/20"的老规律引诱了。这个规律好像很有道理:80%的人只用20%的功能。所以你以为,只要实现20%的功能,就能得到80%的销售量。



不幸的是,那从不是同样的20%。每个人都用到不同的功能。再过去十年中,我大概听说过几十家公司,下定决心不互相吸取教训,企图出版“轻形”版本,只有20%的功能的文字处理软件。大多数情况是,他们把软件送到记者哪里去评论,那些记者评论的方法,就是用这个新的文字处理软件去写他们的评论文章。文章写完了,记者就要用到“字数”这个功能了,因为大多数记者写文章时有明确的字数限制。可是“字数”这个功能在软件里却找不到,因为它是属于“没人用的80%”里面。结果记者就会写一篇文章,一方面说着这个“轻形” 软件怎么怎么好,膨胀软件怎么怎么糟,另一方面又说我不能用这个软件,因为它没有“字数”这个功能。而且这种文章 经常有人写。





当你去推销你的“轻形” 软件时,你跟人家说:“嗨,这个软件很小巧,只有一兆。” 人家听了一般都很高兴,然后就会问你有没有对于他们来说很重要的功能,要是没有,就不会买你的软件。


基本概要是:如果你的战略是“80/20”,你就很难卖出你的软件。事实就是这样。这个战略自从软件工业开始时就有,从来没有胜利过。令人吃惊的是,很多倒闭了的公司的高级主管还觉得它是个好的主意。


Jamie Zawinski 在讨论改变世界的首版Netscape时讲得最好:“Mozilla [Netscape 1.0]很大并不是因为里面全是没用的东西(如果真是那样,解释起来倒很方便)。Mozilla很大,是因为你的需要很大。你的需要很大,是因为因特网是个很大的东西。网上有很多小型的浏览器,说起来基本上是没用的。我们当初写Mozilla的时候,从未想把它做成一颗完美无缺的明珠。”



本文最先用英文出版,题为 Strategy Letter IV: Bloatware and the 80/20 Myth

行进中开火

作者: 周思博 (Joel Spolsky) 译: Siyan Li 李思延 编辑: Paul May 梅普華 2002年1月6日


时不时,总有一阵儿,我什么事也干不了。

我也去办公厅,东瞄瞄,西看看,每十秒钟查一次电子邮件,网上逛一圈。也许干点儿象付运通卡账单之类不需要大脑的事。不过要回去哗啦哗啦写程序,可没门儿。


这种不出活的状态,一般通常会持续一两天。在我的软件开发生涯中也有过几个星期干不了活的时候。就像他们说的,我不在状态,我进入不了情况,我找不到组织。

人人都有情绪波动,有的人温和一些,有的响动大点儿,也有的可以整个乱套。但不管怎么着,那段不出活期似乎总是跟忧郁有点儿关系。

我不由得联想到那些专家说,人们基本上控制不了自己吃什么。任何节食计划都长不了。大家总是悠回各自的正常体重。也许作为一个软件工程师,我也不能控制什么时候最能出活。我唯一希望的就是发呆那段能被哗哗干活那段扯平,最终还能混碗饭吃。



自从我干上软件开发这一行起,我平均每天只有两三个的高效时间。这真让我头大。我在微软实习的时候,另外一个实习生告诉我,他每天12点上班,5点下班。5个钟头还包括午餐时间,但他的同事还对他特别满意。因为他干的活比一般人都多。其实我也一样。我每天只有两三个小时的高效时间。看着别人那么卖力的干,还有点不好意思。不过呢,我总是组里出活最多的。由此可见,“人件理论”和极限编程都坚持不加班,每周只干40小时,还是有点道理的。他们都清楚这么做不会降低一个小组的生产能力。

每天只能干两小时还没让我太担心,真让我担心的是完全干不了活的那些天。

我老想这是怎么回事儿。我努力回忆我出活最多的时候。估计是微软把我搬到一间漂亮的新办公室的时候。舒适豪华的办公室,窗外风景如画,窗对面樱桃花开满了石头堆砌的庭院。所有的一切都那么恰到好处。我马不停蹄地干好好几个月,一口气把Excel Basic的详细设计搞定。用象纪念碑那么高的一叠纸,详细描素了一个超大型目标模型和编程环境,工作之细致,令人难以置信。我自始至终就没停过手。去波士顿参加MacWorld I的时候,我都带着一台手提电脑,坐在哈佛商学院的大阳台上把Windows类别的所有文件都写完了。

按步就班并不难。通常我一天是这样度过的:1,去上班。2,查电子邮件和上网等等。 3,考虑是否应该吃完中饭在开始干活。4,吃完中饭回来。5,查电子邮件逛网。6,终于决定应该开始工作了。7,查电子邮件逛网,东瞄瞄,西看看。8,再次决定确实应该开始开始干活了。9,打开该死的编辑器。10,一直会些程序学到晚上7:30,写到忘记时间。

在以上第8步和第9步之间似乎有点缺陷,因为我不是每次都能顺利地执行下去。

对我来说,启动是唯一的难题。静止物体在不受外力作用的情况下会保持静止。大脑里有些物质的质量大得不可思议,让它加速太难了。但是只要速度上去了,在全速行使的情况下,倒不用使什么劲就能继续走下去。就象骑着自行车去作一次自费横穿美国的旅行,一开始,你根本想象不出要花那么多时间让车轮动起来,可是一旦动起来了,让它们继续转就不是一件很难的事了。

也许高效率的关键就:启动起来。配对编程法之所以成功,说不定就靠两个人在一起,互相强迫对方启动起来。

我在以色烈当伞兵时,一次,有个将军来给我们讲实战战术。他告诉我们,步兵战术其实只有一种:行进中开火。你一边开火一边朝着敌人冲过去,火力让敌人抬不起头来,不能朝你开火 (当一个军人喊:“掩护我”的时候,他的意思就是“在我冲过街时候,你朝敌人猛烈开火,迫使他猫起来,没法朝我开火)。前进了,你就可以占领阵地,接近敌人,这样你的胜算要大的多。你要是不往前冲,敌人就有时间来搞清楚形势,这可不妙。你要是不开火,敌人就要朝你开火,撂倒你。

我很长一段时间都在想着这个教导。我想通了不论是战斗机空中格斗还是大规模舰队攻击,大部份军事战略战术都是以行进中开火作为基础的。我又化了十五年时间才想通了行进中开火也是一个人在现实生活中成功的基本原则。你每天都得往前进点儿,不用想你写的程序怎么差劲,怎么卖不出去,只要你不停地写,不停地改,滴水也能穿石。同时, 要注意你的竞争对手朝你开火。他们是不是想让你全心全意应付他们的扫射,好让你往前走不了呢?

想想这些年来,微软开发出来的资料存取方法,从OBDC,RDO,DAO,ADO,OLEDB直到现在的 ADO,.NET,不停翻新,技术上有必要吗?还是因为那个设计组实在蹩脚,每过他妈一年就得重新发明一遍资料存取技术?(实际上可能真是)。它最终的效果其实是一道掩护火力,让竞争者别无选择,只能把本来该用来开发新功能的宝贵时间都用来移植和升级了。仔细看看软件行业,干得好的公司对那些对大公司都依赖最少,不用把所有精力都用来为赶潮流而把程序重写一遍,还得修改那些只有在Windows XP上才会出现的缺陷。那些花太多时间去猜测微软未来发展方向的公司,日子都好过不了。有些人见了.NET就发怵,忍不住要按.NET来完全重建自己的体系结构,以为自己别无选择。哥门儿,看清楚了,微软是在朝你开火呢,而且这只是掩护火力。这游戏就是这么玩儿的。这样一来,他们就可以大步朝前走,而你却不能。你要支持Hailstorm 吗?SOAP呢?还有RDF?是因为你的顾客需要,所以你支持它们?还是因为有人朝你开火而你觉得应该还击?大公司的营销部都懂火力掩护。他们到客人那儿就说,“你们不一定非买我们的。谁的产品最好您就应该买谁的。不过,我们想提醒您,在下单之前最好先确认他们支持(XML/ SOAP/CDE/J2EE)。否则你们就会被他们的技术套牢。”。等到小公司去向这个客户推销的时候,那个听话的CTO就会问他们:“你们有J2EE吗?”。他们回去就只好不管卖不卖得掉,都埋头打造他们的J2EE。他们也就再没有机会来展示自己的特色了。其实,这只不过是个打勾功能。因为有个打勾拦在那儿空着,你就必须有这个功能。其实谁都不需要它。这就是火力掩护。

对于我这样的小公司来说,行进中开火意味着两件事。别跟时间过不去,同时你还得每天都进步。天不负苦心人,你终有出头的一天。我昨天花了一天时间只不过让FogBUGZ的颜色稍微好看点。这不要紧,只要不停步。最重要的是,我们的软件越来越好,客人越来越多。在我们达到Oracle 的规模之前,我们并不需要通盘战略。我们只需要每天早晨到办公室来,别多想,打开编程器。



本文最先用英文出版,题为 Fire and Motion

看起来简单, 实际上复杂

作者: 周思博 (Joel Spolsky) 译: Bo Yang 翻译 编辑: Billy Chen 编校 2002年3月4日


我们在CityDesk里有一个使用性上的小问题。



问题是这样的:你可以用菜单上“导入网页”的命令,从因特网上导入一个文件。你也可以用鼠标拖放的方法,从磁盘上导入一个文件。但是菜单上没有“导入磁盘文件”这个命令,所以有些用户没有发现CityDesk 有这个功能,或者他们试图用“导入网页”这个命令去导入磁盘上的文件,结果造成无法成功导入。



我一开始想这个问题很好解决,大概的方法就是用一个两个页面的文件导入向导。第一页问你:“你要从哪里导入?”。如果你选择“磁盘”,第二页就会提示你选一个文件;你要是选择“因特网”,第二页就会提示你输入一个URL.



我差点就开始动手去实现我这个想法了,但是有些事情使得我并没有这样做。我决定先写一个小的规约再说。写出来的规约如下:


第一页

你要从哪里导入?

磁盘/因特网


第二页(磁盘)

标准的打开文件对话框


第二页(因特网)

用小浏览器让你输入一个URL


突然间我想到一个问题。Windows的打开文件的对话框,通常是由操作系统提供的。能不能把这个对话框放到我的文件导入向导里面呢?



嗯…


我查了一下。是可以这样做的,但这不是一件好玩的事,而且要花好几个小时的时间。我能不能不使用导入向导的方式呢?我重写了一下我的规约:


两个菜单项:

1)从网上导入网页 -> 显示URL输入对话框

2)从磁盘上导入网页–> 显示打开文件对话框


这就好多了。三分钟的设计时间,省了我几个小时的编程序时间。


如果你这辈子花了二十分钟以上的时间去编软件代码的话,你就可能发现了一条规则:事情没有看起来那么简单。


就像拷贝文件这样简单的事,都充满了危险。如果第一个参数是个目录会如何?如果第二个参数是个文件会如何?如果同名的文件已经存在于目的子目录会如何?如果你没有写的权限又会如何?



如果在拷贝文件的过程中失败了怎么办?如果目的地是在一个远程计算机上,但是需要身份验证怎么办?如果文件很大但网络连接又慢,所以你需要显示一个进度条怎么办?如果文件传输速度降到几乎是零了,你什么时候放弃拷贝而给用户一个错误信息呢?




一个面试测试员的好办法,就是给他们一个简单的操作过程,然后让他们列出可能出现的错误情况。一个在Microsoft面试时典型的问题就是:你怎样去测试打开文件对话框呢?一个好的测试员,可以轻而易举地列出几十个令人难以想到的情况去测试(比如“一个文件显示在对话框里,然后你去打开它,但是在你按打开的按钮之前,这个文件被另一个用户删除了”)。



好,我们得到这样一个公理:事情没有看起来那么简单。


软件工程里还有一个指导思想,那就是你要永远想方设法去减低风险性。一个要特别小心去避免的风险,就是项目进度延期的风险。项目延期很不好,因为老板会训你,闹得你挺不高兴的。除此之外,这也存在经济方面的原因,那就是当初你决定给你的软件加某个功能的时候,你觉得这个功能只需要一个星期就能完成。现在你认识到该功能需要二十个星期才能完成,那么你当初的决定当然就是错的。如果你当初就知道需要花掉二十个星期的话,你可能就作出不同的决定了。你作出的错误决定越多,你公司的财产被一次性冲销处理的可能性就越大(甚至你们公司的标志会被收入债权人的仓库)。到时候你的前老板抱怨道:“我们公司关门倒闭了不说,气人的是连上fuckedcompany的资格都没有。”





事情没有看起来那么简单,再加上减低风险性的指导思想,只能让你得出如下的结论:



先设计再编程序,先思而后行。



让你失望了,很抱歉。我知道你读过Kent Beck的书,所以你以为动手之前不做设计是可以的。对不起,那是不可以的。你修改程序不可能像修改设计文件那样“容易”。有些人总是发表这样的谬论:“我们现在用高级工具了,像Java和XML。 我们在几分钟之内,就可以改动程序里的很多东西。为什么不在程序里直接设计呢?”哥们儿,你可以在你自行车上加个发动机,但你不能把它变成汽车。如果你以为把你拷贝文件的程序,由线程式改为抢占式,而且改得比我写这句话还快,那你就大错特错了。




不管怎么说,我不认为Extreme Programming是在鼓吹零设计的理念。他们只是说:“不要作任何无必要的设计”,这没有什么错嘛。但人们听到的并不是这样。大多数程序员是在找不用设计的借口,所以他们像飞蛾扑火般投向“不用设计” 这个馊主意。这是一种奇怪的,让你事倍功半的懒惰方式。我懒得先在纸上把这个功能给设计好了,所以我就先写程序,然后发现不对,我就去改,结果反倒花更多的时间。或者,更经常发生的是,我先写些程序,发现它不对,但是没时间改了,结果我的产品质量低劣,而且我还是要找出些借口,说明它为什么“一定要那样“。那只不过是马虎潦草,缺乏职业精神。


Linus Torvalds攻击设计的时候,他是在讲那些规模庞大的系统。大规模的系统必须慢慢进化,要不然它们就变成Multics了。他不是在说你那个拷贝文件的程序。你再想想,Linus Torvalds脑子里有一个很清楚的路线图,知道他要到哪去,所以他觉得设计没什么用,也不足为奇。但不要上当,基本上说那对你不适用。Linus Torvalds比我们聪明多了,所以他能干的事,不等于我们一般人也能干。渐增式设计及实现是好事。频繁地发布版本是可以的(但针对在大众市场上的软件来说,频繁发布版本会使用户不高兴,绝不是个好主意——可以多搞些内部的里程碑取而代之)。设计上不要拘泥于形式,那只是浪费时间。我从来没有见过某个项目得益于不动脑筋的流程图、UML、CRC,或者其他什么时髦的,花里呼哨的设计方法。至于那些Linus Torvalds说的系统,那些有一千万行代码程序的庞然大物,它们应该慢慢进化,因为人类还不知道怎样设计那种规模的软件。


但是当你坐下来写你的拷贝文件的程序,或者计划给你的软件下个版本增添功能的时候,你一定要先作设计。不要让报急的号角使你草草动手。



给计算机系学生的建议

作者: 周思博 (Joel Spolsky)

译: Chen Bin 2005年1月2日

Edited By XiaQ on 2007-4-1

虽然大约一两年前我还在夸夸其谈桌面应用程序是将来的潮流,大学生们现在还是偶尔向我请教职业发展的问题。所以我把我的建议写下来。以供学生们阅读,嘲笑,忽略。

大多数锐气十足的学生从来不向前辈征求意见。在计算机科学领域,这样做是正确的。因为前辈们很可能说些“在2010年前,市场对于那些只会敲击键盘的代码工人的需求将会超过一亿(因此前景是乐观的)”,或者诸如“Lisp语言现在真的很热门”。

我和那些前辈也差不多,当我给别人建议时,实际上我不知道自己在说些什么。我是如此的落后于时尚,以至于连AIM也搞不明白,而不得不使用 email(恐龙时代的产品,在那个时代,音乐是刻在扁扁的的圆圆的盒子上,噢,那种盒子叫cd)。(译者按:我认为Joel这里在说反话,后文很多地方作者都在说反话,读者尽量理解这种美国式幽默吧。)

所以你最好不要理睬我将要说的,你应该立刻去制作某种在线交友软件

然而,CA1.jpg

如果你喜欢编程,那就感谢上帝吧:你属于极少数的幸运儿,这些人喜欢工作,他们的工作可以保证他们能过上舒适的生活。大多数人没有这么幸运。对大多数人来说,工作是不愉快的,忍受工作的目的攒钱,是为了在年满65岁退休后能过上自己想过的生活。如果他们想过的生活不需要灵活的膝盖,明亮的眼镜,轻盈的脚步的话。

现在让我回到主题,我将提供一些建议。

好了,不罗嗦了,下面就是Joel给计算机系学生们七条免费的建议:

毕业前学会写作 毕业前学会C语言 毕业前学习微观经济学(microeconomics) 不要因为某些非计算机课程枯燥无趣就敬而远之 学习有大量编程实践的课程 不要担心工作都跑到印度去了 好好做夏季毕业实习 让我逐条解释这些建议。但解释之前我要说明一下,如果因为这些建议是Joel的建议你就打算无条件地接受,以至于连我的理由都想跳过,那么你就太单纯,太容易被别人骗了。如果你是那种单纯的人,我还要给你第八条建议,找心理医生咨询一下如何培养自信(self-esteem)。

毕业前学会写作

如果Linus Torvalds不懂如何布道的话,Linux会成功吗? 正像每一个黑客,Linus精通写作,他知道如何准确地在email和邮件讨论组中使用书面英语表达自己的思想,所以他能够从全世界召集大量志愿者为Linux工作。

你听说过最近风靡全世界的极限编程(Extreme Programming)吗? 即使你不懂什么是极限编程,你至少听说过这个词。为什么?因为宣传极限编程的人都是天才的作者和演说家。

就看看你身边的那些小型的软件开发组织吧,最有权力和影响力的人是那些可以用自信,准确,舒适的英语交流的人。好吧,我承认这些人也许言过其实,但是你无可奈何。

一个合格的程序员和一个伟大的程序员的区别不在于知道多少种编程语言,不在于他们是喜欢Python或者Java,而是在于他们是否擅长表达。他们能够说服别人,所以他们获得权力。他们能够写清楚明白的评论和接口文档,所以他们使得别人不用重写CA2.jpg而可以重用他们的代码,否则他们的代码就是毫无用处的。他们也能够写出清晰的用户手册,于是最终用户可以理解他们的代码是做什么用的,明白了他们的工作的价值。sourceforge埋葬着许多精美的代码,这些已死的代码无人使用,因为代码的作者很少写(或者根本不写)用户手册。

我不会雇佣一个不懂写作的程序员。如果你擅长写作,你就很容易找到工作,紧接着你就会被要求写技术规格文档,这意味着你已经被管理层注意到了。

大学里有一些课程,要求你做很多的写作练习,不要犹豫,赶快参加这些课程。不要错过任何要求你每周或者每天练习写作的课程。

给自己建立一个网络日志(weblog)。在上面写得越多,你会写得越容易。写得越容易,你就写得越多,这是一个良性的循环激励。

毕业前学会C语言 我可没有说是C++。虽然现在用C的工作不多,但是掌握各种编程语言的程序员事实上用C来交流(lingua franca);更重要的是,C比某些“现代”语言更接近机器语言。我不管现在大学里在教什么流行的垃圾语言(trendy junk),你至少得花一个学期接近机器。否则,你不可能使用高级语言写出高效的代码。这意味这你不会有机会写编译器或者操作系统(也许这是更好的编程工作);别人不会相信你能够为大项目设计架构。无论你知道多少高级的控制结构,知道如何进行错误处理,如果你不能解释为什么while (*s++ = *t++);的意思是进行字符串拷贝(而且对你而言这是世界上最自然,最易懂的代码),那么你就是在对编程一窍不通的状态下编程(programming based on superstition)。打个比方,就好比一个医生不懂基本的解剖学就给你开处方,如果你问这个医生为什么开这种药而不是那种药,他会说因为医药销售代表说这种药有用。

毕业前学习微观经济学(microeconomics)

我个人对经济学的一些理解:在经济学刚诞生的时候,它只是局限于有限的领域,在这些领域中人们发展和发现了很多有用的理论和很有趣的事实,这些理论和事实是从逻辑上是可以证明的。然后, CA3.jpg经济学开始走下坡路了。 “有限的领域”就是微观经济学,它对于商业可以进行有意义的指导。然后,事情就开始变糟了(以下部分你可以跳过),你接下来碰到的是讨论诸如失业率和银行利率之间关系之类东东的宏观经济学,很多时候宏观经济学讨论的理论都是无法证明正确或者错误的。接下来事态更加恶化了,经济学中的一些领域开始和物理学搭界,嗯,学习物理经济学也许你帮你在华尔街找到好工作。言归正传,无论如何请学习微观经济学,因为你需要知道什么是“供给和需求”,什么是竞争优势,什么是净现值(NPVs,Net Present Value,指项目经济寿命期内现金流入总和与现金流出总和之差额),什么是折扣和边际效用(discounting and marginal utility),如果你真想了解商业是如何运作的话。

为什么计算机系的学生要学习经济学?因为理解商业基本规律的程序员对商业界来说是宝贵的程序员。我记得无数个程序员使我非常沮丧——因为他们在代码中坚持某些疯狂的设计,而这些设计从技术上来说,完美;从资本主义的角度来看,发疯。如果你是一个理解商业的程序员,商业会给你回报。这就是你要学习经济学的原因。

不要因为某些非计算机课程枯燥无趣就敬而远之

首先,你需要让你的学分平均分(GPA)看起来漂亮点。

不要低估学分平均分的威力。很多雇主和人事经理(包括我)阅读简历时首先看成绩。为什么?因为这代表了大部分的教授在很长的时期内对你的学业的一个平均的看法。托福成绩(美国的托福大致相对于我国的高考中的语文考试)?哈,几个小时的测验而已。当然学分不一定说明了一切,如果你修的是很难的课程,学分就有可能低一点。即使你的学分平均分很高,我还是要看各科分数是否一致。如果你应聘的是软件工程师职位,我为什么要关心你在大学里学的欧洲历史课程分数的高低呢?毕竟,历史很枯燥。那么要是你要编程的部分也是很枯燥的,你是不是要放弃了?事实上,有时候编程是枯燥的,如果你不能忍受编程中的枯燥部分的话,你就不能完成整个工作,雇主不愿意雇佣你这样的员工。

我在大学里修过一门叫做“文化人类学”的课程,因为那时候我也搞不懂我到底要学什么,听起来这么课程可能还蛮有意思的。CA4.jpg

出乎我的意料。我不得不阅读大量讲述巴西热带雨林中的印第安人如何如何的书,让人真昏昏欲睡。听老师讲解也好不到哪去,我发觉看教室外的草如何长更有趣点。土著人如何烤蕃薯藤和我有什么关系?我为什么要去讨论如何烤蕃薯藤?但是期中考试马上就要到了,我暗暗下定决心,如果我能跨越“文化人类学”这个障碍,以后也许没有什么能难倒我了。我决心得A并且得到了A。以后当我不得不坐在林肯中心,连看18个小时的瓦格纳的《尼伯龙根的指环》时,我终于明白我为什么要学习“文化人类学”了,相比之下,我也能忍受这种歌剧了。

学习有大量编程实践的课程

我还记得决定不去读研究生的那一刻。

就是在学习《动态逻辑》(Dynamic Logic)这门课的时候,我记得是耶鲁的Lenore Zuck(一个天才的教师)教的。

修这门课的时候,我已经不再是雄心勃勃了。我可不指望在这么课程中得个A,我梦想的是混个及格。逻辑本质上是很简单的:如果结论正确,前提必须正确。例如,如果“所有读书好的人都能找到工作”并且“张三的读书好”,那么“张三能够找到好工作”。就这么简单。

但是我要学的是动态逻辑, 动态逻辑和一般逻辑差不多,但是要考虑时间因素。例如,“在你开灯之后,你可以看见你的鞋子”加上“过去灯被打开了”意味着“你现在可以看到你的鞋子”。

动态逻辑学对于象Zuck教授这样的天才理论家来说非常诱人,因为这门学科的知识也许可以用来证明计算机程序是否正确。我记得在第一堂课上,为了证明“如果你有一盏关着的灯”并且“你按了一下开关”,那么“现在灯亮了”,Zuck教授就使用了两黑板加上边上的墙壁。

证明过程难以置信地复杂。我觉得如此复杂的证明过程很可能会有小错误,但是我没办法证明证明过程本身是正确的。事实上,写在黑板上的证明跳过了很多中间步骤,许多步的证明使用了演绎法,使用了归纳法,以及一些研究生才懂的证明方法。

作为课后作业,我们需要证明以下命题:如果灯过去是关着的,并且现在它是开着的,请证明有人按了开关。

我真的试着证明它了。

我花了许多小时,试图证明这个命题。

在无数个小时的努力后,我发觉Zuck博士的原始的证明有一个逻辑上的错误,也许这个错误是我的笔记抄错了,我不知道。于是我终于认识到,如果为了证明一个简单的问题需要花三个小时写下几黑板的证明步骤,再考虑到这个漫长的证明过程中可能会引入种种错误,那么这种机制是不可能用来证明任何有趣的东西的。

对动态逻辑学家来说,有用是无关紧要的。

于是我退出了那门课程,发誓永远不会去读计算机系的研究生。

这个故事的主题是,计算机科学和软件开发不一样。如果你非常非常幸运,你的学校会开软件开发的课程。然而,他们也可能不开这样的课程,因为名牌大学认为教授实用技巧的事情应该留给那些二三流的技术学院或者某些释放犯人再安置计划。你可以在任何地方学习编程,我们是耶鲁大学,我们培养未来的世界领导人。你付给耶鲁16万美元的学费就是为了学习如何写循环语句吗?你把耶鲁当成什么地方了?Java速成班吗?哼。

问题在于,我们没有一个专业的学校教授软件开发。所以如果你想成为一个程序员,你可以进计算机系读书(当然计算机科学也值得学习),但是你学的不是软件开发。

如果走运的话,你可以在计算机系发掘出很多有大量编程实践的课程,就像你能在历史系找到很多提供写作水平的课程一样。这些课程绝对值得学习。如果你喜欢编程,不要为你不能上教授诸如lambda算子或者线性代数的课程沮丧,在那里你连摸一下计算机的机会都没有。找找看有没有名字中带有“实习(Practicum)”字样的课程。不要在乎Practicum是个拉丁语。有用的(无奈状)课程就是需要在课程名中塞一些拉丁语,才能从那些装模作样(Liberal Artsy Fartsy)管理层的眼前蒙混过关。

不要担心工作都跑到印度去了

啊哈,如果你人在印度,你就无所谓了。愿你享受外包带来的工作机会并顺祝身体健康。

但是我听说现在愿意读计算机系的学生越来越少了。据说原因之一是工作机会都跑到印度去了。我认为这种观点是大错特错。首先,根据眼前的商业时尚选择事业是非常愚蠢的。其次,即使工作真的都跑到印度和中国去了,编程对于其他有趣的工作来说都是极好的训练,例如业务流程工程(business process engineering)。第三,无论是在美国还是印度,好程序员仍然是非常短缺的,请相信我。当然,现在有许多所谓搞IT的人吵吵嚷嚷地说就业形势不好,工作太难找。但是事实如何?恕我直言,好程序员找工作还是很容易。第四,你还有更好的主意吗?历史系的毕业生找工作更容易吗?去法学院如何?据我所知,99%的律师恨他们的工作,每分钟都恨。而且律师一周工作90小时。正象我以前说过的,如果你喜欢计算机,那么感谢上帝,你将属于全世界人中的极少数的幸运儿,这些幸运儿热爱他们的工作,而且工作也可以提供体面的收入。

实际上,我认为报考计算机系的人越来越少,这没有多大的意义。相对于internet泡沫时期大家都疯狂的往计算机系挤,现在的人数回落只是回归正常水平而已。在泡沫时期,我们这个行业涌入了许多对计算机毫无兴趣的南郭先生,他们梦想的是拿着高的吓人的薪水加诱人的期权,然后年轻退休。谢天谢地,现在这些人都跑了。

好好做夏季毕业实习

明智的招聘者知道热爱编程的人初中就为当地的牙医写数据库程序,高中就在计算机夏令营教课,为校报规划网站,在某个软件公司做实习。他们找的就是这样的人。

如果你喜欢编程,你最容易犯的最大的错误就是“有活就接”。我知道,其他专业的学生假期打工可顾不了这些条条框框。CA5.jpg但是你不一样,你拥有一种特殊技能,不要浪费它。当你毕业时,你的简历上应该已经罗列一堆的编程工作实习。让其他人去“为大家提供租车服务”(Tom Welling是个例外,他业余时间去演超人)。

最后,为了让你的生活更容易一点,也为了说明我这篇文章是能够自圆其说的,我将给我自己的公司的做做广告。我的公司Fog Creek软件公司,可以为大学生提供软件开发方面的实习机会。在我们公司,你可以学习“编码、开发、商业”。去年在我们公司实习的Ben就是这么说的,可不是因为我给他什么好处他才这么说。二月一号截至,抓紧机会吧。

如果你听了我的建议,你就会太早地卖掉Microsoft公司的股票,拒绝Google提供的职位,原因是因为你已经拥有自己的公司了。到时候可别后悔,更别怪我,呵呵。

本文最先用英文出版,题为 Advice for Computer Science College Students

轻松面试找到理想员工-非官方的面试技术指南

作者: 周思博 (Joel Spolsky) 译: Chen Bin 编辑: Rick Ju 2000年3月23日


雇佣合适的人对于Fog Creek软件公司来说是非常关键的。在我们这个领域,有三类人可以挑选。在一个极端, 是哪些混进来的, 甚至缺乏最基本的工作技巧. 只要问这类人两三个简单的问题,再读一下他们的简历,就可以轻易地剔除他们。另一个极端的类型是 [[才华横溢的超级明星] http://joel.spolsky.com/] 这些人仅仅为了好玩就用汇编语言为Palm Pilot(一种手掌电脑)写了一个Lisp(一种人工智能编程语言)编译器。在这两种极端类型中间的是一大群不能确定水平的候选者,也许他们中的某些人能干些什么?这里的关键是明白超级明星和那一大堆属于中间类型的人的区别,因为Fog Creek软件公司只雇佣超级明星。下面我要介绍一些找出超级明星的技巧。

Fog Creek公司最重要的雇佣标准是:

有头脑, 并且 完成工作

就是这些了。符合这样标准的人就是我们公司需要的员工了。 记住这条标准。 每天上床前背诵这条标准。我们公司的目标之一就是雇佣拥有这样的潜质的人,而不是雇佣懂某些技术的人。任何人所拥有的某些具体技术都会在几年内过时,所以,雇佣有能力学习新技术的人,要比雇佣那些只在这一分钟知道SQL编程是怎么回事的人对公司更划算一点。

有头脑确实是一个很难定义的品质。但是让我们看一些在面试时能提问的一些问题,通过这些提问,我们可以找出拥有这种品质的人。完成工作非常关键。看起来有头脑但是不能完成工作的人经常拥有博士学位,在大公司工作过,但是在公司中没有人听他们的建议,因为他们是完全脱离实际的。比起准时交活儿,他们宁愿对于一些学院派的东西沉思。这些人由以下特性而可以识别出来。他们总是爱指出两个根本不同的概念间的相似性。例如,他们会说“Spreadsheets是一种特殊的编程语言”,然后花一个礼拜写一篇动人的,智慧的白皮书。这篇白皮书论述了,作为一个编程语言,spreadsheet关于计算语言特性的方方面面。聪明,但是没用。

现在,我们来谈谈完成工作但是没有头脑的人。他们爱做蠢事。从来也没有考虑过将来得靠他们自己或者别的什么人来亡羊补牢。通过制造新的工作,他们成为了公司的负债而不是资产。因为他们不仅没有为公司贡献价值,还浪费了好员工的时间。这些人通常到处粘贴大堆的代码,而不愿意写子程序。他们是完成了工作,但是不是以最聪明的方式完成工作。

面试时最重要的法则是:

做决定

在面试结束时,对于被面试者,你不得不做一个直截了当的决定。这个决定只有两个结果:雇佣或者不雇佣. 回到你的电脑前,立刻用电子邮件通知招聘负责人你的决定。电子邮件的主题应该是雇佣或者不雇佣。接着你需要在正文中写两段来支持你的决定.

没有其他的答案。永远不要说,“雇佣你,但是不能在我的团队中”。这是非常粗鲁的,因为你在暗示应试者没有聪明到能有和你一起工作的资格,但是以他的头脑适合进入那些天生输家队伍。如果你发觉自己被诱惑,想说出那句“雇佣你,但是不能在我的队伍中”,那么就简单的把这句话变成“不雇佣”再说出口。这样就没事了。甚至如果某个人在特定领域很能干,但是在别的队伍中将会表现不好,也是不雇佣。事物变化的如此之快,我们需要的是在任何地方都能成功的人。如果某些情况下你发现了一个白痴专家(拥有某些特殊能力的白痴),这个专家对于SQL非常,非常,非常的精通,但是除此之外什么也学不会,不雇佣。在Fog Creek公司他们没有将来。

永远不要说,“也许,我吃不准”。如果你吃不准,意味着不雇佣。看,比你想象的容易的多。吃不准?就说不!同样,如果你不能作出决定,那意味着不雇佣。不要说,”嗯,雇佣,我想是这样的。但是关于...,我想知道 ...”。这种情况就是不雇佣。

最重要的是记住这点,放弃一个可能的好人要比招进一个坏人强(译者按:中国有位哲人说过,宁可错杀一千,不可放过一个,呵呵)。一个不合格的求职者如果进入了公司,将要消耗公司大量的金钱和精力。其他优秀员工的还要浪费时间来修复这个人的错误。如果现在你还在犹豫,不雇佣。

如果你是Fog Creek公司的面试官,当你拒绝了大量的应聘者时,不要为Fog Creek公司将因此雇不到任何人了而忧虑。这不是你的问题。这是招聘负责人的问题。这是人力资源部的问题。这是Joel(译者注: Fog Creek公司的老板,本文作者)的问题。但不是你的问题。不停地问自己,哪种情况更糟糕?一种情况是我们变成了一个庞大的,糟糕的软件公司,充斥着许多脑袋空空如可可果壳的家伙,另一种情况是我们是一个小而高品质的公司。当然,找到优秀的应聘者(并聘用他们)是很重要的。找到有头脑而且完成工作的人是公司中的每个员工的日常工作之一。但是当你作为Joel Creek公司的一员真的开始面试一个应聘者时,要装作现在正有很多优秀的人想打破头挤进Fog Creek公司。总之,无论找到一个不错的应聘者是多么的难,永远不要降低你的标准。

但是你如何作出雇佣或者不雇佣这样艰难的决定?你只要在面试过程中不停地问自己:这个人有头脑吗?这个人能完成工作吗?要作出正确的回答,在面试时你必须问对问题。

开个玩笑,下面我要问个有史以来最差的面试问题: “Oracle 8i中的数据类型varchar和varchar2有什么区别”这是一个可怕的问题。掌握这种琐碎的技术细节和Fog Creek公司想雇佣你之间没有任何联系。谁会去记这种东西?如果有在线帮助,你可以在15秒内找到答案。

实际上,还有更差的问题,等会儿我会谈到的。

现在我们要谈到有趣的部分了:面试时提哪些问题。我的面试问题清单来自于我去微软公司找第一份工作的经历。这里实际上有几百个微软面试问题。每个人都有偏爱的问题。你也可以发展一套自己的面试问题以及面试的个人风格,这样你就可以比较容易地作出雇佣/不雇佣的决定。以下是我成功使用过的一些面试技巧,

在面试前,我读一遍应试者的简历,然后在一张纸片上随便写以下我的面试计划。这个计划实际上就是我要问的问题清单。以下是一个例子(用来面试程序员的):

介绍 应试者参加过的项目 无法回答的问题 C语言函数 你满意吗? 设计问题 挑战 你还有什么问题? 在面试前,我非常,非常当心,避免自己先入为主。如果在面试前你就已经想当然地认为,一个麻省理工的博士一定是一个有头脑的人。那么在接下来的一小时的面试时间内,无论那个麻省理工的博士说什么都不能改变你的最初印象。如果在面试前你就认为这个应试者是个傻瓜,那么他面试时说什么也无济于事。面试就象一个非常精巧的天平。一小时的面试结束后就要对一个人下结论是不容易的(但是你又必须在面试结束后得出结论)。一些不起眼的细节可能会影响最后的结论。如果你在面试开始前对于应试者有了一点了解的话,就好比天平的某一端加上了重重的砝码。这样面试本身就会变得没有用处了。以前有一次在面试前,一个招聘负责人跑进我的房间说,“你肯定会爱上这个家伙的!" 对一个男孩? 天哪,这简直让我发疯。我本来应该说,“嗯,如果你这么确定我会喜欢他,为什么你不干脆雇佣他,何必让我浪费时间来面试?”但是那时我还太年轻幼稚, 所以还是面试了那个人。当这个家伙开始说一些蠢话时,我对自己说,“哇塞,这应该是个例外情况,也许是大智若愚。”我开始带着玫瑰色眼镜看他了。于是我以说“雇佣”结束了面试,虽然他是一个糟糕的面试者。接下来发生了什么事?除了我,其他的面试官都说,不要雇佣这个人。教训是,不要听别的人的话,在面试应试者前不要四处打探这个面试者的情况。最重要的是不要和别的面考官谈论应试者,除非你们都已经作出了独立的判断。这才是科学的做法。

作为面试步骤的第一步,介绍的目的是让应试者放轻松。我通常花30秒钟,讲一下我是谁,接下来面试会如何进行。我总是使得应试者确信,我们关心的是他(她)如何解决问题的,而不是他(她)的最终答案是对还是错。顺便说一下,面试时,你不要和应试者隔着一个桌子坐着,否则在你和面试者之间就有了一个障碍,并且暗示着一种比较正式严肃的气氛,这样应试者就很难放松了。更好的办法是把桌子靠墙放着,或者和应试者坐在桌子的同一边,这样有助于应试者放松。只有应试者不会因为紧张而表现失常,你才能更有效的进行面试.

第二步的内容就是问应试者最近做了些什么项目。对刚毕业的学生, 如果有论文就问问论文, 没有的话, 就问问他们做过什么很喜欢的大作业.例如,有时候我会问一下,“你最喜欢上学期哪门课程?不一定要和计算机相关的。”事实上,如果应试者回答的课程和计算机没有关系,我会比较高兴。有时候你会发现这个计算机系应届生选择了尽可能少的计算机相关课程,但是却选修了很多和音乐相关的课程。但是他(她)却说最喜欢的课程是《面向对象数据库》。哼哼,不错啊. 不过如果你直接承认你喜欢音乐胜于计算机, 而不是在这儿胡说八道的话, 我会更高兴一点。

当面试有工作经验的人时,你可以让他们谈一下前一份工作。

我问这个问题的目的是在寻找一样品质:热情。在应试者谈到他(她)最近做过的项目时,你观察到以下迹象都是不错的:

谈到他们做过的项目时变得热情洋溢;他们的语速更快,语言更生动活泼。这说明他们对某些东西有兴趣,有热情(因为现实中有许多人对所做的项目根本漠不关心呢)。即使他们激动地表达对做过的项目的负面感情,这也是一个好的信号。“我曾经为上一个老板安装Foo Bar Mark II,但他是个傻瓜!”表现出热情的人就是我们要雇佣的人。差的应试者对工作根本就不关心,所以根本不会激动。一个非常好的信号是当应试者很激动地谈论上一份工作,以至于暂时忘记了他们正在被面试。有时候应试者刚开始面试时表现的很紧张 -- 这是很正常的现象,所以我通常忽略不计。但是当他们谈到单色计算艺术(Computational Monochromatic Art)时,这个家伙变得极端兴奋, 一点都不紧张了。不错,我喜欢这样的应试者,因为他们关心他们做的事。(什么是单色计算艺术?拔掉你的电脑显示器的电源就可以看到了) 能认真地去解释事情。某些人被我拒掉的原因就是他们不会用普通人能明白的语言去解释他们做过的项目。很多工科专业的人总是以为所有人都知道Bates理论(译者注: Bates Theorem,一种经济学的理论)或者Peano公理组(译者注: Peano's Axioms,数论中的一些定理)是什么。如果应试者开始满口行话了,让他们停一停,然后你说,“能帮我个忙吗?就是为了练习一下,你能把刚才说的用我老祖母也能理解的话说一遍吗?”但即便如此, 有些人还是继续用那些术语, 而且根本没法让人明白他们在说什么。天哪! 如果这个项目是一个团队项目,看看他们是否在有承担领导责任的迹象?一个应试者可能会说:“我们用的是X方法,但是老板说应该是Y,而客户说应该是Z。”我会问,“那么你怎么做的?”一个好的回答可能是“我设法和团队中别的人开了个会,然后一起搞出个办法...”坏的回答看起来象,“嗯,我什么也不能做。这样的问题我解决不了。”记住,聪明并且能完成工作。要搞清楚某人是否能完成工作的一个办法就是看看他(她)过去是否倾向于完成任务。事实上,你可以主动要求他们给你个例子证明他们能担任领导作用,完成任务。-例如克服公司的陈规陋习。 现在我们谈谈清单上的第三款,无法回答的问题。这很有趣。这个主意的关键在于问一些不可能有答案的问题,就是想看一下应试者怎么办。“西雅图有多少眼科医生?”“华盛顿纪念碑有多重?”“洛杉机有多少加油站?”“纽约有多少钢琴调音师?”

聪明的应试者猜到你不是要测验他们的专业知识,他们会积极地给出一个估计。“嗯,洛杉机的人口是七百万;每个人平均拥有2.5辆轿车...”当然如果他们的估计完全错误了也没有关系。重要的是他们能积极地试着回答问题。他们可能会试着搞清楚每个加油站的储量。“嗯,需要四分钟给一个储油罐加满油,一个加油站有十个油泵每天运行十八个小时...”他们也可能试着从占地面积来估计。有时, 他们的想法的创造力让你吃惊. 而有时, 他们直接要一个LA的黄页去查。这都是好迹象。 不聪明的应试者则被难住了。他们目瞪口呆地望着你,好像你来自火星。你不得不提示:“嗯,如果你想建立一个象洛杉机那么大的城市,你需要建立多少个加油站?”你还可以提示他们:“加满一个储油罐要多长时间?”不过,这些榆木疙瘩脑袋还是只会坐在那里发呆,你得拖着他们往前走才行。这类人不会解决问题,我们可不要这样的人。 关于编程问题,我通常要求应试者用C语言写一些小函数。以下是我通常会出的题目:

将一个字符串逆序 将一个链表(linked list)逆序 计算一个字节(byte)里有多少bit被置1 搜索给定的字节(byte) 在一个字符串中找到可能的最长的子字符串,该字符串是由同一字符组成的 字符串转换成整数 整数转换成字符串(这个问题很不错,因为应试者要用到堆栈或者strev函数) 注意,通常你不会希望他们写的代码多于5行,因为你没有时间理解太长的代码。

现在我们来详细看一看其中几个问题: 第一个问题: 逆序一个字符串。我这辈子还没有见过那个面试者能把这题目一次做对。所有的应试者都试图动态生成缓冲区,然后将逆序的字符串输出到该缓冲区中。问题的关键在于,谁负责分配这个缓冲区?谁又负责释放那个缓冲区?通过这个问题,我发现了一个有趣的事实,就是大多数认为自己懂C的人实际上不理解指针和内存的概念。他们就是不明白。这真叫人吃惊,无法想象这种人也能做程序员。但他们真的就是!这个问题可以从多个角度判断应试者:

他们的函数运行快吗?看一下他们多少此调用了strlen函数。我曾经看到应试者写的strrev的算法竟然只有O(n^2) 的效率,而标准的算法效率应该是O(n),效率如此底下的原因是因为他们在循环中一次又一次调用strlen函数。 他们使用指针运算吗(译者按:原文为pointer arithmetic,指的是加减指针变量的值)?使用指针运算是个好现象。许多所谓的“C程序员”竟然不知道如何使用指针运算(pointer arithmetic)。当然,我在前文说过我不会因为应试者不掌握一种特定的技巧而拒绝他。但是,理解C语言中的指针不是一种技巧,而是一种与生俱来的才能。每年一所大学要招进200多个计算机系的新生,所有这些小孩子4岁就开始用BASIC语言在Atari 800s写冒险游戏了。在大学里他们还学Pascal语言,学得也很棒。直到有一天他们的教授讲了指针的概念,突然,他们开始搞不懂了。他们就是不能再理解C语言中的任何东西了。于是90%的计算机系学生转系去学政治学。为了挽回面子,他们告诉朋友,他们之所以转系是因为他们计算机系英俊貌美的异性太少。许多人注定脑子里就没有理解指针的那根弦。所以说理解指针是一种与生俱来的品质,而不是一种单纯的技巧。理解指针需要脑子转好几个弯,某些人天生不擅长转这几个弯。 第三个问题可以考考面试者对C的位运算的掌握,但这是一种技巧,不是一种品质,所以你可以帮助他们。有趣的等他们建立了一个子函数用来计算byte中为1的位的数目,然后你要求他们优化这个子函数,尽量加快这个函数的运行速度。聪明的应试者会使用查表算法(毕竟这个表只有 256个元素,用不了多少内存),整个表只需要建立一次。跟聪明的应试者讨论一下提高时间/空间效率的不同策略是十分有意思的事情. 进一步告诉他们你不想在程序启动时初始化查询表。聪明的面试者可能会建议使用缓冲机制,对于一个特定的byte,只有在第一次被查询时进行计算,然后计算结果会被放入查询表。这样以后再被查询时直接查表就行了。而特别特别聪明的面试这会尝试有没有建立查询表的捷径,如一个byte和它的置1的bit数之间有没有规律可循?

当你观察应试者写C代码时,以下一些技巧会对你有帮助:

事先向应试者说明,你完全理解,没有一个好的编辑器光在纸上写代码是困难的,所以你不在乎他们手写的代码是否看上去不整洁。你也完全明白没有好的编译器和调试器,很难第一次就写出完全没有bug的程序,所以请他们不必为此担心。 好程序员的标志:好程序员写完“{”符号后,通常立刻跟上“}”符号,然后再在当中填上代码。他们也倾向于使用命名规则,虽然这个规则可能很原始。如果一个变量用作循环语句的索引,好程序员通常使用尽可能少的字符为它命名。如果他们的循环语句的索引变量的名字是CurrentPagePositionLoopCounter,显而易见他们写代码的经验还不够多。偶尔,你会看到一个C程序员写下象if (0==strlen(x))一样的代码,常量被放在==的左边。这是非常好的现象。这说明他因为总是把=和==搞混,已经强迫自己养成这种习惯以避免犯错。 好的程序员在写代码前会订一个计划,特别是当他们的代码用到了指针时。例如,如果你要求逆序一个链表,好程序员通常会在纸的一边画上链表的草图,并表明算法中的索引指针当前移动到的位置。他们不得不这样做。正常人是不可能不借助草图就开始写一个逆序链表的程序的。差的程序员立刻开始写代码。 不可避免的,你会在他们的程序中发现bug,于是我们现在来到了第五个问题:你对代码满意吗? 你可能想问,“好吧,bug在哪里?”这是来自地狱的一针见血的问题,要回答这个问题可要大费口舌。所有的程序员都会犯错误,这不是问题。但他们必须能找到错误。对于字符串操作的函数,他们通常会忘记在输出缓冲区加上字符串结束符。所有的函数,他们都会犯off-by-one错误(译者按:指的是某个变量的最大值和最小值可能会和正常值差1)。他们会忘掉正常的C语句结尾的分号。如果输入是零长度字符串,他们的函数会运行错误。如果malloc调用失败而他们没有为此写好错误处理代码,程序会崩溃。一次就能把所有事情做对的程序员非常,非常,非常地少.不过要是真的碰上一个的话, 提问就更有意思了. 你说,"还有Bug"。他们会再仔细地检查一遍代码。这个时候, 观察一下他们内心是否开始动摇了, 只是表面上勉强坚持说代码没有问题。总之,在程序员写完代码后,问一下他们是否对代码满意是个好主意。就像Regis那样问他们!(译者按,Regis Philbin是美国ABC电视网的游戏电视节目主持人,他的口头禅是“这是你的最后的答案吗?”)

第六部分:关于设计的问题。让应试者设计某样东西。Jabe Blumenthal,Excel的原始设计者,喜欢让应试者设计房子。Jabe说,曾经有一个应试者跑到白板前,画了一个方块,这就是他的全部设计。天哪,一个方块!立刻拒绝这样的家伙。你喜欢问什么样的设计问题?

好的程序员会问更多的信息。房子为谁造的?我们公司的政策是,我们不会雇佣那些在设计前不问为谁设计的人。通常,我会很烦恼我得打断他们的设计,说“事实上,你忘记问这个房子是给谁设计的了。这个房子是给一群长颈鹿造的。” 笨笨的应试者认为设计就像画画,你想画什么就画什么。聪明的应试者明白设计的过程是一系列艰难的权衡。一个很棒的设计问题是:设计一个放在街角的垃圾箱。想一想你得做多少权衡!垃圾箱必须易于清空,但是很难被偷走;易于放进垃圾,但是碰到狂风大作,里面的垃圾不会被吹出来;垃圾箱必须坚固而便宜。在某些城市,垃圾箱必须特别设计,以防恐怖分子在里面藏一个定时炸弹。 有创造力的应试者会给出有趣而独特的设计。我最喜欢的问题之一是为盲人设计一个放调味品的架子(译者按:原文为spice rack,老外的厨房里有个专门放调味品的架子,上面放了很多小罐罐,里面装了各种各样的调料)通常许多应试者的建议是把布莱叶文(一种盲人使用的文字)刻在放调料的罐子上,这样文字会卷起来而变形。我碰到一个应试者,他的设计是把调料放在抽屉里,因为他觉得水平地感知布莱叶文比垂直地做更方便。(试试看!)这个答案这样有创意,使我震惊!我面试了有一打得程序员,从来没有人想到过类似的答案。这样有创意的答案确实跃过了普通人考虑问题的条条框框。仅仅因为这个答案太有创意了,而且应试者别的方面还过得去,我雇佣了这个应试者,他现在已经成为Excel团队中一个优秀的项目经理了(译者按,本文作者曾在微软工作过)。 总是争取一个确定的了结。这也是完成工作的特质的一部分。有时候应试者会犹犹豫豫不能作出一个决定,试图回避困难的问题,留着困难的问题不作决定就直接向下进行,这很不好。好的应试者有一种推动事情自然地前进的倾向,即使你有意把他们拖回来。如果关于某个话题的讨论开始原地打转变得没有意义了,好的应试者会说,“嗯,我们可以整天谈论这个,但是我们得做点什么。为什么我们不开始...” 于是我们来到了第七部分,挑战。这部分很好玩。在面试中留心一下, 当面试者的回答绝对的百分之百毫无争议时, 你可以说: " 嗯, 等一下等一下." 然后花上两分钟玩一下魔鬼的游戏(译者按,原文为devil's advocate,魔鬼代言人指的是违背自己的良知,为错误邪恶的观点辩护). 记住一定要在你可以肯定他正确时和他争论。

这个很有意思. 软弱的应试者会屈服。那我就和他说拜拜了。 坚定的应试者会找到一个办法说服你。他们会以肯尼迪总统的口才来说服你,“也许我误会了你的意思,”他们这样开头,但是正文仍是坚定地站稳立场。这样的人我就雇佣。 不得不承认,面试双方的地位并不是平等的。有可能应试者由于害怕你的权力而不敢于你争辩。但是,好的应试者有足够的热情和勇气坚持正确的观点,他们由于热切希望说服你而会暂时忘记正在被面试。这样的人就是我们要雇佣的人。

最后,可以问一下应试者有什么想问的。一些人喜欢看看应试者这时是否会问一些聪明的问题。这是市面上流行的面试书籍的标准技巧。我个人不在乎应试者问什么,因为这时我已经做了决定。麻烦在于,应试者也许已经见了5、6个人,进行了好几轮面试,他们可能很累了,以至于不能为每轮面试都准备一个聪明而独特的问题。所以如果他们没有可问的,没关系。

我总是留下面试的最后5分钟来推销我的公司。这很重要。即使我不打算雇佣眼前这个应试者。如果你幸运的找到一个很棒的应试者,你当然愿意做任何事情说服他(她)来你的公司。即使他们不是好的应试者,你也要尽力让他们为Fog Creek公司激动,这样面试结束时他们会对Fog Creek公司留下一个很好的印象。记住,应试者并不仅仅是可能的雇员,他们也是顾客,也是我们公司的推销员。如果他们觉得我们的公司很棒,他们也许会推荐朋友来面试。

啊哈,我记得我说过我会给出一些应该避免的非常不好的反面的试题例子。 首先,避免不合法的问题。有关种族,宗教,性别,出生国,年龄,服役记录,是否老兵,性取向,生理障碍的问题都是不合法的。即使他们的简历说他们1990年在军中服役,也不要问有关问题。也许这会让他们愉快地谈论在海湾战争中的经历。但是你的问题还是不合法的。如果简历上写着他们上过Technion in Haifa, 不要问他们是否是以色列人, 即使只是为了闲谈, 因为这是违法的. 下面有一个很好的不合法的例子。点击这里有很多关于什么是违法的讨论。(但是这个网站的其余问题够愚蠢的。)

其次,不要在问题中给予应试者暗示,我们公司喜欢或者不喜欢什么样的员工。我能想到的一个例子是问应试者是否有小孩或者是否结婚了。应试者也许会想我们不喜欢有家庭拖累的员工。

最后,不要问那些脑筋急转弯的题目,例如6根火柴怎么拼出4个三角形。象这样的灵机一动的问题是不能看出应试者是否有“有头脑/完成工作”的品质。

面试与其说是科学不如说是艺术。但是只要你记住有头脑/完成工作这个原则,你就可以应对自如。有机会就问问你的同事他们喜欢的面试问题和答案。这是我们公司员工午饭时热衷的话题之一。

The Joel Test: 软件开发成功 12 法则

作者: 周思博 (Joel Spolsky) 译: 李国华 Frank Li 编辑: 孙雯辰 Rosemary Sun 2000年8月9日


有没有听说过SEMA?这可是衡量一个软件开发组好坏的很深奥的系统。别介,等一下!别按那个链接! 给你六年你也搞不清这玩意。所以我自己随便攒了一套衡量系统,信不信由你,这系统,三分钟就可掌握。你可以把省下的时间去读医学院了(译注:美国的医学院可是要读死人的!)。

Joel 衡量法则

1.你们用不用源文件管理系统?

2.你们可以把整个系统从源码到CD映像文件一步建成吗?

3.你们每天白天都把从系统源码到CD映像做一遍吗?

4.你们有软件错误管理系统吗?

5.你们在写新程序之前总是把现有程序里已知的错误解决吗?

6.你们的产品开发日程安排是否反映最新的开发进展情况?

7.你们有没有软件开发的详细说明书?

8.你们的程序员是否工作在安静的环境里?

9.你们是否使用现有市场上能买到的最好的工具?

10.你们有没有专职的软件测试人员?

11.你们招人面试时是否让写一段程序?

12.你们是否随便抓一些人来试用你们的软件?


“Joel 衡量法则”好就好在你只需照着逐条回答以上问题,然后把所答为“是”的问题算成一分,再加起来就可以了,而不需要去算什么每天写的程序行数或程序虫的平均数等等。但咱丑话说在前面,可别用“Joel 衡量法则”去推算你的核电站管理程序是否可靠。

如果你们得了12分,那是最好,得了11分还过得去,但如果只得了10分或低于10分,你们可能就有很严重的问题了。严酷的现实是:大多数的软件开发公司只能得到2到3分。这些公司如果得不到急救可就玄了,因为像微软这样的公司从来就没有低过12分。

当然,一个公司成功与否不仅仅只取决于以上标准。比如,让一个管理绝佳的软件公司去开发一个没有人要的软件,那开发出来的软件也只能是没有人要。或反过来,一帮软件痞子以上标准一条也达不到,没准照样也能搞出一个改变世界的伟大软件。但我告诉你,如果不考虑别的因素,你只要能达到以上12条准则,你的团队就是一个可以准时交活的纪律严明的好团队。

1. 你们用不用源文件管理系统? 我用过商业化的源文件管理系统,我也用过免费的系统,比如CVS,告诉你吧,CVS挺好用。但如果你根本就没有用源文件管理系统,那你就是累死了也没法让你的程序员出活:他们没法知道别人在改动什么源文件,写错了的源文件也没法恢复。

使用源文件管理系统还有一大好处是,由于每一位程序员都把源文件从源文件管理系统里提出来放到自己的硬盘里,几乎不会发生丢失源文件的事,最起码我还没听说过。

2. 你们可以把整个系统从源码到CD映像文件一步建成吗? 这句话问的问题是:从你们最新的源码开始到建立起能够交出去的最后文件,你们有多少步骤要做? 一个好的团队应该有一个批处理程序一步便可将所有的工作做完,像把源文件提取出来,跟据不同的语言版本要求(英文版,中文版),和各种编译开关(#ifdef)进行编译,联接成可执行文件,标上版本号,打包成CD映像文件或直接送到网站上去,等等等等。

如果这些步骤不是一步做完,就有可能出人为差错。而且当你很接近产品开发尾声的时侯,你可能很急于把最后几个虫解决,然后尽快地交活。如果这时候你需要做20步才能把最终文件制出来,你肯定会急得要命,然后犯一些很不该犯的错误。

正因为这个原因,我工作的前一个公司从用WISE改用InstallShield:我们必需要让我们的批处理程序完全自动化地,在夜里,被NT scheduler起动把最终文件制成,WISE不能被NT scheduler启动而InstallShield可以,我们只能把WISE扔掉。(WISE的那帮家伙向我保证他们的下一代产品一定支持在夜里自动运行.)

3. 你们每天白天都把从系统源码到CD映像做一遍吗? 你们有没有遇到过这样的事情:一个程序员不小心把有毛病的源码放进源文件管理系统,结果造成最终文件没法制成。比如,他建立了一个新源文件但忘了把它放进源文件管理系统,然后他高高兴兴锁机回家了,因为在他的机器上整个编译得很好。可是别人却因为这没法工作下去了,也只好闷闷地回家了。

这种造成最终文件没法制成的情况很糟糕,但却很常见。如果每天在白天就把最终文件制一遍的话,就可以让这种事不造成太大危害。在一个大的团队里,要想保证有毛病的源码及时得到纠正,最好每天下午(比如午餐时)制一下最终文件。午餐前,每个人都尽可能地把改动的源文件放到源文件管理系统里,午餐后,大家回来,如果最终文件已经制成了,好!这时大家再从源文件管理系统里取出最新的源文件接着干活。如果最终文件制作出错,出错者马上修正,而别人还可接着用原有的没问题的源程序干活。

在我以前曾干过的微软Excel开发组里,我们有一条规定:谁造成最终文件制作出错,谁就得被罚去负责监视以后的最终文件制作过程,直到下一位造成最终文件制作出错的人来接任他。这样做不仅可以督促大家少造成最终文件制作出错,而且可以让每个人都有机会去了解最终文件制作过程。

如果想更多了解这个话题,可以读我的另一篇文章 Daily Builds are Your Friend.

4. 你们有软件虫管理系统吗? 不论你有任何借口,只要你写程序,哪怕只是一个人的小组,如果你没有一个系统化的管理软件虫的工具,你写的程序的质量一定高不了。许多程序员觉得自己可以记得自己的软件虫。没门!我从来记不住超过2到3个软件虫。而且第二天早上起床后忙着去买这买那,好不容易记住的软件虫早忘掉了。你绝对需要一个系统来管住你的那些虫。

软件虫管理系统功能有多有少。但最少要管理以下几种信息:

如何重复软件虫的详细步骤 正常情况(无虫)应是怎样 现在情况(有虫)又是怎样 谁来负责杀虫 问题有没有解决 如果你觉得用软件虫管理系统太麻烦,可以简化一下,建立一个有以上5列的表来用就行了。

如果想更多了解这个话题,可以读我的另一篇文章Painless Bug Tracking.

5. 你们在写新程序之前总是把现有程序里已知的虫解决吗? 微软Windows Word的第一版的开发项目曾被认为是“死亡之旅”项目。好象永远也做不完,永远超时。所有人疯狂地工作,可怎么也完成不了任务。整个项目一拖再拖,大家都觉得压力大得受不了。最后终于做完了这个鬼项目,微软把全组送到墨西哥的Cancun去度假,让大家坐下来好好想想。

大家意识到由于项目经理过于强求程序员们按时交活,结果大家只能匆匆地赶活,写出的程序毛病百出。由于项目经理的开发计划并没有考虑杀虫的时间,大家只能把杀虫的任务往后推,结果虫越积越多。有一个程序员负责写计算字体高度的程序,为了图快,居然写一行“return 12;”了事。他指望以后的质检人员发现这段程序有毛病后报告他再改正。项目经理的开发计划事实上已变成一个列写程序功能的清单,而上面列的所谓程序功能迟早都会成为软件虫。在项目总结会上,我们称这种工作方法为“绝对劣质之路”。

为了避免再犯这个错误,微软制定了“零缺陷策略”。许多程序员嘲笑这个策略,觉得经理们似乎在指望靠行政命令来提高产品质量。而事实上“零缺陷策略”的真正含义是:在任何时候,都要把解决现有程序里的问题作为首要问题来抓,然后再去写新程序。

为什么要这样做呢?

一般说来,你越不及时地杀虫,杀虫的代价(时间和金钱)就会越高。比如,你写程序时打错了一个字,编译器马上告诉你,你很容易就把它改正。你刚写好的程序在第一次运行时发现了一个问题,你也很快就能解决它,因为你对你刚写的程序还记忆犹新。如果你运行你的程序时发现了一个问题,可这个程序是几天以前写的,你可能就需要折腾一会儿,还好,你还大致记得,所以不会花太长时间。但如果你在你几个月以前写的程序里发现了问题,就比较难解决了,因为你已经忘了许多细节。这时候,你还没准儿正忙着杀别人程序里的虫呐,因为这家伙到加勒比海阿鲁巴岛度假去了。这时候,解决这一堆问题的难度不亚于从事尖端科学研究。你一定得小心翼翼地,非常系统化地从事,而且你很难知道多长时间你才能把问题解决。还有更糟糕的,你的程序已交到用户手里了,才发现问题,那你就等着套腰包吧。

总结起来,就一条:越早解决问题,越容易解决。

另外还有一个原因,刚写的程序里发现问题,你能够比较容易地估算解决它的时间。举个例子,如果我问你写一段程序去把一个列表排序需要花多长时间,你可以给我一个比较确切的估计。如果你的程序,在Internet Explorer 5.5安装以后,工作不正常。我问你要多长时间把这个问题解决,你恐怕都估计不出来,因为你根本就不知道是什么原因造成了这个问题。你可能要花三天时间才能解决,也有可能只花两分钟。

这个例子告诉我们,如果你的开发过程中有许多虫没有及时解决,那你的开发计划肯定不可靠。反过来,如果你们已经把已知的虫全部解决了,要做的事只是写新的程序,那你的开发计划就会比较准确。

把已知的虫全部解决,这样做还有一个好处:你可以对竞争对手快速反击。有些人把这叫着“让开发中的产品随时处在可以交给用户的状态”。如果你的竞争对手推出一个新的功能想把你的客户抢走,你可以马上在你的产品里加上这个功能,立刻将新产品交付用户,因为你没有一大堆积累下来的问题要解决。

6. 你们的产品开发日程安排是否反映最新的开发进展情况? 为什么我们需要开发日程安排?如果你的程序对公司的业务很重要,那公司就必须知道你的程序何时能写完。满世界的程序员都有一个通病,那就是他们都搞不清自己何时才能写完要写的程序。他们都只会对管理人员嚷嚷:“等我做好了就做好了!”

不幸的是,程序写完了,事远远没完。作为一个公司,在发行产品之前,还有许许多多的事情要做:何时做产品演示?何时参加展览会?何时发广告?等等。所有的这一且都依赖于产品的开发日程安排。

定下产品开发日程安排,还有一个很关键的好处:它逼着你只做叫你做的功能,甩掉那些可要可不要的功能,否则这些可要可不要的东西有可能把你缠住。请看featuritis

定下产品开发日程安排,按照它开发,这并不难做,请看我的另一篇文章 Painless Software Schedules ,这篇文章告诉你一种制订产品开发日程的好方法。

7. 你们有没有软件开发的详细说明书? 写软件开发的详细说明书就像是绣花:人人皆知是好东西,可没谁愿意去做。

我不知道这是为什么,也许是因为多数程序员天生就不喜欢写文章。其结果是,一个开发组里的程序员们,宁可用程序来沟通,也不愿写文章来表达自己。他们喜欢上来就写程序,而不是写什么详细说明书。

在产品的前期设计过程中,如果你发现了一些问题,你可以轻易地在说明书里该几行字就行了。一旦进入了写程序的阶段,解决问题的代价就要高得多了,不仅仅是时间上的代价,而且也有感情上的代价,因为没人愿意将自己做成的东西扔掉。所以这时候解决问题总有一些阻力。

没有产品开发详细说明书就开始写程序,往往会导致程序写的乱七八糟,而且左拖右拖不能交付使用。我觉得这就是Netscape遇到的问题。前四个版本的程序越写越乱,以至管理人员作出一个愚蠢的决定:把以前的程序统统扔掉,重新写。后来他们在开发Mozilla时又犯了同样的错误。产品越做越乱,完全失控,花了几年的时间才进入内部测试阶段。

我最得意的理论是:如果让程序员们接受一些写文章的训练如an intensive course in writing,他们就可能会改变一下不写说明书的坏习惯,而以上所说的糟糕的例子就有可能少发生。

另一个解决问题的办法是:雇一些能干的项目主任,专职写产品开发详细说明书。

不论采用以上哪种方法,道理只有一个:在没有产品开发详细说明书之前,决不可写程序。

如果想更多了解这个话题,可以读我的四篇文章

8. 你们的程序员是否工作在安静的环境里? 当你让你的智囊们工作在安静,宽敞,不受人打扰的环境里,他们往往能更快地出活,这已是不争的事实。有一本经典的讲软件开发管理的书Peopleware 把这个问题阐述得很清楚。

问题在于,我们都知道最好不要打断这些智囊们的思路,让他们一直处于他们的最佳状态中,这样他们就能全神贯注,废寝忘食地工作,充分发挥他们的作用。作家,程序员,科学家,甚至篮球运动员都有他们的最佳状态。

问题还在于,进入这个最佳状态不容易。我觉得平均起来,需要15分钟才能进入最佳状态,达到最高工作效率。有时侯,当你疲劳了或已经高效率地干了许多工作了,你就很难再进入这个状态,只好干点杂事打发时间,或上网,玩游戏等。

问题更在于,你很容易就被各种各样的事打扰,被拽出你的最佳状态:噪音啦,电话啦,吃午饭啦,喝杯咖啡啦,被同事打扰啦,等等。如果一个同事问你一个问题,只花你一分钟,可你却被拽出你的最佳工作状态,重新回到这个状态需要花半小时。你的工作效率因此而受到很大影响。如果让你在一个嘈杂的大房间里工作(那帮搞网站的家伙还就喜欢这样),边上的推销员在电话里大叫大嚷,你就很难出活,因为你进入不了你的最佳工作状态。

作为程序员,进入最佳工作状态更难。你先要把方方面面的细节装在脑子里, 任何一种干扰都可能让你忘掉其中某些东西。你重新回来工作时,发现好些东西记不起来了(如你刚用的局部变量名,或你刚才的搜索程序写到哪里了等)你只好看看刚写的程序,回忆一下,慢慢地回到你刚才的最佳工作状态。

我们来做一个简单的算数。假设一个程序员被打扰一下,哪怕只有一分钟,他却需要花15分钟才能回到最佳工作状态(统计资料显示如此)。我们有两个程序员:杰夫和愚夫, 坐在一个大办公区里工作。愚夫想不起来用什么函数去进行Unicode 字符串复制。他可以花30秒查一下,或者花15秒问杰夫。由于他坐在杰夫的旁边,他就选择去问杰夫。杰夫被打扰了一下,耽误了他15分钟,节省了愚夫15秒钟。

现在,我们把他们俩用墙和门隔开,让他们俩分坐在不同的办公室里,愚夫又想不起来什么涵数名,自己查一下要花30秒;问杰夫,要花45秒,因为他要站起来走过去问(对这帮程序员来说,这可不是件简单的事,看看他们的体质就知道为什么了)。所以他选择自己去查。愚夫损失了30秒钟,可是杰夫少损失了15分钟。哈哈!

9. 你们是否使用现有市场上能买到的最好的工具?

用可编译语言写程序恐怕是这世界上为数不多的还不能随便抓一个破计算机就可以做的事。如果你用于编译的时间超过几秒钟,你就应该换一台最新最快的计算机了。因为如果编译时间超过15秒,程序员们就会不耐烦,转而去上网看一些无关的东西比如The Onion,弄不好一看就是好几个小时。

调试图形界面软件时,用只有一个显示器的计算机不仅不方便,有时甚至是不可能。用有两个显示器的计算机,要方便许多。

程序员们经常不可避免地要去画一些图标或工具栏图。多数程序员没有一个好的图形编辑器可用。用微软的“画笔”软件去画图标简直是笑话,可事实上大家还就在这样做。

我的前一个工作,系统管理员成天给我发来自动警告,说我在服务器上使用了超过220兆的空间。我告诉他,按现在硬盘的价钱,超出这点空间的价钱远低于我用的厕纸的价钱。让我花10分钟去清理我的文件绝对是我工作效率的莫大浪费。

一流的开发组绝不折腾它的程序员。工具落后会让人用起来觉得难受,一点点积累起来,会让程序员们成天叫苦,而一个成天叫苦的程序员绝对不会是一个高消率的程序员。

再添一句,要想使你的程序员高兴,最好的办法就是给他们买一些最新最棒的工具软件。用这种方法可以让他们乖乖地为你工作,这可比用高薪吸引他们来得便宜得多。

10. 你们有没有专职的软件测试人员? 如果你的开发组里没有专职的测试人员,或没有足够的测试人员(两到三个程序员就应该配一个测试员),那你的产品就一定是毛病百出,或者你在花100美元一小时的代价去雇你的程序员去做30美元一小时就可以雇到的测试员的工作。想在测试员身上省钱,绝对是打错了算盘。我真不明白为什么这么多人算不过来这笔帐。

我有另一篇文章专门讲这个,请看Top Five (Wrong) Reasons You Don't Have Testers

11. 你们招人面试时是否让写一段程序? 我问你,让你去招一个魔术师,你是否连看都不看一眼他的魔术玩得怎样就要他?当然不会!

你举办婚宴,要请一个厨师,你是不是连嚐也不嚐他做的菜好吃不好吃就要他?我想也不会。

奇怪的是,几乎每天都有这样的事发生:在面试一个程序员时,简历写得漂亮,谈得热火朝天,问几个简单的问题(如CreateDialog()和DialogBox()有什么区别?这种问题,查一下帮助文件就知道了),人就招进来了。你真正应该关心的不是这人记不记得这些写程序的边边角角的东西,而是他能否出产品!更糟糕的是,许多问题是知道就知道,不知道,想死也不知道的问题。

不能这样下去了!在面试时,请一定要让写一段程序。在我的这篇文章里Guerrilla Guide to Interviewing,我有许多好建议。

12. 你们是否随便抓一些人来试用你们的软件? 这句话的意思是,让你从走道里走过的人中,随便抓几个人来,让他们试用你的软件。如果你抓五个人来用你的软件,那你就可能把你的程序中95%的不方便使用的地方找出来。

要想让用户去买你的软件,你必须要设计好你的用户界面。这其实并不难。你可以读我的free online book on UI design打打基础。

用户界面设计的关键是,如果你让几个人去用你的软件(五六人可能就够了),你可能很快就找出最大的问题。想知道为什么吗,请读Jakob Nielsen's article。只要你坚持随便抓一些人来试用你的软件,你就能将你的用户界面设计得越来越好。

The Joel Test 软件开发成功12法则的四个实用领域

用该法则来衡量你的软件开发组,告诉我你得的分数,让我来品头论足。 如果你是开发组的经理,用该法则来使你的组提高效率。如果你们一上来就能得12分,你就 别再打扰你的程序员了, 专心致志别让公司的管理人员来烦你的程序员吧。 如果你在找一份程序员工作,问问你未来的老板他能得几分,如果分数很低,你一定要确信你进去后有足够的权力来改变这一切,否则,最好躲远点,不然,你在那儿会很难受的。 如果你是投资者,正在决定是否向一个软件公司投资,或者你的软件公司正在决定是否兼并另一个软件公司,该法则可以帮你做决定。


本文最先用英文出版,题为 The Joel Test: 12 Steps to Better Code

《微独立软件供应商:从理想到现实》序

作者: 周思博 (Joel Spolsky) 译: feiyafei 编辑: feiyafei 2006年01月14日


本文是我为Bob Walsh的新书,《微独立软件供应商:从理想到现实》所作的序。

我还在想,到底我是如何成为微独立软件供应商运动的代表人物的呢?

而且,天哪,还是所有人的典范。

当我创立Fog Creek 软件的时候,压根儿就没有想过将它做成小型公司。当时的计划是发展成一个大型的跨国软件公司:在120个国家拥有办公地点,而且在曼哈顿能拥有一栋摩天大楼作公司总部,大楼房顶还建有可直达Hamptons的直升机场。一二十年来,我们一直在发展,虽然总是比较谨慎——但是我们从来没有想过要将公司做小。

好吧,我其实不太喜欢微独立软件供应商(MicroISV)这个名称。ISV代表独立软件供应商(Independent Software Vendor)。这是一个源自微软的新词,意思是“除了微软以外的软件产商”,或者更具体的说法是,“由于一些原因我们(微软)还未收购或者未被淘汰掉的软件产商,之所以还没有被淘汰则是因为这些产商的产品不过是用于诸如婚礼餐桌安排的狭窄领域,而我们对这些偏僻软件产商则是不屑一顾;就先让你们这些小家伙们自得其乐一下,只要记住用微软的.NET即可。”

就像另外一个称呼,“遗老遗少”那样,微软也用来指代所有的非微软软件。因此微软的人会将Google称为“搜索引擎的遗老遗少”,无论如何,他们都在试图暗示Google不过是“一家陈旧的、毫无价值的搜索引擎,现在你在使用它不过是因为历史习惯问题,而你必然将转移到MSN上来”。

相比之下,我更喜欢“软件公司”这个词汇,即使对于创业公司也可以这样称呼。我们就将自己的公司形容为“软件创业公司”,我们认为没有必要将其同微软联系起来。

我想读者诸君阅读本书是想开一家小型软件公司吧,它刚好再合适不过了;请允许我利用这个机会提三件你必须了解的事情,以作为在你开办微……咳,软件创业公司的建议。当然你还需要做很多其它事情,这些东西都可以在本书找到。所以在阅读正文之前,先听听我的想法。

第一、如果你无法解释清楚你的公司能够解决用户什么难处,或者为什么你的产品能够解决它,以及用户如何会付费给你们来消除他们的难处;那么在创办公司前最好请三思。有一次我给六家高技术创业公司做讲座,结果发现没有一家能够跟我说清楚,他们能够解决用户什么问题。其中一家公司是想为你安排同朋友喝咖啡的时间;另外一家则是想让用户在浏览器上安装一个插件以跟踪其网上活动,同时可以让用户能够从历史记录中将这些活动删除;还有一家公司的服务则是为你的朋友在特定地点留下便条(例如他们经过你刚刚离开的一个酒吧时,便可以收到你留下的便条)。这些公司的共同点就是没有一家能够真正解决问题,都不过是在痴心妄想。

第二、不要单枪匹马开公司。我知道有很多成功的案例,但是失败的案例更多。如果你甚至都无法让朋友明白你想法的优势何在,那么或许这个创意真的不太好呢?另外,如果没有人能够和你相互探讨,那么创业将是一件孤独而令人沮丧的事业。而对于一个人来说,如果事业变得艰难起来的话——一般都会这样,很可能你只有关门大吉了。而两个人的情况则不同,你将会感觉有义务鼓励你的创业伙伴。当然,必须正确选择创业伙伴。

第三、不要指望过高。当产品出售的第一个月时,没有人知道到底会得到多少收入的。我记得五年前,当我们开始发售FogBugz时,根本不知道第一个月的销售额是50000美元还是零蛋。这两个数字对我来说其实都很有可能。我过去和很多创业者都进行了交流,许多数据表明我其实可以为这个数字提供一个准确的答案。

是的,我有一个占卦水晶球,现在通过它可以告诉你一个绝对想知道的事实:在你的产品开始发售后的第一个月你将能够赚到多少钱。

准备好了?开始!

在公司新产品发售的第一个月,你将可以赚到:

大约……

364美元,如果你面面俱到的话。如果你的产品要价过低,那么也许只能赚到40美元。而要价过高,则一分钱也赚不到。如果你的心理预期超过这些数值,那么很可能真的会大失所望,开始放弃创业,为那个称我们这些创业公司“MicroISV遗老遗少们”的大人物干活了。

364 美元听起来似乎颇让人失望,其实不然,因为你很快会发现产品存在一个极为严重的缺陷,它使得你的50%潜在客户都不愿掏钱;解决了这个问题后下个月或许你就能赚728 美元了。接下来你会奋力拼搏,可以变得小有名气,然后你开始考虑如何有效地使用广告词,甚至你公司的事迹会出现在当地婚礼策划的业务通讯上!再下个月你得到了1456美元。于是再接再厉,你推出了2.0版本,内置垃圾信息过滤以及一个公共Lisp语言解释器,你的用户开始奔走相告。而你发现这个月你的收入已经是 2912美元。然后你开始调整价格,增加技术支持合同,发布3.0版本产品,甚至在The Daily Show节目中被Jon Stewart所提及。这个月你赚了5824美元。

现在我们可以一鼓作气,对未来几年的发展做出规划,如果你坚持努力,每12至18 个月让自己收入翻番肯定没问题;因此无论你的起点多么小,(此处省略详细的数学公式若干),你将很快能够在曼哈顿建造以作自己的摩天大楼,而且大楼上的直升飞机场保证让你半个小时刚好能抵达位于南安普敦(美国纽约市东南部的一个村庄,位于长岛的东南沿海地区,主要是避暑胜地。)、面积达20英亩的度假村。

我认为,这恰恰是创办一个公司的真正乐趣:你自己创造了一件东西,努力培育着它,对它投资并且看着它的成长,同时也享受了投资的回报。虽然这是一条充满荆棘的旅途,但是再苦再累也值得。


本文原文为 Micro-ISV: From Vision to Reality

抽象渗漏法则

作者:周思博 (Joel Spolsky)http://www.joelonsoftware.com

译:Paul May 梅普华 sink.cup

原作发表于:2002年11月11日

ChineseTraditional:[2]

你每天不可或缺的Internet里有个关键的小魔法,这个魔法就在TCP通讯协议这个internet的基础协议里。

TCP是一种可靠的资料传输方法。我说可靠是指如果用TCP在网络上传一个信息,信息一定会到,绝不会乱掉或坏掉。

TCP的用途很多,比如抓取网页资料或传电子邮件都是。由于TCP这么可靠,连那些骗钱的中奖邮件都能完整无缺的到达,真是好笑。

相对的有另一种叫IP的不可靠资料传输方法。IP不保证资料会传到,就算到了资料也可能会乱掉。如果你用IP传送一堆信息,很可能只有一半的信息到达,而且其中还有一些到达的顺序和原先传送时的顺序不同,另外可能有几个信息的内容会变掉,可能变成可爱的猩猩宝贝照片,更可能变成一堆看不懂的垃圾,看起来就像垃圾邮件的标题一样。

这里就是魔法所在:TCP是架在IP上面的。换句话说,TCP不得不靠一个不可靠的工具想办法可靠地传送资料。

为了说明这的确是个魔法,想想下面这个本质上相同(虽然有点滑稽),来自真实世界的情节。

想像你有个方法把演员由百老汇送到好莱坞,基本上就是让人坐上车后开车横越国家送过去。有些车会出车祸让可怜的演员挂掉。有时候演员在路上喝醉了就去剃光头或刺纳粹刺青,结果变得太丑而不能在好莱坞工作。另外由于走的路线不同,演员到达的顺序常会跟出发的顺序不一样。现在想像有个叫好莱坞快递的新服务,可以把演员送到好莱坞,并且保证演员一定会(a)到达,并保证(b)顺序不变而且(c)状态完美地到达。神奇之处在于好莱坞快递除了原本的车子以外,并没有新的运送方法。好莱坞快递的作法是在每个演员抵达时检查演员的状况,如果状况不佳就打电话请公司把该演员的双胞胎送来。如果演员到达的顺序不对,好莱坞快递会照正确顺序重新排好。如果51区有架大幽浮在内华达的高速公路上坠毁阻断了交通,预定走这条路线的演员就会改走亚历桑那州,好莱坞快递甚至不会把事情告诉加州的导演。导演只会觉得演员来得比平常慢,他们甚至不会听到幽浮失事的消息。

TCP的魔法大致上就是这样。这种作法常被计算机科学家称为抽象:把许多复杂的东西隐藏起来的一种简化动作。结果很多计算机程序的设计都是在建立抽象机制。字符串程序库是什么?它是一种伪装,假装计算机能像处理数字一样轻易的处理字符串。文件系统又是什么?也是一种伪装,假装硬盘并不是一堆不停旋转,可以储存比特的磁性碟片,而是一个有着层层目录的阶层式系统,可以存放一个个由一或多个比特组成的字符串构成的文件。

把话题拉回TCP。稍早为了让事情单纯一点,我撒了一个小谎,而且现在有些人可能会因为这个谎气得头上冒烟。我说过TCP保证你的信息会到达,其实并不会。如果你养的蛇把连接计算机的网络线咬断了,就没有任何IP包可以通过,这时候TCP当然也不可能让你的信息抵达。如果你惹毛了公司的系统管理员,他们为了报复就把你接到已经超过负荷的集线器,因此只有部份的IP封包能通过,这时候TCP是会动,不过一切都会变得很慢。

这就是我称之为抽象机制有漏洞的状况。TCP试图提供一个完整的抽象机制,想隐藏底下不可靠的网络,不过有时候网络会渗漏越过抽象机制,这时就会觉得抽象其实并不太能真的提供保护。这只是我所谓「抽象渗漏法则」的一个例子而已:

所有重大的抽象机制在某种程序上都是有漏洞的。

抽象会失效。有时候轻微有时候很严重,反正就是有漏洞。事情会因而出错,而且当你有抽象机制时到处都可能会发生。下面有一些例子。

像扫描一个大的二维矩阵这么简单的动作,是由水平方向或垂直方向扫描都会严重影响效率,影响的大小依「木纹」(译注:二维阵列排列的方式)的方向而定,某个方向可能比另一个方向多产生许多的分页失败,而分页失败是很慢的。虽然写组合语言的程序员应该可以假设自己拥有可连续定址的内存空间,不过虚拟内存表示这种假设只是种抽象机制而已。当出现分页失败时或是某些内存读取时漏洞就会出现,处理时间会比其他内存慢几毫微秒。

SQL语言希望把数据库查询的程序抽象化,让你只要定义想要的东西,查询动作的细节就交由数据库去处理。不过在某些状况下,有些 SQL查询比逻辑上相等的查询慢上几千倍。这有个很有名的例子,在某个SQL服务器用"where a=b and b=c and a=c"来查询,会比用"where a=b and b=c"快上许多,可是查询的结果其实是一样的。照道理只要指定规格,并不需要在意程序。可是有时候抽象机制会失效并导致很差的效率,于是你就得跳出来用查询规划分析器找出问题,然后想办法加快查询。

NFS或SMB之类的网络程序库,能让你「像」处理本机文件一样地处理远程机器的文件。有时候网速会变得很慢或是断线,这时远程文件就不再像是在本机上了,而身为程序员的你必须加程序代码来处理这种状况。「远程文件和本地文件一样」的抽象机制出现漏洞了。 这里有个Unix系统管理员的具体例子。如果你把使用者的home目录放在用NFS挂入的硬盘上(一种抽象机制),而使用者建了一个.forward文件把他们的电邮全部转发到其他地方(另一种抽象机制),如果新邮件进来时NFS服务器停掉了,由于找不到.forward档信息并不会被转寄出去。这个抽象机制的漏洞就真的会把一些信息丢掉。

C++字符串类应该能让你假装字符串是个第一级(first-class)资料。它们尝试把「字符串很难处理」这个事实抽象掉,让它使用上像整数一样容易。几乎所有C++字符串类别都会重载+运算符,才能把字符串连接写成s + "bar"。不过你知道吗?不过怎么努力,世上还是没有C++字符串类能让你写成"foo" + "bar",因为C++里的字符串常数一定是char*,绝对不会变成字符串。这个抽象机制呈现一个程序语言本身不给补的漏洞。(有趣的是,C++随时间演进的历史,可以描述成尝试用修补字符串抽象机制漏洞的过程。他们为什么不直接在语言本身加个原生的字符串类别?这实在让我搞不懂。)

再来就是下雨天时开车没办法开得和平常一样快,虽然车上有挡风玻璃雨刷有头灯有车顶还有暖气,这些装备应该是让你可以忽略下雨这个事实 (他们把天气抽象化了),不过看吧,你还是得担心天雨路滑,有时候雨甚至会大到你看不远,所以在只好慢慢地开,因为基于抽象渗漏法则,天气永远不能完全被抽象化。

抽象渗漏法则会造成问题的原因之一,是因为它说明了抽象机制并不真能照原构想简化我们的生活。当我想训练某人成为C++程序员时,最好能完全不教char*和指针运算,直接去学STL字符串。问题是总有一天他们会写出"foo" + "bar"这样的程序然后看到怪事出现,于是我就得停下来教他们有关char*的事情。他们也可能会试着调用某个需要OUT LPTSTR参数的Windows API函数,于是又得把char*、指标、Unicode、wchar_t以及TCHAR含入档搞懂,才会知道如何调用。而这些全都是漏洞。

在教COM程序设计时,最好只要教学生如何使用Visual Studio的精灵和各个程序产生功能。不过万一出了任何问题,他们根本不会知道怎么回事,也不知道如何除错或回复。我还是得教他们IUnknown和CLSID还有ProgIDS以及。哦,饶了我吧!

在教ASP.NET程序设计时,最好只要教学生可以在控件上双击,然后就能编写使用者点击该控件时在服务器执行的程序。不过处理超链接(<a>) 点击事件的HTML程序,和某个按钮被按时的处理程序是不一样的,而ASP.NET实际上是把这之间的差异抽象化了。问题来了,ASP.NET的设计者必须把HTML无法由超链接传送表单的事实隐藏起来。他们的做法是在超链接的onclick事件加上几行JavaScript程序。不过这种抽象机制也有漏洞,如果使用者关闭JavaScript功能,ASP.NET的应用程序就不能正常的运作了,万一程序员又不了解ASP.NET抽象掉什么东西,根本不可能知道出了什么问题。

抽象渗漏法则表示,当某人发明一套神奇的新程序设计工具,可以大幅提升效率等等,就会听到很多人说:「应该先学会如何手动进行,然后才用这个神奇的工具来节省时间。」程序设计工具假装抽象掉某些东西,和其他所有抽象机制一样都有漏洞,而唯一能适当处理漏洞的方法,就是弄懂该抽象原理以及所隐藏的东西。所以抽象机制虽然替我们节省了工作的时间,不过学习的时间是省不掉的。

而这一切都似非而是地表示,即使我们拥有越来越高级的程序设计工具,抽象化也做得越来越好,要成为一个纯熟的程序员却是越来越难了。

我第一次去微软实习时,写了一个在苹果机上执行的字符串程序库。那是一个很典型的任务:写一个自己的strcat函数传回指向新字符串结尾的指针。只要写几行C就够了。我做的每件事都写在K&R里面(一本讲C程序语言的薄书)。

今天为了要做CityDesk,我必须会Visual Basic、COM、ATL、C++、InnoSetup、Internet Explorer内部机制、正则表示式、DOM、HTML、CSS以及XML。一大堆比古老的K&R更高级的工具,可是我还是得会K&R 讲的东西,否则我就完了。

我们十年前可能想像过,现在会有某些全新的程序设计规范让程序设计更容易。事实上这些年间所建立的抽象机制,的确让我们能处理更高复杂度的软件开发(如GUI程序设计和网络程序设计),这是十或十五年前无法处理的。这些伟大的工具(比如OO型式的程序语言)虽然能让我们用飞快的速度完成许多工作,不过总会有一天我们得去追查因抽象渗漏而产生的问题,到时候就得查上两星期了。另外虽然你得雇一个以写VB程序为主的程序员,不过单纯的VB程序员是不够的,因为当VB的抽象机制渗漏时他们就完全卡住了。

抽象渗漏法则正在拖垮我们。

这些网页的内容为表达个人意见。

Personal tools