Writing a computer program is like trying to assemble a grandfather clock, blindfolded, without being sure that one has all the parts. That is, it requires the coordination of countless intricate pieces with no good way of observing the functioning of the whole. Put one tiny part in the wrong place and everything stops, but you can only discover the error by probing each part of the system in turn, memorizing the numerous linkages, combinations, and movements. It’s a wonder any programs ever work.

Software needn’t be so. No physical constraints govern the arrangement of its components. Nothing need be hidden from view behind a decorative covering. Only our ingenuity limits the number of ways we can recombine different pieces, the tools we can use on them, the ways we look at their operation. As Fred Brooks has said, “the programmer, like the poet, works only slightly removed from pure thought-stuff. He builds his castles in the air, from the air, creating by exertion of the imagination.”

It falls to us, then, the makers and users of programming languages, libraries, environments, to decide which tools we need, how they should function, and what they should look like. The ones we have now are just starting to adjust their forms to the problems we are trying to solve and the behaviors we are try- ing to understand. Originally, they were primitive, general-purpose instruments: the text editor knew nothing of the programming language; the operating system cared little for one’s source code. Now connections are beginning to form: editors display variables in a different color from strings, comments with less saturation than function calls; a program crash often comes with a list of the lines of code immediately preceding the disaster; syntax errors in a source file get a squiggly red underline as you type; one can edit the code of a running program; even record every function called, variable modified, input received.

And yet, there is no equivalent to opening the case of the clock and watching it tick out the seconds, the swaying pendulum letting rotate a gear, that regulating the revolutions of another, slower, one, and that a third, and a fourth, chains driving the hands from behind, the whole ballet powered by a slowly descending weight. We cannot watch a whole program at work.

Of course, there are difficulties. Software is orders of magnitude more complex than even the most intricate clock. It is made of text – words that become meaningless at a distance. It runs inconceivably fast, so that we cannot possibly examine each of its actions individually. It is made of heterogeneous parts, written by different people in different languages with varying degrees of secrecy. It is written under pressure, changed often, and required to work under wide-ranging conditions, with a menagerie of accessories and managers.

Still, reasons exist for hope. As computers get faster and the complexity of their software increases, so too do the resources it offers us to understand and assemble our code. We constantly find new abstractions that allow programmers to work at higher and higher levels, and to reuse more and more mature technology. As we learn that programmers are people too, we can successfully apply to them many of the principles that help ordinary people use all types of software.

This thesis attempts to do just that: show how an understanding of the goals and mindsets of programmers can be used to design tools to help them understand the dynamic behavior of their programs. It attempts to reduce the cognitive burden on programmers by suggesting how knowledge and reasoning could be shifted from their heads into a tool. By making it easier to read as well as write code, it hopes to ease the reuse and debugging of existing source.

Because this work concerns reading and understanding - not writing - code, it develops tools for traditional programming languages like C/C++ and Java. The prevelance of these languages and the large amounts of existing programs written in them suggests that such tools will be necessary for the conceivable future.