Saturday, June 30, 2007

von Neumann's Long Farewell

A big step in solving the software crisis is to accept that programming is not about computers. Yes, it used to be, and still is for brave souls working on operating systems or compilers. But in the long list of the world's software struggles, compilers rank pretty low.

It's easy to think programming is about computers because that's where we see problems. Of course, these are only symptoms of human error. Developers are constantly stretching to express behavior in terms friendly to a computer, making life harder so we can be easier on our machines. Such problems have been pointed out decades ago by the likes of Dijkstra, Backus [pdf], and Abelson and Sussman. Surely there is a way to describe our systems better than the terms of the von Neumann architecture.

For years we were limited by the capabilities of the machines, but this limitation has vanished for most of us. We've entered a new era, where improving the way we build software is as much a social problem as a technical one. Fortunately, there are signs of a growing social bedrock that could finally help us.

The Thirst for Abstraction

For a long time I didn't understand Guy Steele's comments on how Java can pull C++ developers about halfway to Lisp. Surely that fraction must be off; writing code in Java certainly feels a lot closer to C++ than Lisp. But independent of the Java language, the platform did a major service for the industry: it proved to the masses that we no longer need to express our designs directly in terms of the von Neumann architecture.

The abstraction offered by Java-like languages is small but significant. The conventional wisdom in software has long held that code must be expressed in terms of the machine to achieve passable performance. This myth is gone. Nearly every major software company is adopting some form of garbage collected, virtual machine-based language. We rely on the platform to map our higher-level expressions to efficient machine code.

This is a big step because accepting this level of abstraction opens the door to others. Why should we explicitly state data type information, when it can be inferred at compile or run time? Why not abandon primitives and arrays for objects and lists, since our platforms can now optimize away unneeded allocation? Why struggle with keeping track of many small state changes when major operations could change state atomically? Such abstractions make life easier for us, and previous successes suggest it will work. The result is a self-perpetuating thirst for abstraction. Expressing designs so humans can easily reason about and manipulate them is addicting.

von Neumann's Long Farewell
For many of us the shift away from the von Neumann architecture is painfully slow. Unfortunately the best ideas are often slow to be adopted. People are used to the way they've worked before, or averse to risk. So our transition toward better software is incremental -- but it is happening. Mainstream languages are offering higher-level concepts in their latest revisions. Adding concepts like closures, type inference, and applicative libraries does the software industry a service. It moves us toward a better way to write code. Hopefully some day we'll realize the low-level complexity we've dealt with isn't really necessary and abandon it altogether.

Sunday, June 3, 2007

Why are we so polarized about Java?

It seems impossible to constructively praise or criticize Java without eliciting strong reactions. It comes from both sides; some seem to love to hate Java, and parts of the Java community become defensive as a reaction.

For example, Paul Buchheit recently posted some insights into API design, referring to poor examples that happen to be written in Java. He immediately states he doesn't hate Java. The post is about APIs, not the language. Even so, he still had to update his post saying "It's not about Java, really", presumably because of some polarized reactions. This is unfortunate because it distracts us from Paul's excellent commentary.

I suspect the polarization starts from a trap I have fallen into myself. Like many involved in language discussions, I use Java professionally and other languages at night, so I run into examples analogous to the one described by Paul Buchheit. I sometimes get frustrated with poor APIs, and also with the Java language -- either directly or by association with poor APIs. I wonder, couldn't it use powerful constructs I use in other languages, or could the APIs just plain be simpler?

The problem is my frustration may linger when I discuss programming languages, and (knowingly or unknowingly) be reflected in my tone when discussing Java. The resulting post is more acidic, and less level handed than I would like. Those who disagree with my arguments are likely to pick up on that tone and may respond in kind. Before long we've spiraled into isolated camps, and meaningful discussion is hard to achieve. My last post had signs of this.

So, where did I go wrong? When discussing constructive criticism of Java and its APIs, we need to view Java with some perspective. We need to remember its history. So my first point is:
We are critical of Java in a context different from the one in which it was designed.
A key goal for Java was to replace C++, and this goal led to design decisions that are often targets for criticism today. In 1996 it wasn't clear we could create a sufficiently fast language without primitive types and arrays. It wasn't clear how much boilerplate code would be required by anonymous callback classes or checked exceptions. It wasn't clear that since the new syntax exactly specifies implementation, factory patterns would proliferate, and so on. So my second point:
Criticisms of Java should not imply any negatives about the designers of Java. Critics of Java are likely working in a problem space that differs from Java's original design goals, or incorporating new knowledge from the past decade.
There are certainly some that disagreed with the above decisions in 1996, but it was surely more debatable then, and different decisions may have slowed Java's proliferation -- which was opposed to its original design goals.

The key is we need to keep this background in mind whenever discussing Java. We can criticize Java and its APIs without insulting anyone. When being critical of Java, any frustrations should be tempered by knowing the landscape has changed. Similarly, apologists should recognize that criticism need not be viewed as an attack; it might be an attempt to make things better.