I discovered the creative exhilaration of programming at a formative age. Yet all along I have also felt stifled by primitive, ill-suited languages and tools. We are still in the Stone Age of programming. My quest is to better understand the creative act of programming, and to help liberate it. Reflection upon my own practice of programming has led me to three general observations:
- Programming is mentally overwhelming, even for the smartest of us. The more I program, the harder I realize it is.
- Much of this mental effort is laborious maintenance of the many mental models we utilize while programming. We are constantly translating between different representations in our head, mentally compiling them into code, and reverse-engineering them back out of the code. This is wasted overhead.
- We have no agreement on what the problems of programming are, much less how to fix them. Our field has little accumulated wisdom, because we do not invest enough in the critical self-examination needed to obtain it: we have a reflective blind-spot.
From these observations I infer three corresponding propositions:
- Usability should be the central concern in the design of programming languages and tools. We need to apply everything we know about human perception and cognition. It is a matter of “Cognitive Ergonomics”.
- Notation matters. We need to stop wasting our effort juggling unsuitable notations, and instead invent representations that align with the mental models we naturally use.
- The benefits of improved programming techniques can not be easily promulgated, since there is no agreement on what the problems are in the first place. The reward systems in business and academics further discourage non-incremental change.
What is the future of programming? I retain a romantic belief in the potential of scientific revolution. To recite one example, the invention of Calculus provided a revolutionary language for the development of Physics. I believe that there is a “Calculus of programming” waiting to be discovered, which will analogously revolutionize the way we program. Notation does matter.
Our current choice of notation leaves much to be desired: ASCII strings encoding structure through grammars and names. We have automated many complex information artifacts, from documents to diagrams, and we have built many complex data models and user interfaces for them. From this perspective, it is absurd that programs are still just digitized card decks, and programming is done with simulations of keypunch machines. The move from keypunches to on-screen editing was a huge leap forward, but that was 30 years ago. We have not yet taken the next logical step, which is to represent programs with the complex information structures made possible by computers.
The guiding goal I propose above is programmer usability. One way to discover how to make programming more usable is to look for clues in what currently feels the most difficult and unnatural when we program. Here are some of the clues I am investigating:
- We often think of examples to help understand programs. Programs are abstractions, and abstract thinking is hard. Across all fields, examples help us learn and work with abstractions. Example centric programming is my proposal to integrate tool support for examples throughout programming. Going further, I am trying to reduce the level of abstraction required in the first place with prototype-based semantics and direct-manipulation programming.
- We tend to build code by combining and altering existing pieces of code. Copy & paste is ubiquitous, despite universal condemnation. In terms of clues, this is a smoking gun. I propose to decriminalize copy & paste, and to even elevate it into the central mechanism of programming.
- The dominant programming languages all adopt the machine model of a program counter and a global memory. Control flow provides conditional execution, and allows memory accesses (side-effects) to be serialized. The problem is that control flow places a total order on the actions of the program, while both conditionals and side-effects are inherently partially ordered. One condition arises when a specific combination of other conditions arise. Likewise we care that a data read occurs only after a specific set of data writes. Control flow languages force us to do a topological sort in our head to compile these relationships into a linear execution schedule. What’s worse, we later have to reverse engineer the tacit relationships back out of the code. Control flow is a suitable notation only for the back-end of a compiler, and should be considered harmful to humans. Escaping the linear confines of textual notation is a first step towards directly expressing non-linear relationships. To better represent side-effect relationships, I am exploring database-like transactional semantics.
- Our languages are lobotomized into static and dynamic parts: compile-time and run-time. This dichotomy exists solely for ease of compilation and optimization of performance. Modern hardware and compilers have made these concerns unimportant in most situations, yet they live on enshrined in the design of our languages. There should be no difference between run-time and edit-time. More generally, we must discipline ourselves to ignore the siren call of performance, keeping the tiller pointed towards usability.
- We can roughly categorize many mental models into two types: structural and behavioral. Some cognitive scientists trace this division to specializations for vision and communication, respectively. Our programming languages are highly biased about these two representation styles. Generally, we use structural models for static constructs, and we use behavioral models for dynamic constructs. This pattern is seen most clearly in pure OO languages like Smalltalk. We can not afford to program with one hand tied behind our back: we need to integrate the use of structural and behavioral models throughout programming. To better frame the issue, I am exploring the â€œdualâ€ of OO, in which the encapsulation of behavior is replaced by the publication of reactive structure.
These clues outline a long-term research program, in which I hope to collaborate with others of like mind. The first steps can be seen at subtext.
Leaping ahead, let us suppose for the moment that we have invented a revolutionary new way to program. How can we get programmers to use it, academics to research it, and entrepreneurs to invest in it? As discussed earlier, there are deeply entrenched obstacles to change, both psychological and institutional. The endless cycle of hype and disappointment has hardened cynicism. I am afraid that we have reached the point where talking is useless.
I can think of only one strategy to break this deadlock: lead by example. We need to get our hands dirty and build real code for real users, and do it better-faster-cheaper. Nothing succeeds like success. Thinking even further out, perhaps we could establish something like a teaching hospital: a non-profit organization that combines programming for real clients with a mission of education and research. In the meantime, the first job is the inventing.
[Welcome Diggers. Before you comment on this old post, I suggest you take a look at what I have done in the meantime. The best summary is in my last OOPSLA paper.]