This Manifesto is deprecated. My views have evolved, and a new version will be released “real soon now”.
Compared to every other field of design and engineering, programming is an embarrassment and a failure. The “software crisis” has dogged us from almost the beginning. We who have made programming our life will no longer tolerate this.
Programming languages are the fundamental technology of programming. To make fundamental improvements in programming you need a fundamentally better programming language.
History is not over
There is a widespread belief in both industry and academia that working on new programming languages is pointless. This is short-sighted. Historically, all sciences and technologies undergo revolutionary change. The lack of meaningful progress in the last 20 years means that there is an enormous pent-up potential for change, and the lack of interest in it means there is an enormous opportunity for the intrepid. It is a good time for a revolution.
It’s usability, stupid
Programming is so hard that only highly talented, trained, and dedicated individuals can do it passably well. The inescapable conclusion is that programming as we know it is just unnatural for humans. The solution is to reinvent programming to suit human cognitive skills – to program the way we think. This is a matter of usability. The sad fact is that modern programming languages are usability disasters, full of design mistakes inherited from earlier eras.
Power to the people
The first principle of usability is to know the user. The vast majority of programmers are those building end-user applications, and the even greater population of potential programmers are the end-users themselves. This kind of programming is hard not because of sophisticated algorithms and data structures, but rather because of the overwhelming multiplicity of simple constructions. Application programming is where the most people stand to benefit the most. Kernel coders and compiler writers can stick with C.
Development is adaptation
To make programming languages more usable, we must ask how they are used. In practice, programming is rarely development from scratch, but the adaptation of existing code to new needs. Development from scratch is generally a last recourse due to the inability to adapt existing code. The fragility of code to changes in design and intention is one of the most appalling failures of programming, and one of the most visible to outsiders.
Extreme Programming is a movement to adjust our methodologies and practices to the reality of adaptation. Refactoring is a technique to build support for adaptation into IDEâ€™s. The logical next step is to build adaptability into programming languages themselves. Programming languages have often been designed, and are still largely taught, under the naïve illusion that programming consists of first specifying behavior and then implementing it. OO inheritance provides a little improvement, but is increasingly acknowledged to be fragile and inadequate. We need an Extreme Programming Language.
To fully embrace adaptation as the essence of programming will require a change of attitude that is quite difficult: discarding elegant yet fragile constructions in favor of messy but flexible ones. One case in point is copy-and-paste programming. This violates all the accepted rules of modularity and hygiene, yet everyone still does it routinely. Either most programmers are stupid and evil, or the accepted rules are idealistic and impractical. The latter is the case. It is necessary to embrace copy-and-paste as a first-class “semi-modularity” mechanism in the language to track it, manage it, and eventually refactor it into proper modularity. This may be heretical, yet an honest appraisal of how programmers really work requires something like it. Usability is a subversive idea.
Text is a dead-end
Programming is stuck in an evolutionary dead-end: the use of character strings to encode programs. Every other computer-mediated form of expression has evolved beyond text into sophisticated WYSIWYG interfaces to complex data structures. For example, no one still uses textual markup for word processing (except, notably, Computer Scientists with TeX). We need WYSIWYG programming.
It’s called “code” for a reason
Programming languages are built upon two basic tricks: the use of grammars to encode tree structures (AST’s) into text, and the use of names to encode linkages across these trees. Much of what makes a language unique is its particular style of name resolution, as in the polymorphism and inheritance techniques of OO languages. Text is a dead-end because all these sophisticated techniques in one way or another are just encoding structure in text strings. This is disastrous for usability.
Structure needs to be made explicit and directly manipulable, not implicit and encoded. Mentally parsing and interpreting this implicit structure is an enormous cognitive burden for the programmer. Modern IDE’s such as Eclipse go to great lengths to extract the encoded structure back out of the text and help us to visualize and manipulate it somewhat more directly. Refactorings are provided by the IDE to automate the complex and widespread changes in syntax necessary to effect simple semantic changes. This is absurd. We should manipulate semantic structures directly through a WYSIWYG interface. The language is the IDE.
Much of what we know about programming language design is about clever ways to encode structure in text, and fancy ontologies to rationalize naming. Discarding the textual representation suddenly makes all this irrelevant, and opens a whole new space of design choices. Some who are invested in the status quo will see this as a threat and become counter-revolutionaries.
Visual languages are not the solution
Prior and ongoing attempts to evolve beyond textual programming have focused on Visual Programming. The common idea is to replace AST structures with some form of graphical diagram. While well-intentioned, nothing compelling has yet resulted from this approach, and it is widely seen as a failure. The reason may be that it does not go far enough, merely substituting a different surface representation for the same old semantics (and generally retaining even the surface syntax of names). These semantics are highly evolved to suit textual representations, so it is not a surprise that merely altering the surface representation does not help. We need to simultaneously rethink both the syntax and the semantics of programming languages to break out of the current deadlock.
Programming is not Mathematics
Many usability failures of programming languages are due to the pernicious idea that programming should be like mathematics. The need to discard unrealistic expectations of mathematical elegance has already been discussed.
Expressions do not scale
In Science and Math, formulas are typically one-liners. Even small programs are far larger than any mathematical statement. Expression-based languages attempt to scale up formulas to hundreds or thousands of lines. One reason this does not work is that people can not easily handle more than about 2 levels of nesting. We are not stack machines! Natural languages rely on linear narrative flow and avoid deep nesting. This may be the real problem with LISP: people complain about parentheses, but they are really complaining about deep nesting.
Featureless structures do not scale
Argument lists become difficult to use beyond about 2 or 3 arguments. Even in math, operators and functions of arity more than 2 are rare. English verbs take at most 4 arguments. It is absurd to expect humans to remember large function/method signatures purely by argument order. The simple expedient of keyword arguments is lacking in most languages. This fact reveals a shocking disregard by programming language designers of even the most basic considerations of usability. What can they be thinking?
Terseness is prized in Math and Science. While being able to write Quicksort in 3 lines may seem like a powerful feature, it is in fact bad for the actual practice of programming. Theorems and Laws of Nature may last a century before becoming obsolete, and are generally about widely relevant concepts. Programs are lucky to make it to the next release, and are mostly about highly localized and detailed concerns. The primary use-case of programming is the modification of code written by someone else. Readability, as opposed to terseness, is far more important in programming.
Many programming languages are designed as if saving keystrokes was important. This might have been appropriate when we used teletypes to program, but it is not relevant in real life programming, where far more time is spent reading and thinking than typing, and especially when there is a smart IDE to fill in some of the typing.
Change is natural
There has been much effort expended to remove the concept of mutable state from programming, to be replaced by immutable values as in mathematics. This is entirely misguided. The idea of a changing world, if not in the nature of reality, is certainly in the nature of humans. To replace this utterly common sense idea with elaborate abstractions is precisely the wrong thing to do to make programming more usable. Monads are a reductio ad absurdum.
Control flow considered harmful
Most programming languages adopt a control flow model of execution, mirroring the hardware, in which there is an execution pointer flowing through the program. The primary reason for this is to permit side-effects to be ordered by the programmer. The problem is that interdependencies between side-effects are naturally a partial order, while control flow establishes a total (linear) order. This means that the actual design exists only in the programmer’s mind. It is up to the programmer to mentally compile (by a topological sort) these implicit dependencies into a total order expressed in a control flow. Whenever the program’s control flow is to be changed, the implicit interdependencies encoded into it must be remembered or guessed at in order to maintain them. Obviously the language should allow the partial order to be explicitly specified, and a compiler should take care of working out an execution schedule for it.
Performance is a cop-out
Performance is a favorite excuse for rejecting technological change. Performance improves with engineering investment, and thus tends to be superior for entrenched technologies. The fact is that performance is not critical in most software, especially in the end-user applications that are the target. Performance also steadily improves in hardware. Based on history, it takes 20 years for a new programming language idea to become mainstream, and in 20 years we can expect a 1000-fold improvement in hardware performance. Thus the appropriate performance target is to handle unintensive end-user code given hardware 1000 times faster than today. This provides so much leeway that performance becomes effectively a non-issue.
Concrete is better than abstract
Programming is fundamentally about building abstractions, and humans are fundamentally weak at understanding abstractions. This conflict is an essential reason for the difficulty of programming. Whenever possible, language features should favor the concrete over the abstract.
The proven method for understanding abstractions of all kinds is to make them concrete with examples. Abstractions should appear, whenever possible, in the context of examples. The fullest realization of this idea is to integrate examples into the abstraction mechanisms of the programming language itself. There should be no such thing as naked code which is isolated from a working example. Another perspective on this approach is that it builds testing into the semantics of the language. For more details, see Example Centric Programming
Vive la revolution!
Programming will continue to suck until we treat this as the overriding issue, and are willing to sacrifice absolutely everything else to fix it. Commercial considerations often dictate that compatibility and performance have the highest priority, with disastrous consequences (witness C++). As the Open Source movement has demonstrated, progress requires overthrowing the economics of software. We will need to go even further, freeing our minds of traditions established with the very first programming languages. Usability is the guiding light to rationally reinvent programming from scratch.
Programming is at a dead-end. The only way things will get better is with a complete revolution. More conservative attempts over the years have repeatedly failed to make a difference, leading to the widespread abandonment of hope. We have nothing to lose.
Programmers of all countries, unite!
Comrade Jonathan Edwards
June 16, 2004