JoelOnSoftware

Joel on Software

Lord Palmerston on Programming

帕默斯顿勋爵谈编程

by Joel Spolsky Wednesday, December 11, 2002

There was a time when if you read one book by Peter Norton, you literally knew everything there was to know about programming the IBM-PC. Over the last 20 years, programmers around the world have been hard at work building abstraction upon abstraction on top of the IBM-PC to make it easier to program and more powerful.

曾经有一段时间如果你读过彼得诺顿写的那本书,那基本上你就了解了关于IBM-PC编程所需要的一切。在过去的20年里,世界各地的程序员努力的在IBM-PC上面构建一层又一层的抽象来让编程变得更加容易更加强大。

But the law of leaky abstractions means that even as they built the abstractions that are supposed to make programming easier, the sheer amount of stuff you have to know to be a great programmer is expanding all the time.

但是抽象失效定理告诉我们:随着他们围绕让编程变得更容易构建抽象,要成为一名伟大的程序员所要了解的绝对的知识量却一直在增长。

Becoming proficient, really proficient, in just one programming world takes years. Sure, lots of bright teenagers learn Delphi one week and Python the next week and Perl the next week and think they are proficient. Yet they don't have the foggiest clue how much they're missing.

要在一门仅仅一门编程语言上变得熟练,绝对熟练,就要花上若干年。当然有很多的聪明的少年一周学完了Delphi,一周就学完了Python,然后又一周学完了Perl并且觉得他们很熟练,然而他们根本不明白他们缺失了多少基础知识。

I've been working with ASP and VBScript since it first came out. VBScript is the dinkiest language on earth and ASP programming consists of learning about 5 classes, only two of which you use very often. And only now do I finally feel like I know the best way to architect an ASP/VBScript application. I finally think I know where the best place to put database access code is, the best way to use ADO to get recordsets, the best way to separate HTML and code, etc. And I finally use regexps instead of one-off string manipulation functions. Only last week, I learned how to get COM objects out of memory so you can recompile them (without restarting the whole web server).

自从ASP和VBScript诞生以来我就一直在使用它们。VBScript是世界上最小的编程语言。 而ASP编程则包含了学习大约五个类,其中只有两个你会经常用到。然而直到现在我才感觉到:我了解了ASP/VBScript应用程序的最佳方式。我终于觉得我知道哪儿放数据库访问方法最合适。哪儿最好使用DAO来获得数据结果集。分离HTML和代码的最佳方式是什么?我最终学会了使用正则表达式而不是一次又一次的去编写字符处理函数。就上周我学会了如何把COM对象从内存里拿出来重新编译。(而不需要重新启动整个Web服务器)。

Fog Creek is too small to have specialists, so when I needed to write a really good installer for FogBUGZ, our ASP/VBScript based product, I drew on several years of C++/MFC experience, and years of experience with Windows APIs, and good Corel PhotoPaint skills to create a neat picture in the corner of the wizard. Then to get FogBUGZ to work perfectly with Unicode, I had to write a little ActiveX control using C++ and ATL, which drew upon years of C++ and COM experience and a week or so learning about character encodings when I implemented that code in CityDesk.

Fog Creek太小了没有什么专家,所以当我要给FogBUGZ写一个很好的安装器的时候。(FogBUGZ是我们的一款基于ASP/VBScipt的产品)依赖于若干年来我在C++/mfc领域编程经验,以及我在WindowsAPI编程若干年的经验,还有我的优秀的CorelPhotoPaint技术。我才能在安装向导的拐角处画上了漂亮的图案。然后为了让FogBUGZ能够很好的支持Unicode,我又只好用C++和ATL写了一个小小的ActiveX插件,而这也要依赖于我数年来在C++和COM组建上经验加上我在实现CityDesk时花一个星期左右时间学到的关于字符串编码的知识。

So when we had a weird NT 4.0-only bug, it took me 3 minutes to debug, because I knew how to use VMWare, and I had a clean NT 4.0 machine set up in VMWare, and I knew how to do remote debugging with Visual C++, and I knew to look in the EAX register to get the return value from a function. Someone who was new to this all might have taken an hour or more to debug the same problem, but I already knew a tremendous amount of "stuff" that I've been learning, basically, since 1982 when I got my first IBM-PC and that Norton book.

所以当我们遇到一个奇怪的只会在NT4.0上才会出现的错误的时候,我只花了三分钟时间调试,因为我知道如何使用VMWARE,然后我在Vmware上安装了一个NT4.0干净版本,然后我还知道如何使用VisualC++进行远程调试,我还知道,要到EAX寄存器里面去获得函数的返回值。而刚到这个领域的新人可能要花一个小时甚至更多在这个问题上。而我因为已经了解了这些我一直在学习的大量的“知识”。基本上自从1982年我拿到我的第一个IBM-PC,以及那本诺顿书的时候我就一直在学习这些东西。

Leaky abstractions mean that we live with a hockey stick learning curve: you can learn 90% of what you use day by day with a week of learning. But the other 10% might take you a couple of years catching up. That's where the really experienced programmers will shine over the people who say "whatever you want me to do, I can just pick up the book and learn how to do it." If you're building a team, it's OK to have a lot of less experienced programmers cranking out big blocks of code using the abstract tools, but the team is not going to work if you don't have some really experienced members to do the really hard stuff.

抽象失效意味着我们得习惯像曲棍球一样陡峭的学习曲线。你可以通过一个礼拜就学到你平常工作中要用到的东西的90%,但是剩余的10%你可能要花上几年才能够补齐,这就是那些非常有经验的程序员和其他程序的区别。他们只会说:不管你要做什么,我都能够拿起书学会如何去做。但是如果你在组建一个团队,你当然可以有许多这样没有太多经验的程序员,靠他们使用各种抽象工具来编出大堆大堆的代码。但是如果你没有一些很有经验的程序员来处理那些非常非常困难的事情的时候,这个团队没办法工作。

There are a lot of programming worlds, each of which requires a tremendous amount of knowledge for real proficiency. Here are the three I personally know best:

有很多的编程领域,每个领域都需要大量的经验才能够变得真正的熟练。下面是我个人最了解的三个。

  • MFC/C++/Windows

  • VBScript/ASP

  • Visual Basic

All, basically, what you would call Windows programming. Yes, I've written Unix code and Java code, but not very much. My proficiency in Windows programming comes from knowing not just the basic technologies but also the whole supporting infrastructure. So, I claim, I'm really good at Windows programming because I also know COM, ATL, C++, 80x86 Assembler, Windows APIs, IDispatch (OLE Automation), HTML, the DOM, the Internet Explorer object model, Windows NT and Windows 95 internals, LAN Manager and NT networking, including security (ACEs, ACLs, and all that stuff), SQL and SQL Server, Jet and Access, JavaScript, XML, and a few othercheerful facts about the square of the hypotenuse. When I can't get the StrConv function in VB to do what I want, I bang out an COM control so I can drop into C++ with ATL and call the MLang functions without dropping a beat. It took me years to get to this point.

所有的这些,基本上你都可以叫Windows编程,当然,我也写过一些Unix代码和Java代码但是没那么多。我在windows编程领域的驾轻就熟,不仅仅来自于我知道的一些基本技术。更因为我理解整个支撑架构。所以我敢说:我精通Windows编程。因为我同样知道COM,C++,汇编器,WindowsAPI,Idispatch(OLE自动化),HTML,文档对象模型,IE对象模型,局域网管理器,NT网络,同样还有安全(ACE,ACL之类的东西), SQL,SQLSERVER, JET,Acces,还有一些其他的例如关于平方斜边的精彩知识。当我不能够StrConv达成我的目的的时候,我就会拿出一个COM组件这样我就能够进入C++使用ATL,然后调用Mlang函数来完成我想要的功能并且完全不会打乱工作节拍。我花了很多很多年才达到今天这一步。

There are lots of other programming worlds. There's the world of people developing for BEA Weblogic who know J2EE, Oracle, and all kinds of Java things that I don't even know enough about to enumerate. There are hard core Macintosh developers who know CodeWarrior, MPW, Toolbox programming in System 6 through X, Cocoa, Carbon, and even nice obsolete things like OpenDoc that don't help any more.

还有很多其他的编程领域。还有一个领域有很多人在BEA WEBLOGIC上面进行开发。他们懂很多J2EE ORACLE 还有许多java方面的概念(我在这方面不是很在行,没有办法一一列举)。 还有很多铁杆的Mac开发人员知道在System6上面用X,Cocoa,Carbon进行CodeWarrior,MPW,Toolbox编程, 哪怕那些已经被舍弃的好东西例如OpenDoc实际上已经起不了什么作用了。

Very few people, though, know more than one or two worlds, because there's just so much to learn that unless you have to work in one of these worlds for more than a couple of years, you don't really grok it all.

只有很少的人知道一两个或更多的领域。因为要学的东西实在太多了,除非你在这些领域中待上个几年。否则你真的很难得到要领。

But learn you must.

但是只学你必须知道的。

People get kind of miffed when they go on job interviews and get rejected because, for example, they don't have Win32 (or J2EE, or Mac programming, or whatever) experience. Or they get annoyed because idiot recruiters, who would not know an MSMQ if it bit them in the tailbone, call them up and ask if they "have 5 years MSMQ."

人们有时候会因为参加面试的时候被拒了很恼火,原因就是例如他们没有win32(或者J2EE,Mac编程或者其他的经验)经验。又或许他们被激怒只是因为:面试官太愚蠢了。如果不是要用的话谁会知道什么MSMQ,还打电话问他们是否有五年的MSMQ经验。

Until you've done Windows programming for a while, you may think that Win32 is just a library, like any other library, you'll read the book and learn it and call it when you need to. You might think that basic programming, say, your expert C++ skills, are the 90% and all the APIs are the 10% fluff you can catch up on in a few weeks. To these people I humbly suggest: times have changed. The ratio has reversed.

直到你从事过一段时间win32编程之前,你可能都会觉得Win32只是一个库,就像其他的库一样,你只要在你需要的时候去买本书,学习他,然后弄清楚如何调用。你可能觉得对于基本的编程而言例如:你的专家级c++技术,是90%重要的,然后其他所有的都是10%的东西,你能够在一周时间内补上来。对这些人,我虚心地建议:“时代已经变了,这个比例已经反过来了”。

Very few people get to work on low level C algorithms that just move bytes around any more. Most of us spend all our time these days calling APIs, not moving bytes. Someone who is a fantastic C++ coder with no API experience only knows about 10% of what you use every day writing code that runs on an API. When the economy is doing well, this doesn't matter. You still get jobs, and employers pay the cost of your getting up to speed on the platform. But when the economy is a mess and 600 people apply for every job opening, employers have the luxury of choosing programmers who are already experts at the platform in question. Like programmers who can name four ways to FTP a file from Visual Basic code and the pros and cons of each.

只有很少的人需要在底层的c里面工作去把字节移来移去。我们中的大多数会把大部分的时间花在调用api上,而不是把字节搬来搬去。所以某个出色的c++程序员,但是完全没有api编程方面的经验 对于如何调用API编写出这个平台上工作的程序只有10%的知识。当经济景气的时候,这可能没有关系。还是会有雇主会花钱让你去弥补缺失的平台知识。但是当经济糟糕的时候。比如有六百个人应聘同一个职位,雇主就能够奢侈地挑选那些在这个平台上已经是专家的那些程序员。比如那些能够举出四种方法通过VBScript使用FTP传递一个文件。并且列出这些方式的优点和缺点。

The huge surface area of all these worlds of programming leads to pointless flame wars over whose world is better. Here's a smug comment somebody anonymously made on my discussion board:

所有这些编程领域的大部分表层方面都导致了许多没有意义的关于哪个领域更好的口水战,比如下面这个某人匿名发表在我的讨论版上面的调皮评论:

"Just one more reason why I'm glad to be living in the 'free world.' Free as in speech (almost) and freedom from pandering to things like setup programs and the registry - just to name a few."

“再说一个理由为什么我很高兴我生活在自由的开源编程领域。举几个例子:‘言论自由(几乎),免于给程序设置注册表项目的自由’”。

I think this person was trying to say that in the Linux world they don't write setup programs. Well, I hate to disappoint you, but you have something just as complicated: imake, make, config files, and all that stuff, and when you're done, you still distribute applications with a 20KB INSTALL file full of witty instructions like "You're going to need zlib" (what's that?) or "This may take a while. Go get some runts." (Runts are a kind of candy, I think.) And the registry -- instead of one big organized hive of name/value pairs, you have a thousand different file formats, one per application, with .whateverrc and foo.conf files living all over the place. And emacs wants you to learn how to program lisp if you're going to change settings, and each shell wants you to learn its personal dialect of shell script programming if you want to change settings, and on and on.

我觉得这个人其实是想说在那个领域里面,他们不用编写安装程序。很抱歉让你失望。但是你们不还是有一些同样复杂的概念么,imake,configure 之类的配置文件.当你写完程序的时候,你不还是得使用20kb左右的安装文件,搞一个写满了了杂乱的安装指令的文件。比如:“你需要一个zlib(这啥玩意儿)”又或是“这可能要花上一段时间,去打个盹儿吧(我觉得打盹儿到时不错的)”。 然后来谈注册表,相比一个巨大的组织好的名值对数据库,你们有一千种不同的文件格式,每个程序几乎都有一个。例如:到处都充斥着.XXRC,foo.config这样的文件。而且如果你想要修改配置的话emacs会让你学lisp语言编程。更甚,如果你想改变shell配置的话,每个shell都会你学他们自己的脚本语言方言。等等等等。

People who only know one world get really smarmy, and every time they hear about the complications in the other world, it makes them think that their world doesn't have complications. But they do. You've just moved beyond them because you are proficient in them. These worlds are just too big and complicated to compare any more. Lord Palmerston: "The Schleswig-Holstein question is so complicated, only three men in Europe have ever understood it. One was Prince Albert, who is dead. The second was a German professor who became mad. I am the third and I have forgotten all about it." The software worlds are so huge and complicated and multifaceted that when I see otherwise intelligent people writing blog entries saying something vacuous like "Microsoft is bad at operating systems," frankly, they just look dumb. Imagine trying to summarize millions of lines of code with hundreds of major feature areas created by thousands of programmers over a decade or two, where no one person can begin to understand even a large portion of it. I'm not even defending Microsoft, I'm just saying that big handwavy generalizations made from a position of deep ignorance is one of the biggest wastes of time on the net today.

那些只懂一个领域的人会变得很虚伪。每当他们听到其他领域的复杂之处的时候。就会让他们觉得他们的领域没有那种复杂之处,但其实还是有。你已经超过了他们的那个程度,因为你比他们更熟练。对于公司来说这些领域已经没有那么庞大那么复杂了。帕默斯顿勋爵曾经说:“石勒苏益格-荷尔斯泰因问题实在是太复杂了,整个欧洲只有三个人曾经搞懂过。一个是二伯特王子,他已经死了;第二个是一个德国教授,已经疯了;我是第三个但是我已经了。软件领域是如此的巨大和复杂并且呈现出多面性。因此,会看见那些其实很聪明的人写博客宣称一些没有意义的事情。例如,微软不会做操作系统啦!老实说他们看起来很傻。想象一下把成千上万的程序员在十年二十年间写出的上百万行代码,按照主要的功能领域进行摘要。我觉得即便这样,几乎也没有人能够理解其中的大部分。我都没有为微软辩护,我只说这种从很深层次的无知出发然后一杆子打翻一船人的做法是如今互联网上最严重的时间浪费行为。

Fre quent readers, by now, have noticed that I've been thinking of the problem of how one might deliver an application on Linux, Macintosh, and Windows without paying disproportionately for the Linux and Macintosh versions. For this you need some kind of cross-platform library.

经常到这个时候就会有读者注意到。我一直在思考如何能够实现在Linux,mac和windows上面发布一个程序而不需要花费过多时间来处理Linux和Mac领域的复杂性?答案就是你需要一些跨平台库。

Java attempted this but Sun didn't grok GUIs well enough to deliver really slick native-feeling applications. Like the space alien in Star Trek watching Earth through a telescope, they knew exactly what human food was supposed to look like but they didn't realize it was supposed to taste like something. Java apps have menus in the right places but there are all these keyboard things that don't work the same way as every other Windows app and their tabbed dialogs look a little scary. And there is no way, no matter how hard you try, to make their menubars look exactly like Excel's menubars. Why? Because Java doesn't give you a very good way to drop down to the native facilities whenever the abstraction fails. When you're programming in AWT, you can't figure out the HWND of a window, you can't call the Microsoft APIs, and you certainly can't intercept WM_PAINT and do it differently. And Sun made it plenty clear that if you tried to do that, you weren't Pure. You were Polluted, and to hell with you.

Java对此进行了一次尝试。但是SUN没有能够把握住用户界面的精髓。并发布那种华丽的具有本地应用外观的应用程序。就像在《星战》里面用望远镜看着地球的那些宇宙外星人一样,他们完全知道人类的食物看上去应该什么样子,但是却不知道这些食物尝起来应该是什么样子。java应用程序的菜单放在正确的位置,但是它的键盘热键却跟其他的应用程序不怎么一致,他们的那种分页对话框看起来实在有点吓人。而且没有方法,不管你多努力地去尝试,能够让他们的菜单栏看起来跟excel的菜单栏一样,为什么?Java没有给出很好的方式在抽象失效的时候去求助于一些本地措施。当你用SWT编程的时候,你没办法获得一个窗口的句柄,你也没有办法调用Windows API,你当然更不能截获WM_PAINT事件然后用不同的方式来绘制。而且SUN清楚地声明你不能这样做,如果你硬要这么做那么你就不纯洁了,你就被污染了。你就等着下地狱吧!

After a number of highly publicized failures to build GUIs with Java (e.g. Corel's Java Office suite and Netscape's Javagator), enough people know to stay away from this world. Eclipse built their own windowing library from the ground up using native widgets just so they could write Java code that had a reasonably native look and feel.

经历过几次公开的著名的公司使用java来构建用户界面事件之后。(例如Corel的JavaOffice系列,网景的java浏览器系列)。已经又足够多的人,知道要远离这个世界。Eclipse为了让他们写出来的Java界面空间看起来具有本地外观的美感。用java原生的那些控件从头开始重写了他们自己的窗口库程序。

The Mozilla engineers decided to address the cross platform problem with their own invention called XUL. So far, I'm impressed. Mozilla finally got to the point where it tastes like real food. Even my favorite bugaboo, Alt+Space N to minimize a window, works in Mozilla; it took them long enough but they did it.

Mozilla的工程师想通过他们自己的发明XUL来解决这个跨平台问题应用程序问题,到目前为止我还是很惊讶他们的表现的。他们最终还是走到了让食物尝起来真的有它原来的味道那一步,哪怕是我自己最吓人的组合,用Alt-Space-N来最小化一个窗口在Mozilla XUL下面也是可以工作的。虽然花了很长时间,但是他们还是做成了。

Mitch Kapor, who founded Lotus and created 123, decided for his next application to go with something called wxWindows and wxPython for cross platform support.

米奇 *卡普尔也就是那个发明了lotus,123的人。决定使用某个叫做wxWindows和wxPython跨平台支持库来创建它的下一代应用程序。

Which is better, XUL, Eclipse's SWT, or wxWindows? I don't know. They are all such huge worlds that I couldn't really evaluate them and tell. It's not enough to read the tutorials. You have to sweat and bleed with the thing for a year or two before you really know it's good enough or realize that no matter how hard you try you can't make your UI taste like real food. Unfortunately, for most projects, you have to decide on which world to use before you can write the first line of code, which is precisely the moment when you have the least information. At a previous job we had to live with some pretty bad architecture because the first programmers used the project to teach themselves C++ and Windows programming at the same time. Some of the oldest code was written without any comprehension of event-driven programming. The core string class (of course, we had our own string class) was a textbook example of all the mistakes you could make in designing a C++ class. Eventually we cleaned up and refactored a lot of that old code but it haunted us for a while.

哪一个更好?XUL,Eclipse SWT还是wxWindows,我不知道!这些都是如此巨大复杂的领域我没办法真正评价,分辨。光读教程是没有用的,你必须通过一年,两年时间来在里面出汗在里面流血,你才能真正搞清楚他是不是真的足够好还是说你最终会意识到不管你多努力地尝试你始终不可能做出尝起来像食物那样的界面。对大多数项目来说,在写第一行代码之前你就必须决定你要使用的那一个领域。恰恰就像这个时候没有什么信息的时候。在前份工作的时候,我们必须得容忍一些非常糟糕的架构。因为写这个项目的第一个程序员尝试使用这个项目来教他们自己c++和windows编程,同时这个程序还是在没有对事件驱动编程的理解的基础上写出来的,其中最核心的字符串类(当然我们有我们自己的字符串类)简直就是一个你能够在设计一个c++类时候能犯的所有错误的教科书案例。但是我还是把这些清理干净了,我重构了旧代码里面的大部分。但是这些工作让我们停顿了好长一段时间。

So for now, my advice is this: don't start a new project without at least one architect with several years of solid experience in the language, classes, APIs, and platforms you're building on. If you have a choice of platforms, use the one your team has the most skills with, even if it's not the trendiest or nominally the most productive. And when you're designing abstractions or programming tools, go the extra mile to make them leak proof.

所以现在我的建议就是:如果团队里面没有一个对你们要构建的平台有着若干年扎实的语言,类,API设计经验的架构师的话,不要开始这种新的项目。如果你可以选择平台的话,选择那些你的团队最熟悉的那个平台。哪怕它不符合当下的流行趋势,也就是说不是最有效率的。然后当你的设计抽象,或者编程工具的时候,多花点时间,让他们不要失效。