No Royal Road to Programming

Proclus Diadochus (c. 410–485 C.E.) wrote that, “Ptolemy once asked Euclid whether there was any shorter way to a knowledge of geometry than by a study of the Elements; whereupon Euclid answered that there was no royal road to geometry.” Advice of the same sort is pertinent to those who wish to become good computer programmers, although there is no Euclid to write the Elements for informatics—unless perhaps we count Donald Knuth and his magnum opus, The Art of Computer Programming. Like the Elements, Knuth’s epic is stunning in its span and its depth, and perhaps equally daunting to the newcomer.

Yet the shelves in the Computer Books section of your local bookstore are filled nearly to bursting with titles that purport to set you a smooth and easy path to some programming goal, whether it may be writing “Java enterprise applications,” or the latest fads in dynamic web pages using “active Javascript and XML” (AJAX). Academic publishers regularly flood my mailbox with titles that claim to “teach programming in 12 easy lessons,” or provide lessons in plain and simple language free of “complicated mathematics.” I have found that these books are uniformly awful as instructional aids. Much of their awfulness stems from the fact that they try too hard to pave over the precise thinking and careful, methodical effort that is necessary to a good programmer.

Rex Page, at the University of Oklahoma, wrote of learning to program, that:

“Your greatest frustrations will come when you try to construct programs on your
own because programming language systems [...] are unbelievably intolerant of
minor errors. One comma out of place and the whole program is kaput.
This may be the first time in your life you’ve had to deal with such an extreme level of inflexibility. Unfortunately, you’ll just have to get used to it. Computer systems are more tolerant now than they were twenty years ago, and they’ll be more tolerant twenty years from now than they are today, but it may be a very long time before they are as tolerant as even the most nit-picky teacher you ever crossed paths with.”

His words are true and wise. There are no shortcuts that will permit you to become an effective programmer without precise thinking; there is no substitute for patient and methodical work. There is, in short, no royal road to computer programming.

But that does not mean that learning to program has to be unpleasant or burdensome. This kind of logical thinking is not natural for most people, but even though learning to think in a careful and logical manner can seem a little strange and confusing at first, it gives you a feeling of great liberation and power once you have gotten the trick of it. The joy of making a program work the way you intended is difficult to describe to someone who has not had the experience firsthand—but everybody who tries it honestly discovers it is fact. That it is not easy only makes it more rewarding when you succeed.

I think that part of the key to enjoying the effort of programming is recognizing that the rules of computation we use are not “natural laws,” but simply customs of convenience: “Formal logical proofs, and therefore programs—[which are] logical proofs that particular computations are possible, expressed in a formal system called a programming language—are utterly meaningless. To write a computer program you have to come to terms with this, to accept that whatever you might want the program to mean, the machine will blindly follow its meaningless rules and come to some meaningless conclusion.” (Saeed Dehnadi and Richard Bornat, “The Camel Has Two Humps”). We should therefore not wrack ourselves searching for deep, philosophical implications of these customs, but instead relax and treat the whole exercise as a kind of game, in which the goal is to find pretty patterns in an intricate piece of artwork. We play such a game not to answer the enduring questions of epistemology or metaphysics, but because it is an enjoyable activity in its own right.

To put it another way, what makes programming difficult is not usually the assignment of meaning to the results of some computation, but in understanding the very mechanical consequences of an arbitrary system of formal rules that, in itself, lacks any intrinsic meaningful interpretation. Once we can grasp the implications of the rules we have chosen, the problem of assigning meaningful interpretations to what the computer has done is a task analogous to choosing what colours to use in a painting: It is a human task, subject to whatever combination of aesthetic and utilitarian judgement suits our purposes. Much more difficult is to learn all the “rules” of painting—what manner of canvas to use, how much gesso to lay down, what types of brushes to employ, how to mix and thin the pigments, and with what substances; what order to lay down the colours, how to achieve a particular texture, how long to wait for drying, and so forth. These are the tasks that require practise, perseverance, and attention to detail. They have no importance in themselves, but they are the basic tools of the art, and until we understand them, we cannot paint a picture, even if we can see the picture clearly in our minds.

A competent computer programmer must also learn some basic skills of this type. She must learn how to reason deductively from a set of premisses to reach a conclusion. She must know the primitive elements of her formal system, and learn the rules governing combination of its elements. She must learn a language of conventional jargon that will permit her to talk with other programmers about the construction, analysis, and encoding of algorithms, so that she can both read and write about what she has learned. She should learn a solid vocabulary of basic data structures and algorithms, so that she need not solve every new problem from first principles. And, most importantly, she must practise what she has learned by using it to solve new problems she has never seen before, so that she will become fluent and comfortable with her new knowledge and not lose it through idleness.

Above all, however, it is important for a programmer to keep a sense of curiosity and fun about the whole process. Programming shares a lot in common with playing a musical instrument, in many ways: It requires a lot of hard work and practise to to become really good at it, but anybody who is patient can learn the basics and have some fun. There are lots of different programming languages you can use, but there’s a common theory that ties them all together. A well-written program can be beautiful, although occasionally it takes another programmer to really appreciate that beauty. A group of programmers can produce a much more complex program than an individual working alone, but it takes a lot of discipline for them to work together effectively. If you make a lot of mistakes in your program, nobody will want to use it (although, if you’re the only game in town, they might put up with it anyway). If you want to become a better programmer, you can—if you take the time to learn and practise. The quality of your tools can affect the quality of your programs, but not nearly as much as your skill as a programmer does. There are lots of programmers out there who make lots of money, yet have no real talent for programming.

This analogy is pretty good, and there are useful lessons to be drawn from it—though as far as I know, nobody ever made a living by busking code in the subway tunnels for spare change. The point is, although there is no royal road to becoming a skillful programmer, the effort of doing so has its own rewards. It’s not for everyone, but if you’re the kind of person who likes to ask, “what happens if I try this?” or who says, “I wonder if I could get the computer to do that for me,” then it seems pretty likely you would enjoy the ride. Just remember not to let a little work scare you off, nor the need to keep track of a few details. And, while you’re at it, it couldn’t hurt to familiarize yourself with Euclid’s Elements; after all, it’s the great-grandaddy of all meaningless formal systems.

How Quaint

Every technology goes through three stages: first a crudely simple and quite unsatisfactory gadget; second, and enormously complicated group of gadgets designed to overcome the shortcomings of the original and achieving thereby somewhat satisfactory performance through extremely complex compromise; third, a final proper design therefrom.

In transportation, the ox cart and the rowboat represent the first stage of technology.

The second stage might well be represented by the automobiles of the middle twentieth century just before the opening of interplanetary travel. These unbelievable museum pieces were for their time fast, sleek, and powerful—but inside their skins were assembled a preposterous collection of mechanical buffoonery. The prime mover for such a juggernaut might have rested in one’s lap; the rest of the mad assembly consisted of afterthoughts intended to correct the uncorrectable, to repair the original basic mistake in design—for automobiles and even the early aeroplanes were “powered” (if one may call it that) by “reciprocating engines.”

A reciprocating engine was a collection of miniature heat engines using (in a basically inefficient cycle) a small percentage of an exothermic chemical reaction, a reaction which was started and stopped every split second. Much of the heat was intentionally thrown away into a “water jacket” or “cooling system,” then wasted into the atmosphere through a heat exchanger.

What little was left caused blocks of metal to thump foolishly back-and-forth (hence the name “reciprocating”) and thence through a linkage to cause a shaft and flywheel to spin around. The flywheel (believe it if you can) had no gyroscopic function; it was used to store kinetic energy in a futile attempt to cover up the sins of reciprocation. The shaft at long last caused the wheels to turn and thereby propelled this pile of junk over the countryside.

The prime mover was only used to accelerate and to overcome “friction”—a concept then in much wider engineering use. To decelerate, stop, or turn the heroic human operator used his own muscle power, multiplied precariously through a series of levers.

Despite the name “automobile” these vehicles had no autocontrol circuits; control, such as it was, was exercised second by second for hours on end by a human being peering out through a small pane of dirty silica glass, and judging unassisted and often disastrously his own motion and those of other objects. In almost all cases the operator had no notion of the kinetic energy stored in his missile and could not have written the basic equation. Newton’s Laws of Motion were to him mysteries as profound as the meaning of the universe.

Nevertheless millions of these mechanical jokes swarmed over our home planet, dodging each other by inches or failing to dodge. None of them ever worked right; by their nature they could not work right; and they were constantly getting out of order. Their operators were usually mightily pleased when they worked at all. When they did not, which was every few hundred miles (hundred, not hundred thousand), they hired a member of a social class of arcane specialists to make inadequate and always expensive temporary repairs.

Despite their mad shortcomings, these “automobiles” were the most characteristic form of wealth and the most cherished possessions of their time. Three whole generations were slaves to them.

— Robert A. Heinlein, “The Rolling Stones” (1952)