If men could learn from history, what lessons it might teach us! But
passion and party blind our eyes, and the light which experience
gives is a lantern on the stem, which shines only on the waves
behind us!
Samuel Taylor Coleridge, Recollections
The world of computing changes all the time, and the pace seems to accelerate.
Programmers must cope with new languages, new tools, new systems, and of course
incompatible changes to old ones. Programs are bigger, interfaces are more compli-
cated, deadlines are shorter.
But there are some constants, some points of stability, where lessons and insight
from the past can help with the future. The underlying themes in this book are based
on these lasting concepts.
Simplicity and clarity are first and most important, since almost everything else
follows from them. Do the simplest thing that works. Choose the simplest algorithm
that is likely to be fast enough, and the simplest data structure that will do the job;
combine them with clean, clear code. Don't complicate them unless performance
measurements show that more engineering is necessary. Interfaces should be lean and
spare, at least until there is compelling evidence that the benefits outweigh the added
complexity.
Generality often goes hand in hand with simplicity, for it may make possible solv-
ing a problem once and for all rather than over and over again for individual cases. It
is often the right approach to portability as well: find the single general solution that
works on each system instead of magnifying the differences between systems.
Evolution comes next. It is not possible to create a perfect program the first time.
The insight necessary to find the right solution comes only with a combination of
thought and experience; pure introspection will not produce a good system, nor will
pure hacking. Reactions from users count heavily here; a cycle of prototyping, exper-
iment. user feedback, and further refinement is most effective. Programs we build for
ourselves often do not evolve enough; big programs that we buy from others change
too fast without necessarily improving.
Interfaces are a large part of the battle in programming. and interface issues
appear in many places. Libraries present the most obvious cases. but there are also
interfaces between programs and between users and programs. The desire for sim-
plicity and generality applies especially strongly to the design of interfaces. Make
interfaces consistent and easy to learn and use; adhere to them scrupulously. Abstrac-
tion is an effective technique: imagine a perfect component or library or program;
make the interface match that ideal as closely as possible; hide implementation details
behind the boundary, out of harm's way.
Automation is under-appreciated. It is much more effective to have a computer
do your work than to do it by hand. We saw examples in testing, in debugging, in
performance analysis, and notably in writing code, where for the right problem
domain, programs can create programs that would be hard for people to write.
Notation is also under-appreciated, and not only as the way that programmers tell
computers what to do. It provides an organizing framework for implementing a wide
range of tools and also guides the structure of the programs that write programs. We
are all comfortable in the large general-purpose languages that serve for the bulk of
our programming. But as tasks become so focused and well understood that program-
ming them feels almost mechanical, it may be time to create a notation that naturally
expresses the tasks and a language that implements it. Regular expressions are one of
our favorite examples, but there are countless opportunities to create little languages
for specialized applications. They do not have to be sophisticated to reap benefits.
As individual programmers, it's easy to feel like small cogs in a big machine,
using languages and systems and tools imposed upon us, doing tasks that should be
done for us. But in the long run, what counts is how well we work with what we
have. By applying some of the ideas in this book, you should find that your code is
easier to work with, your debugging sessions are less painful, and your programming
is more confident. We hope that this book has given you something that will make
your computing more productive and more rewarding.