将程序装在脑中

Paul Graham 2007-08-01

将程序装在脑中

2007年8月

一个优秀的程序员密集地工作在他自己的代码上时,可以像数学家把持一个他在解决的问题那样把持它。数学家不像学校教的那样在纸上工作来回答问题。他们在脑子里做得更多:他们试图充分理解问题空间,能够像漫步在你成长房屋的记忆中那样漫步其中。在最佳状态下,编程也是如此。你把整个程序装在脑中,你可以随意操纵它。

这在项目开始时特别有价值,因为最初最重要的是能够改变你正在做的事情。不仅仅是以不同的方式解决问题,而是改变你正在解决的问题。

你的代码是你对你正在探索的问题的理解。所以只有当你把代码装在脑中时,你才真正理解这个问题。

把程序装进脑中并不容易。如果你离开一个项目几个月,当你回到它时,可能需要几天才能真正再次理解它。即使你在积极地处理一个程序,每天开始工作时也需要半小时才能把它装进脑中。这是最好的情况。在典型办公条件下工作的普通程序员永远不会进入这种模式。或者更戏剧性地说,在典型办公条件下工作的普通程序员永远不会真正理解他们正在解决的问题。

即使是最优秀的程序员并不总是把他们正在处理的整个程序都装在脑中。但你可以做一些事情来帮助:

避免干扰。

干扰对许多类型的工作都是有害的,但对编程尤其有害,因为程序员倾向于在他们能处理的细节极限上运作。

干扰的危险不在于它持续多久,而在于它使你的大脑混乱的程度。程序员可以离开办公室去吃个三明治而不会失去脑中的代码。但错误的干扰可以在30秒内抹去你的大脑。

奇怪的是,有计划的干扰可能比没有计划的干扰更糟。如果你知道一小时后有个会议,你甚至不会开始处理困难的事情。

长时间工作。

因为每次开始处理一个程序都有固定成本,所以在几个长时段中工作比在许多短时段中工作更有效率。当然,总会有一个点,因为你累了而变得愚蠢。这因人而异。我听说过人们连续36小时编程,但我能管理的最多只有18小时左右,而且我在不超过12小时的块中工作效果最好。

最佳状态不是你身体能忍受的极限。分解项目既有优势也有成本。有时当你在休息后回到问题时,你会发现你的潜意识留下了答案等着你。

使用简洁的语言。

更强大的编程语言使程序更短。程序员似乎至少部分地用他们用来编写程序的语言来思考程序。语言越简洁,程序越短,就越容易装进脑中并保持在那里。

你可以通过使用一种称为自底向上编程的风格来增强强大语言的效果,在这种风格中,你编写多层程序,较低的层作为其上层的编程语言。如果你正确地这样做,你只需要把最顶层装在脑中。

不断重写你的程序。

重写程序通常会得到更清晰的设计。但即使不会,它也有优势:你必须完全理解一个程序才能重写它,所以没有更好的方法把它装进脑中。

写可重读的代码。

所有程序员都知道写可读代码是好的。但你自己是最重要的读者。特别是在开始时;原型是与自己的对话。当为自己写作时,你有不同的优先事项。如果为别人写作,你可能不想让代码太密集。程序的某些部分可能最容易读,如果你把东西摊开,像一本入门教科书。而如果你写代码是为了让它容易重新装进脑中,最好追求简洁。

小组工作。

当你在脑中操纵一个程序时,你的视野倾向于停在你拥有的代码边缘。其他部分你理解得不够好,更重要的是,不能随意处理。所以程序员数量越少,项目就能越完全地变异。如果只有一个程序员,通常开始时是这样,你可以做全面重新设计。

不要让多个人编辑同一段代码。

你永远不会像理解自己的代码那样理解别人的代码。无论你多么彻底地读过它,你只是读了它,而不是写了它。所以如果一段代码由多个作者编写,他们中没有人像单个作者那样理解它。

当然你不能安全地重新设计别人正在处理的东西。不仅仅是你必须请求许可。你甚至不让自己考虑这样的事情。重新设计有几个作者的代码就像改变法律;重新设计你独自控制的代码就像看到模糊图像的另一种解释。

如果你想让几个人在一个项目上工作,把它分成组件,每个给一个人。

从小开始。

随着你对程序越来越熟悉,它变得更容易装在脑中。一旦你确信你已经完全探索了某些部分,你就可以开始把它们当作黑盒处理。但当你开始处理一个项目时,你被迫看到一切。如果你开始的问题太大,你可能永远无法完全把握它。所以如果你需要写一个大的、复杂的程序,开始的最佳方式可能不是为它写规范,而是写一个解决子集问题的原型。无论计划有什么优势,它们往往被能够把程序装在脑中的优势所抵消。

程序员们经常偶然做到这八点,这很引人注目。有人有了一个新项目的想法,但因为不是正式批准的,他必须在下班时间做——结果证明更有生产力,因为没有干扰。受到他对新项目的热情驱使,他连续工作许多小时。因为它最初只是一个实验,他使用的是”脚本”语言而不是”生产”语言——实际上它强大得多。他完全重写程序几次;这对正式项目是不合理的,但这是爱的劳动,他想要它完美。而且因为除了他没有人会看到它,他省略了除笔记类型外的任何注释。他被迫在小团队中工作,因为他要么还没有告诉任何人这个想法,要么它看起来如此无望以至于不允许其他人在其上工作。即使有一个团队,他们也不能让多个人编辑同一段代码,因为它变化太快,那是不可能的。项目从小开始是因为想法一开始很小;他只是有一些很酷的黑客技巧想试试。

更引人注目的是有多少正式批准的项目设法把这八件事都做错了。事实上,如果你看看大多数组织中软件编写的方式,几乎就像他们在故意做错事情。在某种意义上,他们确实如此。自从有组织以来,其定义性品质之一就是把个人当作可互换的部件。这对更可并行化的任务很有效,比如打仗。在历史上大部分时间里,一支训练有素的专业士兵军队可以指望打败一群个人战士,无论多么勇敢。但拥有想法不是很可并行化的。而程序就是:想法。

组织不喜欢依赖个人天才的想法不仅仅是真的,它是同义反复。不这样做是组织定义的一部分。至少是我们当前组织概念的一部分。

也许我们可以定义一种新型的组织,结合个人的努力而不要求他们可互换。可以说市场就是这种形式的组织,尽管把市场描述为退化情况可能更准确——当组织不可能时默认得到的情况。

可能我们能做到的最好的是某种hack,比如让一个组织的编程部分以不同于其他部分的方式工作。也许最佳解决方案是大公司甚至不尝试内部开发想法,而只是购买它们。但无论解决方案是什么,第一步是意识到存在问题。“软件公司”这个短语本身就有矛盾。这两个词在相反的方向上拉扯。任何大型组织中的优秀程序员都会与之冲突,因为组织的设计是为了防止程序员追求的目标。

优秀的程序员无论如何都能完成很多事情。但这往往需要对雇佣他们的组织进行实际上反抗的行为。如果更多的人理解程序员的行为方式是由他们工作的需求驱动的,这可能会有所帮助。他们长时间工作,期间推掉所有其他义务,直接投入编程而不是先写规范,重写已经工作的代码,这不是因为他们不负责任。他们更喜欢独自工作,或者对探头说你好的人咆哮,这不是因为他们不友好。这个表面上随机的令人讨厌习惯集合有一个单一的解释:将程序装在脑中的力量。

无论理解这一点是否能帮助大型组织,它肯定能帮助他们的竞争对手。大公司的最弱点是他们不让个别程序员做出伟大的工作。所以如果你是一个小创业公司,这是攻击他们的地方。接手那些必须在一个大脑中解决的问题。

感谢Sam Altman、David Greenspan、Aaron Iba、Jessica Livingston、Robert Morris、Peter Norvig、Lisa Randall、Emmett Shear、Sergei Tsarev和Stephen Wolfram阅读本文的草稿。

Holding a Program in One’s Head

August 2007

A good programmer working intensively on his own code can hold it in his mind the way a mathematician holds a problem he’s working on. Mathematicians don’t answer questions by working them out on paper the way schoolchildren are taught to. They do more in their heads: they try to understand a problem space well enough that they can walk around it the way you can walk around the memory of the house you grew up in. At its best programming is the same. You hold the whole program in your head, and you can manipulate it at will.

That’s particularly valuable at the start of a project, because initially the most important thing is to be able to change what you’re doing. Not just to solve the problem in a different way, but to change the problem you’re solving.

Your code is your understanding of the problem you’re exploring. So it’s only when you have your code in your head that you really understand the problem.

It’s not easy to get a program into your head. If you leave a project for a few months, it can take days to really understand it again when you return to it. Even when you’re actively working on a program it can take half an hour to load into your head when you start work each day. And that’s in the best case. Ordinary programmers working in typical office conditions never enter this mode. Or to put it more dramatically, ordinary programmers working in typical office conditions never really understand the problems they’re solving.

Even the best programmers don’t always have the whole program they’re working on loaded into their heads. But there are things you can do to help:

Avoid distractions.

Distractions are bad for many types of work, but especially bad for programming, because programmers tend to operate at the limit of the detail they can handle.

The danger of a distraction depends not on how long it is, but on how much it scrambles your brain. A programmer can leave the office and go and get a sandwich without losing the code in his head. But the wrong kind of interruption can wipe your brain in 30 seconds.

Oddly enough, scheduled distractions may be worse than unscheduled ones. If you know you have a meeting in an hour, you don’t even start working on something hard.

Work in long stretches.

Since there’s a fixed cost each time you start working on a program, it’s more efficient to work in a few long sessions than many short ones. There will of course come a point where you get stupid because you’re tired. This varies from person to person. I’ve heard of people hacking for 36 hours straight, but the most I’ve ever been able to manage is about 18, and I work best in chunks of no more than 12.

The optimum is not the limit you can physically endure. There’s an advantage as well as a cost of breaking up a project. Sometimes when you return to a problem after a rest, you find your unconscious mind has left an answer waiting for you.

Use succinct languages.

More powerful programming languages make programs shorter. And programmers seem to think of programs at least partially in the language they’re using to write them. The more succinct the language, the shorter the program, and the easier it is to load and keep in your head.

You can magnify the effect of a powerful language by using a style called bottom-up programming, where you write programs in multiple layers, the lower ones acting as programming languages for those above. If you do this right, you only have to keep the topmost layer in your head.

Keep rewriting your program.

Rewriting a program often yields a cleaner design. But it would have advantages even if it didn’t: you have to understand a program completely to rewrite it, so there is no better way to get one loaded into your head.

Write rereadable code.

All programmers know it’s good to write readable code. But you yourself are the most important reader. Especially in the beginning; a prototype is a conversation with yourself. And when writing for yourself you have different priorities. If you’re writing for other people, you may not want to make code too dense. Some parts of a program may be easiest to read if you spread things out, like an introductory textbook. Whereas if you’re writing code to make it easy to reload into your head, it may be best to go for brevity.

Work in small groups.

When you manipulate a program in your head, your vision tends to stop at the edge of the code you own. Other parts you don’t understand as well, and more importantly, can’t take liberties with. So the smaller the number of programmers, the more completely a project can mutate. If there’s just one programmer, as there often is at first, you can do all-encompassing redesigns.

Don’t have multiple people editing the same piece of code.

You never understand other people’s code as well as your own. No matter how thoroughly you’ve read it, you’ve only read it, not written it. So if a piece of code is written by multiple authors, none of them understand it as well as a single author would.

And of course you can’t safely redesign something other people are working on. It’s not just that you’d have to ask permission. You don’t even let yourself think of such things. Redesigning code with several authors is like changing laws; redesigning code you alone control is like seeing the other interpretation of an ambiguous image.

If you want to put several people to work on a project, divide it into components and give each to one person.

Start small.

A program gets easier to hold in your head as you become familiar with it. You can start to treat parts as black boxes once you feel confident you’ve fully explored them. But when you first start working on a project, you’re forced to see everything. If you start with too big a problem, you may never quite be able to encompass it. So if you need to write a big, complex program, the best way to begin may not be to write a spec for it, but to write a prototype that solves a subset of the problem. Whatever the advantages of planning, they’re often outweighed by the advantages of being able to keep a program in your head.

It’s striking how often programmers manage to hit all eight points by accident. Someone has an idea for a new project, but because it’s not officially sanctioned, he has to do it in off hours—which turn out to be more productive because there are no distractions. Driven by his enthusiasm for the new project he works on it for many hours at a stretch. Because it’s initially just an experiment, instead of a “production” language he uses a mere “scripting” language—which is in fact far more powerful. He completely rewrites the program several times; that wouldn’t be justifiable for an official project, but this is a labor of love and he wants it to be perfect. And since no one is going to see it except him, he omits any comments except the note-to-self variety. He works in a small group perforce, because he either hasn’t told anyone else about the idea yet, or it seems so unpromising that no one else is allowed to work on it. Even if there is a group, they couldn’t have multiple people editing the same code, because it changes too fast for that to be possible. And the project starts small because the idea is small at first; he just has some cool hack he wants to try out.

Even more striking are the number of officially sanctioned projects that manage to do all eight things wrong. In fact, if you look at the way software gets written in most organizations, it’s almost as if they were deliberately trying to do things wrong. In a sense, they are. One of the defining qualities of organizations since there have been such a thing is to treat individuals as interchangeable parts. This works well for more parallelizable tasks, like fighting wars. For most of history a well-drilled army of professional soldiers could be counted on to beat an army of individual warriors, no matter how valorous. But having ideas is not very parallelizable. And that’s what programs are: ideas.

It’s not merely true that organizations dislike the idea of depending on individual genius, it’s a tautology. It’s part of the definition of an organization not to. Of our current concept of an organization, at least.

Maybe we could define a new kind of organization that combined the efforts of individuals without requiring them to be interchangeable. Arguably a market is such a form of organization, though it may be more accurate to describe a market as a degenerate case—as what you get by default when organization isn’t possible.

Probably the best we’ll do is some kind of hack, like making the programming parts of an organization work differently from the rest. Perhaps the optimal solution is for big companies not even to try to develop ideas in house, but simply to buy them. But regardless of what the solution turns out to be, the first step is to realize there’s a problem. There is a contradiction in the very phrase “software company.” The two words are pulling in opposite directions. Any good programmer in a large organization is going to be at odds with it, because organizations are designed to prevent what programmers strive for.

Good programmers manage to get a lot done anyway. But often it requires practically an act of rebellion against the organizations that employ them. Perhaps it will help if more people understand that the way programmers behave is driven by the demands of the work they do. It’s not because they’re irresponsible that they work in long binges during which they blow off all other obligations, plunge straight into programming instead of writing specs first, and rewrite code that already works. It’s not because they’re unfriendly that they prefer to work alone, or growl at people who pop their head in the door to say hello. This apparently random collection of annoying habits has a single explanation: the power of holding a program in one’s head.

Whether or not understanding this can help large organizations, it can certainly help their competitors. The weakest point in big companies is that they don’t let individual programmers do great work. So if you’re a little startup, this is the place to attack them. Take on the kind of problems that have to be solved in one big brain.

Thanks to Sam Altman, David Greenspan, Aaron Iba, Jessica Livingston, Robert Morris, Peter Norvig, Lisa Randall, Emmett Shear, Sergei Tsarev, and Stephen Wolfram for reading drafts of this.