Sunday, February 12, 2012

Programming at the speed of thought

In his classic "No Silver Bullets" paper in 1986, Fred Brooks claimed that the "accidents" of software development had been substantially addressed. He used the word "accident" in the Aristotelian sense, meaning tasks not inherently essential to programming like waiting for a program to compile. We were getting close to the being limited only by the essential tasks, where the limit is the human mind. I wonder how he might amend his views had he known how enterprise Java would introduce one bad accident after another to the profession. Fortunately, I think things are turning around.

The contrast between accident and essence came into sharp relief to me recently because of two things that happened one day. The first was when a colleague mentioned to me that he had wasted half a day trying to get Maven to build our application. He wasn't changing the build system: all he wanted to do was check out the latest code, build it, and work on it in Eclipse. This took literally hours to get working. The second thing was that I had been working on a personal project based on Grails.

What might have been

Grails is an example of what developer-centric programming could be. I don't say that it is unique in this regard -- even its name implies that it got its inspiration from elsewhere -- but that it is one example of a philosophy that recognizes there is a human being doing the work. If I may be so bold, I would call it humane development. The whole framework seems designed to make programming a joy. It minimizes the make-work tasks so you can focus on the creative work.

Consider what you need to do to get started with a web app. You might set up a folder structure and write a build script to compile, package, and deploy the application to the app server. You'd need to provision and configure a Tomcat instance. You'd need to set up a database server, configure a database and hook up the database connection parameters. In Grails, all you need is "grails create-app" followed by "grails run-app".

When developing in Grails, you don't build. You don't deploy. There are no build scripts. There is just "run-app". Grails will run your code in-place using its own embedded Tomcat or Jetty. Grails also embeds a RAM-based database server that it instantiates and tears down automatically. You don't need to worry about how to configure an app server nor how to connect to a database: why should you? Code changes take effect as soon as you save the file: Grails detects the changes and hot deploys into your running app. The build/deploy/restart cycle does not exist because your application is running all the time. You edit your code, save, and hit refresh on your browser to see the changes. Even database schema changes are "live": when you change your domain classes, you can have Grails either blow away the old schema (it's just RAM) and create a new one from a bootstrap script or have Hibernate apply a schema update on the fly.

As I said, Grails is not unique in its pampering of the developer. Nor is this philosophy limited to non-Java languages: we see other new frameworks like Play that exhibit a similar philosophy using Java. This kind of experience is only remarkable if you have been trapped in "enterprise Java" for a while.

The great sabotage

I keep saying "enterprise Java" instead of "Java" because the Java platform itself is not inherently unproductive. When Java came out, it eliminated a lot of the accidents of development familiar to us in C/C++ land: memory management, no more SIGSEGV nor core dumps, debugging-friendly stack traces … it was actually a good thing. Then we -- the enterprise Java community -- sabotaged it.

We got the J2EE mentality with the heavy frameworks, the XML configuration files, the bloated app servers, over-architected design patterns, intricate build scripts etc. The Java language itself may have a verbose syntax, but it is the other overhead that saps our productivity. I think the underlying problem is that we forgot about the developer. We're engineers, so we like to focus on the code and architecture. We forgot to ask "how is the developer going to work with this?" I certainly had forgotten to ask, and in the process inflicted my share of pain.

Consider the state of IDEs. When Brooks proclaimed the conquest of accidents, Turbo Pascal was popular. The executable was under 40KB in size. That size included an IDE that lets you edit, compile, run and debug all in one place. It had context sensitive language help. It could compile substantial applications in seconds on a 4.77Mhz Intel 8088 processor. Today, 40KB might be the size of your pom.xml. It takes me 15 minutes to do a build/deploy/start cycle.

It's not that today's IDEs have gotten less advanced: modern IDEs are perfectly capable of compiling and deploying a webapp in seconds. The trouble is that we often sabotage their capabilities by basing our builds on intricate Ant or Maven scripts, so that building from the IDE is impossible. For example, Eclipse can deploy non-Java resources by copying them to the output folder the moment you save the file. But if you rely on Maven's resource filtering -- which replaces placeholders in the text  during the build -- then this Eclipse behavior is no longer useful. When both the IDE and the build tool try to compile the same code, they can conflict. Only one can be in control, so we have to do things the slow way, using Maven.

Consider class hot reloading. Server-side applications can take a long time to load (it doesn't help that class loaders are still generally single-threaded). What if we could just recompile a changed class and push it to a running application? There are projects like DCE VM and Javaleon that do just that. That's great if you are writing a plain Java application, but not very useful for enterprise Java. The problem is that so much configuration happens outside of class loading. Java annotations control web service endpoints, class marshalling, transaction demarcation, database mapping, dependency injection etc. The database named query you want to change is buried in an XML file somewhere. Just reloading a class won't change any of these things: somehow the appropriate framework or container must be instructed to reread the metadata and reconfigure itself. Java frameworks assume these configuration files and annotations are only read at startup.

What could yet be

We (or just myself, at least) have done a fine job of making life miserable for ourselves. I think we should be more selfish. That is, we should not be exclusively code/architecture focused, but rather recognize that a human needs to do this work. After all, it's our productivity that is at stake, and we should be vigilant about guarding it. The technology itself is not inherently unproductive. After all, Grails itself is built on top of Spring, Spring MVC and Hibernate: all mainstream enterprise Java frameworks. We can do better both with our practices and our frameworks.

It would be nice to start a green field project with a more humane framework. But even if we can't, there is the  JRebel option. This product that claims to let you hot-reload your changes most of the time, including annotation and configuration changes for a lot of frameworks. It doesn't address the bloat and complexity of typical enterprise projects, but it does let you eliminate a lot of the build/deploy/restart turnaround time that saps concentration and productivity. I suspect JRebel's name is inspired by the Star Wars movies, and it's an apt reference. I'm thinking of that famous line,

"Help me Obi-Wan Kenobi. You're my only hope"

It's scary that JRebel is the only thing out there that claims to do what it does. It's an expensive commercial product, but it holds great promise for productivity. That is why I have requested an evaluation license to check it out. For the stuff I'm doing, it's my only hope.

Related links

2 comments:

  1. Hi,

    I'm always wondering why people are tired of restarting their app/container/server/whatever. Just write tests and stop testing with your mouse/browser. That's what ruins your productivity !

    Browser testing during development should be used only to test the JSP/JSF code which reloads instantly since JSP is JSP. Of course, if you use GWT, no one can help you...

    About Maven and Eclipse, just use m2eclipse plugin (very stable since 2 years) + WTP-bridge, classes are compiled by eclipse on your CTRL+S and deployed to your server instantly.

    I don't think Grail, Play! or JRebel are a silver bullet. They are just like aspirin when your are sick, hide the sickness, but doesn't heal anything. The real diseases is that developpers don't write tests.

    ReplyDelete
  2. Oh man I feel your pain. I'm in a very 'enterprisey' project right now, and about one and a half years ago I read about JRebel, downloaded the evaluation version and plugged it straight into the enterprise project. My God what a difference it made in my productivity - much less server restarts (didn't eliminate them completely) which saw me churn through my own list of bugs/defects like nothing before. I bought the full version once the trial expired and have been using it happily for work and personal projects ever since.

    I keep looking for little things like JRebel to help the development process along because I really believe that nothing has to be as difficult as we or these frameworks/tools/whatever keep making it. In my search for 'better ways', I've learned that the frameworks/tools/whatever that I stick with are the ones that either match closely to what I believe development should be like, or impose a very light learning curve on my part when adapting to their way of thinking.

    It's for this reason that Grails interested me a few days ago when I looked at it because its conventions for code/configuration were very close to my own. However, it's also for this reason that I shy away from the ever-popular Maven (I think their pom files are a pain in the ass and am not a fan of the directory structure it imposes) and hate JSF to death (Its bastardization of HTML is a big F U to web designers the world over).

    I like the idea that we should develop for ourselves, and the major hurdle in reaching such a lofty goal is the people: we're fickle, and we vary greatly (the commenter above me likes Maven, I do not). But I wish those who develop for developers the best of luck, because nothing has to be as difficult as we keep making it.

    ReplyDelete