It's a long-standing principle of programming style that the functional elements of a program should not be too large. If some component of a program grows beyond the stage where it's readily comprehensible, it becomes a mass of complexity which conceals errors as easily as a big city conceals fugitives. Such software will be hard to read, hard to test, and hard to debug.
编程风格中有一条长期存在的原则:程序的功能性元素不应过大。如果程序的某个组件大到难以轻易理解,它就会变成一团复杂性,其隐藏错误的轻松程度,就像大城市隐藏逃犯一样。这样的软件会难以阅读、难以测试,也难以调试。
In accordance with this principle, a large program must be divided into pieces, and the larger the program, the more it must be divided. How do you divide a program? The traditional approach is called top-down design: you say "the purpose of the program is to do these seven things, so I divide it into seven major subroutines. The first subroutine has to do these four things, so it in turn will have four of its own subroutines," and so on. This process continues until the whole program has the right level of granularity-- each part large enough to do something substantial, but small enough to be understood as a single unit.
按照这一原则,大程序必须拆分成若干部分,而且程序越大,就越需要拆分。怎样拆分一个程序?传统的方法称为自顶向下设计:你会说“程序的目的就是做这七件事,所以我把它分成七个主要子程序。第一个子程序要做这四件事,因此它又会有自己四个子程序”,诸如此类。这个过程会一直继续,直到整个程序具有合适的粒度——每一部分都大到足以完成实质性的工作,但又小到可以作为一个独立单元来理解。
Experienced Lisp programmers divide up their programs differently. As well as top-down design, they follow a principle which could be called bottom-up design-- changing the language to suit the problem. In Lisp, you don't just write your program down toward the language, you also build the language up toward your program. As you're writing a program you may think "I wish Lisp had such-and-such an operator." So you go and write it. Afterward you realize that using the new operator would simplify the design of another part of the program, and so on. Language and program evolve together. Like the border between two warring states, the boundary between language and program is drawn and redrawn, until eventually it comes to rest along the mountains and rivers, the natural frontiers of your problem. In the end your program will look as if the language had been designed for it. And when language and program fit one another well, you end up with code which is clear, small, and efficient.