测试一下自己算不算出色的程序员
极出色程序员的迹象
我多希望自己拥有这些特质,但可惜没有,我之所以能把它们写下来,是因为我在别人身上观察到了这些特质。常常有那么一刻,我觉得自己正拥有其中一种特质,但那些时候弥足珍贵。这些特质正在逐渐消失,并遭到了那些孤僻学者的刻板成见。而这些特质往往得之不易:如果你想成就卓越,那你必须准备好为此付出代价。
1.永远保持耐心
特征
火灾警报让你感到心烦胜过恐慌。
叫不出广播里播放的歌曲名称,或从听筒里传出的电话彩铃。
很清楚室友去喝咖啡、洗澡或上医院的次数。
对办公室争斗不在乎。
代码还没运行就能预知其中的 bug。
如何获得这种特质
幻想会导致分心。我写这篇文章的那天就发现自己完全不能集中精力,当时我在蒸桑拿,而有个人在健身房唱法语歌让我很恼火。歌声在桑拿房外面飘来飘去,彻底把我惹火了。我非常希望他能停下来不要再唱了,因为我实在没办法集中注意力。我在脑子里把他想象成一个不管别人感受的男人,一个穿着粉色衬衫颐指气使的变态。接着我走出桑拿房发现,那是个红褐色皮肤的老人,他就像一个带有纽扣眼睛的破旧泰迪熊,哪有我想象的那么危险。他开始唱《 La Vie en rose 》,这是我很喜欢的一首歌,然后我就纳闷自己是不是很久以前就变成了一个让人讨厌的混蛋。
我不知道如何才能避免分心,但如果我曾经尝试去这么做,那我可能会觉得“这歌声夹杂了丝丝敬意又饱含魅力”,而这种魅力又会指引我的想象,而不是反过来由主观臆想来判定那歌声的魅力。每当我要失去耐心的时候,我都希望自己能不带个人偏见地去对待生活。
2.不顾一切地追求完美
最糟糕的优化通常是为了追求利益而非为了美,而二者之间只有美才更长存。追求完美不等同于沉迷,但它们之间的关系确实非常密切。
特征
宁愿辞职也不愿妥协。
对规定的验收日期不屑一顾。
在截止日前夕大量重构代码。
不愿意接受奖金、升迁或是短期的优先认股权。
很喜欢由斯坦利·库布里克( Stanley Kubrick )执导的电影。
如何获得这种特质
正如 Tyler Durden 所说“你必须知道,抛弃恐惧,面对你终将死去的事实”。你那拥有宜家家具的漂亮公寓只是生活的附属品,而不是生活的奖励。如果你不是个独特又出色的人,那你创造出来的东西应该是。
追求完美也被认为是对自己的工作感到自豪。记住,理智对待代码是一种美德,但这不意味着避免把感情带入工作也是一种美德。实际上,理智对待代码的另一种方法是把兴趣放在结果上。你应该思考的结果犹如一位女士,如果她不能抢在下午 4:59 这一分钟内把你的程序交付出去,那她就会被炒鱿鱼(译者:这么漂亮的姑娘,你应该舍不得她因为你被解雇吧)。
有这样一个传说,一个营销人员在沃尔玛( Wal-Mart )为 Sam Walton 工作,有一天他/她想出了一个很棒的活动计划为零售品做广告。Sam 看了一眼提案然后说了一大堆话,大意是“太棒了,现在算算这个活动的开销,然后把这些开销用来降低零售品的价格吧”。从这个故事发现,不做活动反而比做活动能卖出更多零售品,创造出更多的利润。
在脑子里好好想想这个故事传达的精神,思考一下如何将这个故事映射到自己的工作中去。你的 boss 也许不像 Sam Walton,但可能你和 Sam 有一点点像呢。是选择像别人希望的那样妥协更好,还是应该选择坚持把产品做的更好,哪怕只是微小的提升?
这可能会不利于你的收入,对优先认股权也有风险。但只要你工作干得好、做事像样,按应该使用的方式完成一个项目,那总有一天时间会原谅所有的任性。或许有一天你的 boss 会郑重地把你叫回来,为以前的事情向你道歉。
3.精通平台
绝大部分程序猿都知道手头工具的寿命期很短,也不会花功夫去记住哪些工具注定会被淘汰。同样,绝大多数程序员都没有重视这样一个事实:这个行业的一切都是早先积累的产物,它们之间有共同的秩序和规则,而这些东西的存在时间会比我们的寿命长得多。最优秀的程序员们都在践行牛津大学一贯坚持的原则:学会拉丁和数学,走遍天下都不怕,因为你已经掌握了理解一切事物的钥匙。(译者:也就是已经抓住了事物的本质,掌握了学习的精髓。)
特征
可以凭记忆背诵 C 标准库里的所有头文件。
提到“ 500 mile email ”的时候,扬扬眉毛一副早就了然的样子。
书架上有《 OpenDoc Programmer’s Guide 》的复印本,太久没看上面落了一层灰。
可以完整说出《魔戒 | Lord of the Rings》、《星际大战 | Star Wars》,《红矮星号 | Red Dwarf》或《蒙提派森 | Monty Python》中的任何一句对白。
可以快速定位一个由 TCP 滑动窗口( TCP’s Sliding Window )算法引起的同步漏洞。
可以识别出由于测试 CPU 上发生微指令错误而引起的 bug。
有一张来自 Donald Knuth 的个人支票,价值 2.56 刀
译者:因为曾在 Donald Knuth 出版的书中发现过错误而得到这个支票奖励,详见 Knuth reward check。
如何获得这种特质
要达到广博的知识面需要花费数十年的时间,但世界上每一位大师都是通过每天都做相同的三件事才达到这个水平,这三件事大致是:
努力解决他们认为很难的问题。
记录他们是如何解决难题的。
反思他们解决难题的过程。
从前,有一个程序员菜鸟被一个他搞不明白的程序 bug 难倒了。在这个令人崩溃的报告里全是看不懂的数字,比如 -32760。这些数字到底从哪来的?他按下 Ctrl-F ,在代码里到处找“ -32760 ”,但是一无所获,没有发现任何有用的线索。 他花了一个星期的时间返回去看大学时用的破旧计算机科学课本、编译器手册,几乎什么都找过了,最后一天的时候,他那呆滞的目光突然落在了一个数字表上。他的精神早已疲惫不堪,但透过思维的迷雾他猛然认出了其中一个数字: -32768。他心里想这个数字和自己要找的那个实在太像了,接着他注意到这个数字表格显示的是几种整型的表示范围,以及每种类型都有带符号和不带符号两种版本。真相的出现让人措手不及。
对这个问题迟来的洞悉让他非常激动,于是他为此写了一篇博客。很快这篇文章就消失得无影无踪,没什么人阅读,只有一群给力的小伙伴支持着他。那一夜他失眠了,一直想着那个 bug 、整型变量、由编译器来检查变量类型的利弊等等。
十年后,我们的这位朋友成为了公司的程序员主管。有一天,他眼睛一扫,发现一个初级程序员正耷拉着肩膀,显然这个人是遇到了挫折。输出窗口上显示了一连串调试跟踪信息,还有一个数字 -32762 。如今已是专家的他拍了拍这个新手的肩膀,并说“你是不是把一个无符号的 16 位整型值赋给了带符号的 16 位整型变量了?”。
如果现在没有遇到让你感觉棘手的问题,那你需要换一份工作,或者换个爱好,或者换个舞台,或者改变一下其他什么事情。在你的工作中或学校里,找机会做做新事物;尝试破解你的 Roomba 机器人;从一个好几个月都没人碰过的开源项目中找出 bug ,并修复它;尝试在 StackOverflow 上回答那些荒废已久没人回答的问题,这会迫使你去查阅那些你不懂的知识。
如果你能带上一个有魔法的放大镜,看看一个大师的大脑内部构造,你可能会发现有大量的神经元包围着视觉皮质。这些神经元就像臭名昭著的“ Grandmother cells ”,它们长年累月地休眠着,但只要看到了某些象征,它们就会被激活,比如一个 2 的幂次函数、精度可疑的延迟(意味着 DNS 超时)、奔腾浮点除法错误( FDIV bug )的信号。这些“ grandmother cells ”只有通过如此艰难的方式才能形成。
4.用代码表达思想
特征
随意交谈中,他们那些信手拈来的暗喻都来源于编程结构的灵感。
虽然大部分时间都在“游手好闲”,但每天都比同事提交更多无 bug 的代码。
站在后面看你的代码,并用手指出其中的错误。
无论是喝醉了还是躺在床上,通过电话就能正确诊断出代码的 bug。
洗澡的时候想出了他们最棒的代码。
面对一个很顽固的 bug,他们的直觉是起身出去走走。
在交谈的中途突然停顿发呆,然后什么都不解释就抛下你,快步走向电脑。(这又叫做“ A Columbo Moment ”或“ Gregory House behavior ”)。
译者:“ A Columbo Moment ”或“ Gregory House behavior ”是一类怪异但预示着有重大发现的行为。
如何获得这种特质
就拿那些捣蛋鬼和他们的手机来说,一个 12 岁的小姑娘怎么能够在数字键盘上如此快速地发短信呢?这不是遗传,因为所有乳臭未干的小孩都能做到,不论是男是女,不论父母是谁;这也不是培养出来的,因为社会各个阶层的孩子都能做到。你想来想去想破了脑袋,最后得到这样一个古老的真相:人们用语言来表达思想才学会了说话。一个青少年的手指头知道发短信该按哪里,这是他们用发短信的方式来表达。在编辑短信的时候,打错字就会感觉到不对劲。那些学习多种口语并经常使用的人倾向于用多种语言来表达自己的思想,在经过长期训练之后,他们就不再需要先在脑子里翻译一遍。不用把读入的俄语词组翻译成英文后他们才能明白其中的含义,他们就是用俄语的方式来理解。
你不能想着“向后开炮”,然后翻译成俄语,你应该用俄语思考如何表达。
如果你听说过萨丕尔-沃尔夫或读过《 1984 》等诸如此类的书,那或许你已经领会过这种隐喻:文字传递的是理念,语言体现的是思想。无论你脑子里掌握的是句法语言,还是可视化或听觉型的语言,这些都没关系,重要的是你的大脑如何处理这些符号以及操纵这些符号的规则。
要获得这种特质,你最好读一读由 Abelson 、 Sussman 和 Sussman 共著的《计算机程序的结构与解释 | Structure and Interpretation of Computer Programs 》,并完成书中的练习。 这本书使用了 Scheme 语言介绍每一课,即使那不是你写程序用的语言,它也仍然是教你学习编程的最佳语言之一。记住:学会数学和拉丁,就能理解任何事物。
不管你有没有这本书,关键在于练习写代码,直到你能像对待自己的母语那样阅读和思考代码。你不可能在 30 天内就学会这项技能,这或许要花 30 个月以上。当你开始用代码来表达自己的思想,就会知道自己是不是已经获得了这个特质。
5.入乡随俗
我认为自己做不到这点,因为我就是喜欢用 MonoTouch 来写 iOS 下的应用。我确实了解Objective-C,也能用它编写应用程序,但我最爱的还是 LINQ (集成语言查询)。如果我要为这个规则给出一个例外,可能就是“入乡随俗,但在罗马会计部门的话,做一个会计该干的事。”尽管代码运行在解释器或其它层上会对性能或特性不利,但选择某种适合特定领域的语言并不总是错误的。就连那些极好的程序员们也从不拒绝跟硬件打交道,而且还会学习相应的本机语言。抽象都是有漏洞的。(译者:语言层面上的抽象不是万能的,总是存在漏洞,你应该通过了解底层硬件,从而在语言提供的抽象层面之下去思考并解决遇到的问题。)
特征
不会下意识地对跨平台的框架感兴趣。
鄙视“语言之战”。
没有看到用多种语言维护同一个程序在策略上存在的劣势。
把产生 bug 的责任归咎于编译器、函数库或操作系统之前,知道自己的代码才是根源。
派分到基于 Linux 或 Android 平台的项目之后,会在自己的隔间里放一个毛绒燕尾服企鹅或安卓机器人。
工作环境不变,但不断更换手机或平板品牌。
在确认诸如 double 或 decimal 等数据类型能否按他们设想的在新设备上运行之前,先查阅一堆技术手册。
如何获取这种品特质
平台多样性对这类家伙而言,就像同一个餐盘中的多种蔬菜一样平常,让他们感到轻松自如。我之前说过“用代码作为思维表达的方式( thinking in code )”和“理智对待代码( emotional detachment )”都是美德,而这个特质就是前面这两种美德的附加福利。虽然这些程序员很重视抽象,但他们并没有自然而然就欣赏泛化。如果一个新平台没有任何优势,那最初为什么创建它呢?
由于我们可以用软件解决上千种问题,因此就会有上千种计算机语言存在。在二十世纪八十年代首次推出麦金托什( Macintosh )以后,有上百种DOS产品移植到了这个鼠标驱动的新平台。这些产品从头整顿基于 Alt 的用户界面,并粗暴地将台式机的键盘驱动范式转向Mac的视觉氛围。这些DOS产品中的大部分都被苹果公司或市场淘汰掉了,就算它们还想卷土重来也已经落人之后,因为已经有人快速地翻开了这本装帧成册的人性化界面指南(HIG)并如饥似渴地在阅读。
或许 Excel 曾经需要模仿 Lotus 1-2-3 (电子表格的开山鼻祖,由 Lotus 公司出品)基于斜线的菜单;或许 AutoCAD 如今仍然需要处理命令行,但这两个产品的设计者从未忽视这个日新月异的世界,这也是它们到今天还很著名的原因。就扩展来说, Objective-C 有 Categories , C# 有 Extensions ,但这两者不太一样,稍有不同。键值观察( Key-Value Observer )或许就像是事件( Event ),这跟说“机会等同于许可”表达的含义是一样的。
要获得这种特质,你必须从学习一个新平台开始,学习它独特的指令集和用户与之交互的方式。新平台的大部分外观设计得和你已经熟悉的平台非常相似,这样就能快速上手使用(那些“太过前卫”且改变剧烈的平台常常会失败),但也能让你注意到不同之处。安卓手机常常比 iPhone 更喜欢添加硬件按钮。或许那么做很不错,也有可能很糟糕,但用户们期望以后可能有程序会用上它们。不要让他们失望:毕竟,操控人们的思想可比控制晶体管难得多。
新平台要么会推出一种新的编程语言,要么推出一些独特的新约定,无论如何,你要学的其实就是个新的词汇表。尽管它看上去就像是拿了一个现有平台来进行“改造”,但这里谈到的改造必须是有意义的。他们都说“麦当劳巨无霸的特制酱不过是外面加了更多甜泡菜的千岛酱”。
要管理好一个面向多平台的单一产品,必须对你的产品进行抽象,而不是对产品要面向的平台抽象。你可以通过消除来实现,将关于平台特性的代码从产品的灵魂中抽离。如果你能掌握“渴望修复那些没出问题的东西”这条规则,然后大刀阔斧地修整你的代码直到它被你精简得所剩无几,那最后剩下来的部分就是应该留下的。
代码越简单,越好模块化;越容易模块化,就越容易解耦;越容易解耦,为了修复 bug 和添加特性而要修改的代码就越少;要改变的代码越少,就越容易将那些变化移植到其他系统。不要依赖自动化的方法——这就好像要依赖一只猫来为你系鞋带,不靠谱。
6.创建自己的工具
特征
建立了一个可自动创建的服务器。
写了一个自己的基准程序或专业分析器。
在 GitHub 上维护一个开源项目。
至少重造过一次 LISP。
知道什么是特定领域语言( Domain Specific Language ),为其中某个语言设计并写了一个解释器。
通过自定义宏来扩展 IDE 或 Editer。
桌上套着一个 Radio Shack 项目封皮,上面用 7 段显示器展示了 bug 追踪器抛给他们的问题个数。