文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> 资讯>Jamie Zawinski访谈:在折腾中成长

Jamie Zawinski访谈:在折腾中成长

时间:2010-10-09  来源:cnblogs

  文 / Peter Seibel  译 / 李琳骁

  Jamie Zawinski(简称jwz),Lisp黑客、Netscape早期开发人员。Zawinski十几岁开始编程,一直投身Lisp和人工智能领域,浸染于黑客文化。领导开发了XEmacs,后来成为最著名的开源分支之一;Netscape浏览器Unix版本及其后Netscape邮件阅读器最初的开发人员之一;与Brendan Eich一道,通过mozilla.org促成了Netscape浏览器的开源。目前在旧金山经营夜总会,力争让它成为各年龄层都能进入的现场音乐表演场所。

  更差就是更好

  Seibel:你好像对过度设计非常反感。

  Zawinski:是的。今晚产品必须给我发布!重写代码,让它更清晰,这种方式固然很不错。但这不是重点,你上班不是为了写代码,而是要发布产品。

  Seibel:沉溺过度设计的人常常会说:“嘿,只要这个框架准备妥当,以后一切自会水到渠成。总的来看,我这么做其实是在节省时间。”

  Zawinski:那终究只是理论。

  Seibel:是的,不过有时这个理论也能成真,只要主事者有良好的判断力,框架也不是太过精致,的确能节省时间。你能讲讲自己属于哪一类吗?

  Zawinski:虽然是陈词滥调,不过我还是要重提:更差就是更好(worse is better)。假定你花时间构建了完美的框架,满足了你的全部需求,从1.0版一直用到5.0版,一切都很棒;猜猜结局如何:1.0版发布用了三年时间,而你的竞争对手只用六个月就发布了他们的1.0版,结果就是你出局了。

  你的竞争对手六个月就推出的1.0版,代码质量低劣,他们可能得花上两年时间重写代码,那又怎样?他们有机会重写,而你早就丢了工作。

  Seibel:很多时候,也许是期限逼近,时间紧迫,你扔掉了大块代码,因为你认为另起炉灶反而更快。

  Zawinski:是的,一定会碰到,那时你得赶紧脱手,避免更多损失。

  Seibel:就是这一点导致开源软件开发中你深感遗憾的无休止的重写?

  Zawinski:是的。但撇开效率不谈,从另一角度来看,写自己的代码远比弄清楚别人的代码来得有意思。这一切就那么自然而然地发生了。其中一点就是所有东西总是在不停重写,结果一样都没完成。如果你是那些开发人员之一,那也不错,因为总有东西折腾,当然前提是你更热衷于捣鼓计算机,而不是将其作为达成目的的手段。

  以编程为乐

  Seibel:说到捣鼓计算机本身,你现在是否仍以编程为乐?

  Zawinski:有时。我现在净干些系统管理员的脏活,我很受不了,也从没喜欢过。我喜欢做XScreenSaver的相关开发,从某些角度来看,屏幕保护程序(即实际的显示方式而非XScreenSaver框架本身)堪称完美程序,因为它们基本上都是从头写起,养眼好看,绝无所谓的2.0版本。

  Seibel:你喜欢做数学计算、求解几何和图形之类的谜题?

  Zawinski:是的。以这种方式显示,这个抽象的小方程式会是什么样?或者,怎样才能让这些方块移动时更生动,不那么生硬,就像是计算机在正常搬移东西?诸如此类的问题。还有,怎么处理这些正弦波,才能让它看上去更像是在弹跳?此外,我还会写些简单蹩脚的shell脚本,聊以自用。

  Seibel:除了有两百万人用上你的软件,你还以编程的哪些方面为乐?

  Zawinski:这个问题有点难。我想大概是解决问题的过程。

  Seibel:你感觉到代码的美吗?美感是否在可维护性之上?

  Zawinski:是,当然是。任何东西只要表达恰当,不论精炼,抑或平淡,都是具有美感的。

  Seibel:你认为编程和写作是类似的智力活动?

  Zawinski:从某些角度看,我认为是这样。当然,编程要严格得多。但就表达思维的整体能力而言,两者非常相似。不要不着边际,说出口之前先想一下准备说什么,然后尽量言简意赅。我认为这正是编程和写文章的共同点。

  优秀和差劲程序员的区别

  Seibel:接下来我们聊点编程的细节。你怎么设计自己的代码?如何组织代码的结构?不妨以你最近OS X上的XScreenSaver移植工作为例讲讲。

  Zawinski:好,首先我会随意鼓捣一番,写些短小的演示程序,最后不会再用。

  接着,为每个X11调用创建一个空函数(stub),然后再开始慢慢逐个实现,弄清楚自己准备如何实现这个,怎么实现那个。

  另外,在Mac平台上,需要编写启动代码。这有点像粗线条绘制,搭建基础框架。剩下的就是一个接一个地移植屏保护程序。

  Seibel:这么说来,针对每个X11调用,你都要编写相应的实现。你有没有发现自己累积了大量非常相似的代码?

  Zawinski:有,当然有。通常当你第二或第三次剪切和粘贴相近代码时,就不能再剪切和粘贴了,而应抽取成子程序。

  Seibel:假定再次开发规模与邮件阅读器相当的软件,你前面提到开始会写下几段文字,列出一组功能特性,这是你着手编写代码之前所做的最细粒度的准备吗?

  Zawinski:是的。也许还会简略描述库和前端的差别。不过也可能不会。如果是独自一人开发,我不会关心这些,毕竟那部分我再清楚不过了。随后,我采取的第一步是自顶向下或自底向上开始。无论采用哪种方式,我都会先在屏幕上显示一个窗口,包含若干按钮,然后逐步深入,开始构建那些按钮的功能。

  我发现尽早在屏幕上显示一些东西,有助于集中注意力去解决问题。这能帮我决定下一步做什么。

  Seibel:你是否经常重构以保证代码内部结构的一致性?或者你一开始就很清楚如何将代码各部分整合在一起?

  Zawinski:通常我一开始就很清楚。编写程序的第一个版本时,我一般会把所有代码写在一个文件里。随后,我开始分析那个文件的结构,比如有几段代码非常相似。那些代码已有上千行,何不把它们挪到另一个文件里。另外,只有真正开始编写代码,发现情况不受自己掌控,你才能体会到这点。

  Seibel:我注意到优秀程序员和差劲程序员的区别之一是,优秀程序员在不同抽象层之间切换自如,游刃有余,修改时仍能保证各层独立,并且选择最合适的那一层进行修改。

  Zawinski:显然决定在哪里进行修改很有讲究,而且可能关系非常大。

  对我而言,我认为最重要的一点是在构建全新的程序时,应当想办法尽快写好自己能用的程序,哪怕只实现一点功能。这样你就能真正知道下一步做什么。

  调试经验谈

  Seibel:下面,我们再谈谈调试相关的话题。对初学者而言,你推荐哪个调试工具?打印语句?符号调试器?形式证法证明程序正确性?

  Zawinski:过去这些年里变化太大。当初使用Lisp机器时,我做了一些修改,基本上Lisp侦听器(listener)就成了检查器,只要它打印出对象,就会出现一个上下文菜单,你可以点击菜单项,返回指定的值。这么一来,很容易跟踪一组相关对象和类似的东西。这就是我早期思考问题的方式。深入代码内部,来回修改,不断试验。

  后来,我开始编写Emacs内部的C代码,使用GDB时,我试图沿用同样的方式。不过一直没有取得很好的效果。随着时间的推移,我渐渐地不再使用这类工具,而是直接插入打印语句,重新运行程序。如此反复,直到搞定为止。如今,人们似乎不清楚何谓调试器,大多数人都用打印语句。

  Seibel:这其中有多少是因Lisp和C语言的区别而非工具的区别所致?一处区别是在Lisp里你可以测试一小部分,调用你不确定工作正常与否的小函数,然后中断函数执行,检查运行状态。而C代码呢,复杂之极,必须运行整个程序,然后在某个地方设置断点。

  Zawinski:与C语言相比,Lisp这类语言本身更适合调试。另外Perl、Python和类似语言在这方面也更具Lisp的特质,不过我还没看到多少人真的按照Lisp的方式去做。

  Seibel:你们是否使用断言,或其他比较正式的文档编写方式或真正检查不变量的方式?

  Zawinski:显然,插入断言语句对调试而言是个好主意,如你所说,还有利于文档化。但随之而来的问题是,在产品代码中,断言失败时会怎么样?你会怎么做?我们商定的做法是返回零,好让它继续运行下去。

  许多程序员都有种本能:“我必须呈现错误消息。”不,根本不用。没人会在意那个。

  Seibel:你会为了调试而逐句查看程序,或者,如有些人建议的那样,写好程序之后,把逐句查看作为检查代码的方法?

  Zawinski:不会。只有调试程序时,我才单步查看代码。有时是为了确认代码写得没问题。但很少这么做。

  Seibel:那你是怎么调试代码的?

  Zawinski:我会先审读代码。然后插入一些代码,尝试解决存在的问题。总之视情况而定,很难一概而论。

  Seibel:与调试相关的,是测试。在Netscape,你们有专门的QA组,还是你们自己测试所有项目?

  Zawinski:两个都有。我们会一直运行软件,那是最好的一线QA。另外我们有个QA组,他们会从头到尾做详细的正式测试。

  Seibel:那么开发人员那一级的测试呢,比如单元测试?

  Zawinski:没有,我们从来不做那类测试。

  软件维护

  Seibel:说到这个,正好聊聊软件维护相关的话题。你怎样设法理解别人的代码?

  Zawinski:我会直接一头扎进去,开始阅读代码。

  Seibel:那么你会从哪里开始呢?从第一页开始,按顺序读下去?

  Zawinski:有时会这么做。更常见的是学习如何使用某个新的库或工具包。幸运的话,你能找到一些文档,还有API。最后弄清楚自己可能会用到的那部分,或者弄懂它是怎么实现的。按这个思路一直做。或者,对于诸如Emacs的程序,有可能从底层着手。基本上就是不断抽取,直到现出骨架。

  Seibel:我们讨论过重写为何比修正更有趣,但重写并不总是好主意。我想知道你怎么拿捏两者之间的界限?

  Zawinski:一开始我只是修正缺陷,并试着做些优化,结果原有代码不见踪影,后来几乎变成了重写。

  当然,我在Lucid Emacs里添加的许多东西不像重写字节码编译器那样有充足的理由。实际上,我做许多东西的动机在于让它更像Lisp机器,更像我熟悉的Emacs,而那其实是我熟悉的Lisp环境。于是我添加了大量东西,设法让Emacs在许多方面不再是半吊子的Lisp,比如应该用事件对象取代包含数字的链表。现在回想起来,那些修改当属最大的问题。那类修改导致与第三方库的兼容性问题。

  Seibel:当然,那时你不知道会出现两个Emacs。

  Zawinski:的确。不过即使没有XEmacs,也不会只有一个Emacs,也无法避免兼容性问题。事后看来,如果我早意识到那些修改有那么大的影响,我也许会采取不同的做法。或者多花些时间,让原来的方式也能工作。

  Seibel:代码可读性事关维护,前面你谈到一些编写易读代码的做法,有哪些特性可以让代码更易读?

  Zawinski:嗯,显然是注释。写下期望是什么,实际又做了什么。如果是创建数据结构,那就描述其成员布局。

  Seibel:那结构呢,你是以自顶而下还是自底向上的方式组织自己的代码?

  Zawinski:通常我会把叶节点放在文件顶部,尽力保持那种基本结构。然后,通常是在顶部之上,编写API注释说明。

  Seibel:那么假定为了进一步论证,你准备重新出来工作,组建一个开发团队。你会怎么组织安排?

  Zawinski:在我看来,最好的安排是一个团队不超过三个或四个人,成员之间紧密合作,每天一起共事。这种做法可以按比例放大很多倍。

  Seibel:怎么协调这些团队呢?

  Zawinski:我们会约定好各模块之间的接口。就我的理解,要让模块之间交互自如,最佳做法就是保持模块本身真正简单,减少可能出错的途径。

  至于怎么划分则完全视项目而定。

  Seibel:这么说来,在Netscape,你们会把事情分割开来,每个人负责软件不同的模块。有的人认为那么做很重要,其他人则认为团队共同拥有所有代码的做法更好,你怎么看?

  Zawinski:两种方法我都用过,各有优势。让每个人都拥有全部代码,我认为不切实际,因为代码实在太多。

  Seibel:当还是资历尚浅的程序员时,你导师做了哪些对你有帮助的事情?

  Zawinski:我觉得关键在于他们能意识到什么时候该提升员工的等级。

  Seibel:你阅读代码主要是因为你正在开发相关功能,抑或你只是想探究它是怎么工作的?

  Zawinski:只是到处看看,我想知道那是怎么工作的。把东西拆开的冲动是将人们带入这一行当的一大原因。

  对自学的程序员的建议

  Seibel:你觉得自己自学了计算机科学,抑或只是学习编程?

  Zawinski:嗯,这些年我的确学了些计算机科学,但目标是学习编程。让机器做事情是目标,计算机科学则是达成目标的手段。

  Seibel:你是否认为那是种缺失,有没有想过但愿自己曾以更系统的方式学习过计算机科学?

  Zawinski:有时的确会有那种想法,特别是早期,我会想:“天哪,我什么都不懂。”这只会叫人窘迫,还会让人缺乏安全感。要是多花点时间在求学上,我的生活的确会全然不同,不过那时我做了我该做的。

  Seibel:你有过相反的感觉吗,觉得身边的计算机科学家并不像自己那样懂得编程的真谛?

  Zawinski:我经常有那种感觉,不过,“哇,你们这些家伙搞错对象了。”这种想法其实并不多,更多是觉得:“哇,我们只是兴趣不同。”

  Seibel:你主要是靠自学的。对那些自学的程序员,你有什么建议?

  Zawinski:我不知怎么就跌跌撞撞做了程序员。我当时做的一些决定,导致了其他决定,最终成了现在的我。

  我不时收到邮件,内容大体是“我想成为程序员,我该怎么做?”或是“我该不该上大学?”我怎么回答得上?要是在1986年问我,我也许还有不错的答案。现在人们已不可能循着我当年的路走,因为那条路已经无迹可寻。

  Seibel:计算机方面的书呢?哪些计算机科学或编程书籍是必读的?

  Zawinski:老实说,计算机书我读得并不多。我一直都推荐的书是《计算机程序的构造和解释》(Structure and Interpretation of Computer Programs),许多人都怕读这本书,因为Lisp味太浓。不过,这本书在不教语言的前提下教授编程,做得非常到位。

  还有一本书,是关于调试的,微软员工写的【译者注:疑为微软出版社1993年出版,Stephen A. Maguire的Writing Solid Code - Microsoft Techniques for Developing Bug-free C Programs,图灵影印版《编程精粹:编写高质量C语言代码》】,主要介绍如何有效使用断言。还有本书叫《设计模式》,人人追捧,称其为当时最好的作品,不过在我看来,这本书一派胡言。

  捣鼓折腾很重要

  Seibel:有程序员必须具备的关键技能吗?

  Zawinski:嗯,好奇心,把东西大卸八块的好奇心。好奇心是获取知识的主要途径。把东西拆开,用心研习,才能做好自己的东西。至少我是这么做的。计算机的书我读得很少。我的经验主要来自不断挖掘源代码和参考手册。

  Seibel:你读过Knuth的《计算机程序设计艺术》【编者注:即将由人民邮电出版社出版】(The Art Of Computer Programming)吗?

  Zawinski:没读过。这也许是我真正该读的一本书。

  Seibel:这本书很难读,需要很好的数学功底才能真正读懂。

  Zawinski:数学我可不在行。

  Seibel:很多程序员都有数学背景,大量计算机科学理论都离不开数学。这么看来,数学也并非不可或缺,你就是很好的例子。想成为优秀程序员得具备多少数学知识或数学化的思维?

  Zawinski:嗯,那要看你怎么划分,什么算是数学的,什么不算。

  不过,我还不至于认为做程序员不需要数学。但是,我总觉得比起数学,编程与写文章有更多共通之处。这就如同你正在写故事,尝试向非常愚钝的人——词汇有限的计算机——表述观念。你已经掌握自己想表达的观念,以及用于表达的那些工具,你会使用哪些词,序论和总结陈述会写成什么样?编程也大抵如此。

  谈到文章,口味问题就凸显出来了。用一段文字描述某样东西,可以描述得体,也可以描述出彩,很有特色。这些同样适用于程序。程序可以只是完成任务,或者,只要组合得好,还能做到容易理解。

  Seibel:为什么口味很重要?只是为了让自己满意,还是从实践角度来说优美的代码更好?

  Zawinski:很大程度上,优美和易维护是相似的,或者说息息相关。

  Seibel:你是否认为,如今在编程上能获得成功的人已不同往常?

  Zawinski:当然,现在已不太可能从无到有编写没有任何依赖的程序。

  Seibel:要是你现在只有13岁,看到现在编程的方式,你还会被吸引吗?

  Zawinski:这太难回答了。我不认识13岁大的孩子,也不知道当下的世界变成什么样了。

  我觉得正是折腾捣鼓,比如拆开磁带仓背部,查看齿轮是怎么啮合在一起的,这种探索吸引我走上了编程之路。除了乐高机器人(LEGO Mindstorms),在我看来,现在人们已经没什么机会循着我当年那条路成长。不过,也许我是错的。

  Seibel:另一方面,编程本身也变得更容易。只是让计算机做些常规任务的话,你根本不必一开始就掌握晦涩复杂的汇编语言。

  Zawinski:没错。我觉得今天的孩子想要编程可以从搭建Web应用或编写Facebook插件等开始。搭建LiveJournal的Brad Fitzpatrick是我朋友。当初写LiveJournal时,他只是随便玩玩,写了个Perl脚本,以便他和朋友可以用它留言:“我准备吃午饭去了。”他开始的方式就是写个简短的Perl脚本,然后放在Web服务器上。这种现象也许会愈演愈烈。

  本文节选自《Coders  At Work》中文版(即将由人民邮电出版社图灵公司出版)。该书是当今世界15位大师级计算机程序员的访谈录,重点介绍了他们的编程感悟。


  

相关阅读 更多 +
排行榜 更多 +
辰域智控app

辰域智控app

系统工具 下载
网医联盟app

网医联盟app

运动健身 下载
汇丰汇选App

汇丰汇选App

金融理财 下载