程式设计领域的帕麦尔斯顿勋爵

作者:周思博(Joel Spolsky)
译:Paul May 梅普华
Wednesday, December 11, 2002
属于Joel on Software, http://www.joelonsoftware.com

曾经一度如果读过Peter Norton的一本书,就能完全了解在IBM- PC上写程式所需的全部知识。在过去20年间,全世界的程式师很努力地在IBM-PC上建立层层的抽象机制,让程式更容易撰写而且功能更强大。

不过[抽象渗漏法则](/wiki/The_Joel_on_Software_Translation_Project:%E6%8A%BD%E8%B1%A1%E6%BB%B2%E6%BC%8F%E6%B3%95%E5%89%87 “The Joel on Software Translation Project:抽象渗漏法则”)表示,即使他们建立了这些理应让程式更易设计的抽象机制,做个伟大的程式师所需的各种知识还是一直在增加。

要真正地精通某个程式设计领域需要好几年的工夫。当然也有很多出色的青少年学了一星期Delphi,再学一星期Python然后再学一个星期的Perl,就自认已经精通了。不过他们根本不知道自己差得有多远。

我打从ASP和VBScript刚出来就在用了。VBScript是世界上最微不足道的程式语言,而ASP程式设计大概只要上五堂课会了,而且其中只有两堂是会经常用到的。可是直到现在,我才感觉自已知道架构一个ASP/VBScript应用程式的最佳作法,我才终于觉得自己知道资料库存取程式最适当的位置,用ADO取得recordset的最佳作法,分离HTML和程式码的最佳方式等等。另外我也终于会用正规表示式,不再每次都重写一次字串操作函数。另外我上星期才学会如何取得不在记忆体中的COM物件,这样就就可以不需整个web伺服器重开就能重新编译。

Fog Creek太小了养不起专家,所以当我要为FogBUGZ(我们用ASP/VBScript制作的产品)写一个真正好的安装程式时,我得拿出数年C++/MFC和Windows API的经验,再用我还不错的Corel PhotoPaint技巧做出放在精灵角落的图片。另外为了让FogBUGZ能无误地使用Unicode,我还得用C++和ATL写一个小小的ActiveX元件,这里头有着数年的C++和COM经验,还有当初实作CityDesk时学了一周左右的字元编码知识。

所以当我们遇到某个只有NT 4.0才发生的怪问题时,我只花了三分钟就解决了,因为我知道如何使用VMWare,而且我有一套用VMWare灌的干净NT 4.0机器,另外我也知道如何用Visual C++做远端除错,还知道可以由EAX暂存器知道函数的回传值。完全没接触过这些东西的人要抓同一个问题,恐怕得花一个小时或更多的时间,不过我已经知道了很多很多「东西」,那些基本上是从1982年拿到我第一台IBM - PC和那本Norton书时就开始学的东西。

有漏洞的抽象表示我们面对一个直线上升的学习曲线:你可以用一星期学到每天工作所需知识的90%。不过其他10%可能得要好几年才能补齐。有些人会说:「不管你要我做什么,我都可以拿本书来就学会了。」真正有经验的程式师超越这种人的地方就在这里。如果你正在建立一个团队,当然可以找一堆经验较少的程式师用抽象工具制作出一大堆程式码,不过如果少了经验老到的人去做真正困难的事情,这个团队是做不起来的。

程式设计有很多不同的世界,每个世界都需要大量的知识才能真正的精通。以下是我个人最熟的三个领域:

1. MFC/C++/Windows
2. VBScript/ASP
3. Visual Basic

基本上这全部都可以称作Windows程式设计。没错,我也写过Unix或Java的程式,不过很少就是了。我对Windows程式设计的专精不光是了解基本技术,也知道整个支援的整体结构。我敢宣称对Windows程式设计很在行,是因为我也会COM、ATL、C++、80x86 组合语言、Windows API、IDispatch (OLE Automation)、HTML、DOM、Internet Explorer物件模式,Windows NT以及Windows 95内部机制,LAN Manager和NT网路以相关安全机制(ACE、ACL等等)、SQL及SQL Server、Jet和Access、JavaScript、XML,还有一些其他有关直角三角形斜边的有趣事实。如果不能在VB里用StrConv函数达成我的目的,我会为了用C++和ATL呼叫MLang函数而去写一个COM控制元件,眼睛连眨都不会眨一下。我花了很多年才达到这种境界。

还有很多其他程式设计的世界。有开发BEA Weblogic的世界,里头的人要懂J2EE、Oracle还有各种我列不出来跟Java相关的东西。另外也有硬派的麦金塔开发者,他们懂的是CodeWarrior、MPW、由System 6到OS/X各版本的Toolbox程式设计、Cocoa、Carbon、甚至还有现在已经没用的OpenDoc等过时的好东西。

不过只有极少数人能清楚一个以上的世界,因为要学的实在太多,除非在这些世界工作过几年,否则是不会真的全部都懂。

不过你却必须学会。

面试时因为没有Win32或是J2EE或Mac程式设计经验而被拒绝,大家都会觉得很生气。 或者某些笨蛋面试官其实根本不知道MSMQ,却打电话问面试者是否具有「五年的MSMQ经验」,也会让人觉得很不爽。

如果你刚写Windows程式不久,你可能认为Win32只不过是个程式库,跟其他程式库差不多,要用到时再去查书学着怎么呼叫就好了。你可能会认为基本的程式设计(比如你的C++专业技能)占九成,所有API合起来算是只占一成的小事,几星期就可以恶补回来。对这些人我只能小声地建议:时代已经变了。现在的比例是反过来的。

已经很少有人需要去做把位元组搬来搬去的低阶C演算法了。现在我们大多数人都把全部时间花在呼叫API而不是搬移位元组。一个没有API经验的C++程式高手,对用API写程式的日常工作内容其实只知道大约一成而已。当经济状况好的时候这并不打紧。你还是会得到工作,而雇主会花钱让你熟悉平台。不过当[经济不景气](http://sfgate.com/cgi- bin/article.cgi?f=/c/a/2002/10/20/IN.DTL)时,每个工作都有600个人申请,雇主有本钱选择已经精通该平台的程式师。比如说能列出四种Visual Basic中FTP档案的方法,还能指出每种方法优缺点的人。

这所有的程式设计世界的表相都很多,因此常常引发毫无意义的论战,争执哪个世界比较好。某位匿名者在我的讨论区写了以下这段自以为是的意见:

「再说另一个让我乐意留在『自由世界』的理由,言辞的自由(几乎),以及免于屈从安装程式和registry这种东西(还有很多,我只是举两个例子)的自由。 」

我认为这个人真正要说的是,在Linux世界里是不写安装程式的。嗯,我讨厌让你失望,不过你的世界也有些一样麻烦的东西:imake、make、config档等玩意。另外当你完成应用程式之后,要发行时还得附上20KB的INSTALL档案,里头全是些拿古怪装有趣的指示,比如「你会需要zlib」( 那是什么东西? )或是「这会要花一些时间,去拿一些runt吧。」 (我猜runt大概是某种糖果吧)。至于registry登录档,虽然你并没有用一个有组织的大结构(hive)存各个名称/值的组合,不过你有上千种不同的档案格式,每种应用程式都各有一种,而且到处都有.rc和foo.conf档案。另外想在emacs里更改设定还得学写lisp程式,而每个shell都要你学它独有的shell脚本方言才能更改设定,还有其他其他其他。

只认识一个世界的人是很讨人厌的。他们每次听到其他世界的复杂状况时,就会觉得自己的世界没那么复杂。不过事实上是一样的。只是你已经很精通,所以视而不见。这些世界实在太大太复杂无法相互比较。帕麦尔斯顿勋爵(Lord Palmerston)说过:「什列斯威-好斯敦问题(Schleswig-Holstein Question)问题实在是太复杂了,整个欧洲也只有三个人了解。第一位是已经逝世的Prince Albert。第二位是某个疯了的德国教授。第三位就是我,不过我已经完全忘掉了。」软体的世界也是如此巨大复杂而多面相,以致当我看到某些其方面很聪明的人在网志写些像「微软不懂作业系统」之类的[空话](http:// www.winterspeak.com/2002_10_01_archive.html#85572348)时,不禁要坦白的说他们看起来很蠢。Windows是由数百位程式师在十到廿年间所创造,具有数百个功能的几百万行程式。想像尝试要概述这种庞然大物,却连开始了解其中一大部份就没有。我并不是在为微软辩护,只是觉得这种源自极度无知的巨大模糊概括,是现在网路上最浪费时间的东西。

常来的读者应该已经注意到我在思考要如何发展跨Linux、Macintosh和Windows平台的应用程式,又不必为Linux和Macintosh版本投入不成比例的成本。这时候你需要某种跨平台程式库。

Java有这个野心,不过Sun并没有真的把GUI弄通,不能做出真正感觉自然的应用程式。这就像星舰迷航记里的太空异形透过望远镜观察地球一样,他们知道人类食物的 外观 ,却不了解它的_味道_ 。Java程式会在正确的地方画出功能表,可是键盘操作和Windows程式完全不一样,而且Java的分页对话盒看起来有点恐怖。另外不管怎么试都不能让功能表列和Excel的一模一样。为什么会这样呢?因为Java在抽象机制失败时,并没有提供很好的方法去将就使用平台原始的机制。当你用AWT写程式时并不能取得视窗的HWND,不能呼叫微软的API,当然也不能把WM_PAINT拦截起来自己画。而Sun已经表示得很明白了,如果你这样就就不够纯粹。你被污染了所以活该去死。

试图用Java建立GUI的努力经过多次众所周知的失败之后(比如Corel的Java Office suite和Netscape的Javagator),不少人学会要和这个世界保持距离。Eclipse运用平台原本的机制,从最底层开始建立了[他们自己的](http://www.eclipse.org/articles/Article- SWT-Design-1/SWT-Design-1.html)视窗程式库,这样才能写出使用观感符合原平台感觉的Java程式。

Mozilla的工程师决定用他们自己的发明XUL来处理跨平台问题。到目前为止令我印象深刻。Mozilla终于做到用起来感觉对劲的境界。连我最喜欢的怪用法「用Alt+Space N把视窗缩到最小」都可以在Mozilla里面使用;虽然花了很久不过他们还是做到了。

成立Lotus并创造123的Mitch Kapor决定下一个计划要做一个叫wxWindows和wxPython的产品,目标也是跨平台支援。

哪一个比较好呢?是XUL?是Eclipse的SWT?还是wxWindows呢?我不知道。这些都是很庞大的世界,大到我根本无法实际去评估并找出答案。光是读完教学并不够。你必须自己去辛苦用个一两年,才能真正知道它是的确够好,还是怎么试都无法让做出感觉对劲的使用介面。不幸的是,大多数专案都必须在写第一行程式之前决定要用哪个世界,而这正是资讯最少的时候。在前一个工作我们得面对某些很烂的架构,因为最早期的程式师利用该专案同时学写C++和Windows程式设计。有些最初期的程式码是完全不懂事件驱动程式设计下写出来的。核心的字串类别(我们当然有自己的字串类别)可以写进教科书,用以示范C++类别在设计上会犯的各种错误。最后终于把很多旧程式清理并重整干净,不过还是让我们头痛了好一阵子。

所以现在我会建议:至少要有一个对所用的语言、类别、API以及平台有数年以上经验的设计者,否则还是不要启动专案吧。如果你可以选择平台,就用你的团体最熟悉的吧,即使这个平台并不是最符合趋势或看起来最有生产力也没关系。另外在设计抽象机制或程式设计工具时,多做些努力让它不会漏吧。

这些网页的内容为表达个人意见。
All contents Copyright © 1999-2006 by Joel Spolsky. All Rights Reserved.