The Artima Developer Community
Sponsored Link

Cool Tools and Other Stuff
JavaOne 2007, #2: Making Web Apps Easy
by Eric Armstrong
May 10, 2007
Summary
Today, JavaOne 2007 showcased a complete open source technology stack that lets you develop and deploy web applications quickly and easily, including JRuby, Rails, NetBeans, and Glassfish.

Advertisement

While JavaFX Script aims to simplify things for web designers, a collection of technologies including JRuby, Rails, NetBeans, and Glassfish combine for an unparalleled application development experience. This post focuses on those development technologies.

I've heard a lot about how easy it is to develop web applications using Rails, but now I've actually seen it. At one of their several talks on JRuby and Rails at JavaOne, Charlie Nutter and Tom Enebo stepped through the process and took the audience on a short tour of the application structure.

At each talk, Charlie asked the mostly-Java audience, "By a show of hands how many people really love their development process for web apps?" There were staggeringly few. But Rails developers, it seems, are rabid about it. They love doing it. So let's see how the other half lives.

Note: It's still an open question as to how much they love maintaining an app they built a while ago--or someone else's app. That's where Java's readability really shines. I'd love to see a straw pole on that topic, one day.

Contents

Why Rails?

There are a number of reasons to like the Rails framework for web development:

  • The "Convention over Configuration" mantra keeps things simple. You follow some basic naming conventions and the framework figures things out for you--so if you're looking for Person with ID=Fred, Rails will go to the database, access the People table, find the row with right ID, wrap it's contents in a Person object, and deliver it back to you.
  • The database specs are agnostic, so you can easily migrate to a different database later. That makes it easy to develop your app with a test database and later deploy with a production version.
  • You can define database migration scripts that make it possible to rollback to a previous version of the schema for testing and bug fixing.
  • There are libraries for login, authentication, and other common web application tasks.

Rails also gives you an agile development environment:

  • You have a fully functional app right from the start that you can incrementally extend to add the behaviors you need.
  • You can iterate quickly. Ruby is interpreted, so there is no need to recompile the app, redeploy it, or restart the server. You just make the changes you need to make, then run your tests or try it out interactively. That's all there is to it.
  • The testing harness is built into the framework. You have a place for your tests right from the start, and many of the code generating functions create an initial set of tests--so you're encouraged to test as you develop--and that is the key to keeping it fun.

Rails also gives you the benefits of Ruby. It takes a lot less code to get things done in Ruby and Rails--to the point that development time can be measured in days, rather than weeks. Ruby has many features that conspire to make you more productive. Even if no one feature is compelling by itself, those features make Ruby great for writing the "glue" that ties libraries and components into an application:

  • Fully OO: Everything is an object, so there is no need to remember different ways of doing things for primitives.

  • Dynamic, but strongly typed: Once assigned, a variable stays true to type.

  • Literals for regular expressions, lists, and hash maps.

  • Powerful string processing, including multi-line strings and string interpolation (put #{x} in a string, and the value of x is inserted inline).

  • Blocks: Snippets of code you pass around and invoke.

  • Closures: Snippets that know their context, so this code knows about the File object, and knows to close it when the block has finished executing:

    File.open(someFile) { |f| ... }
    
  • "Duck" typing: If it quacks like a duck, then for all intents and purposes, it is a duck. If it has the methods you need, it works. You don't have to declare them in advance. (But since there is no interface to remind you to implement them, you have to do more testing--which is a good idea in any case.)

Ruby is also a better language for metaprogramming and building domain-specific languages (DSLs):

  • Open classes: You can literally "extend" a class by adding behaviors you need to that class.
  • Module mix-ins: You add stuff to your class by "requiring" a module.
  • Hooks like method_missing and method_defined that let you implement dynamically adaptive behavior.
  • Reflection behaviors, so x.send(:y args) is equivalent to x.y(args)

Ruby has a terrific ecosystem, as well. You not only get Rails, you get a variety of other utilities that take advantage of Ruby's ability to define a higher level language that is tailored for a specific domain:

  • Rake: A powerful build utility.
  • Raven: Ruby's implementation of Maven.
  • Rspec: A testing utility in which each test is literally a functional specification.

There certainly is a lot to like. (For more on the features that make Ruby great, see the articles in the Resources.)

Create and Test a Rails App

All of those features are terrific, and they got me into Ruby. But knowing about them didn't help me get started building a Rails app. After two Ruby conventions, I still didn't know how to create one. (Ok. So I could have read a book. I'm lazy. Shoot me.)

But JavaOne is a different kind of convention. I don't know how the organizers do it, but they manage to set things up so that most every presentation explains the basics and demonstrates how things are done. That makes JavaOne pretty much the best educational opportunity in town. And this year, a lot of time was devoted to other languages that run on the Java platform, including JRuby, Groovy, Tapestry, and JavaFX Script.

So this year, I got to see how a Rails app is constructed. Here's an overview of the process:

(j)rails myapp -- setup the project directory
(j)ruby script/server -- start server and see basic page
(j)ruby script/generate -- create parts of the app skeleton
 ...do a little editing...
 ...repeat for other parts of the app...
(j)rake -- build the app
 ...try it out...

What follows is a mashup of a couple of demos I saw. Some of the details are bound to be wrong, but the notes should serve to outline the process.

The first step was to setup the application:

rails myapp

There must have been a configuration step to make that step work with jruby, but we didn't see it. The next step was to start the server:

jruby script/server

The default server, Webrick, is built-in, so that's all you needed to do. Even with no code added, it was now possible to view http://localhost:8080 and see an initial start page.

Next, they generated the username/password action for logging in, along with the unit tests for that behavior:

jruby script/generate controller test hello

The next two steps were single line edits in very small generated files. The first added the variable @hello="..." to the action script:

vi app/controller/tests/(target file)

The second displayed the contents of that variable in the view file (an rhtml file that looks a lot like a JSP page):

vi app/views/hello.rhtml

The call looked something like this:

<% someDisplayFunction @hello %>

To configure database access (an optional, but typical part of a Rails app), they copied a small configuration file, to save a bit of time:

cp ../database.yml config/

Then, just for fun, they took a look at the place where the Rails conventions are defined:

vi config/environment.rb

Next, they set up for database migration, to show how that works:

jruby script/generate migration person
vi db/migrate/001_person.rb

As you make changes to the database, such scripts let you migrate the schema and rollback to a previous version to fix the bug with a command like this:

rake db:migrate

The next step generated the scaffolding for CRUD operations (create, read, update, delete):

jruby script/generate scaffold person

It was now possible to take a look at some of the generated scripts:

app/models/person.rb
app/controllers/people_controller.rb

It was then necessary to restart the server (something which, in general, is only needed after adding or removing a database):

jruby script/server

Visiting the localhost URL then showed the modified page.

Architectural Overview

Here are the major components of Rails:

  • ActiveSupport -- base framework
  • ActiveRecord -- DB support
  • ActionPack -- views & controllers
  • ActionWebService -- web service framework
  • ActionMailer -- email framework
  • Railties -- ties it all together

And here is the directory structure of a Rails application:

app
  controllers
  helpers
  models
  views
config
db
lib
public
test

Develop Faster with NetBeans 6

Once you have the application skeleton created, you'll need to add some code. NetBeans 6 will make that process a heck of a lot easier.

Charlie Nutter's comment underscores that point:

There is a lot of corporate interest in Ruby IDEs, these days and a lot of work going into tools support. NetBeans is the furthest ahead. Some people are even leaving emacs, to get those features in NetBeans.

Actually, NetBeans is supporting more than just Ruby. They've been putting in generalized support for dynamic languages and letting users customize the pretty printing behaviors (among other things) by making choices in a dialog--a lot better solution than having to write a plugin that uses the NetBeans APIs.

With respect to Ruby, Tor Norbye from Sun Microsystems demonstrated the many capabilities that make life easier for (J)Ruby developers:

  • Project types for Ruby & Rails
  • Integrated gem management
  • Integrated rake builds
  • Code completion
  • Go to definition
  • Syntax coloring
  • Background error detection with red underlining
  • Gray for unused variables
  • Bold for a method
  • Cursor on an variable highlights it everywhere it exists
  • Cursor on method call highlights all exits
  • Ctrl+shift+F to reformat code

As a long time IDE user in Java-land, I have to say that I desperately missed those capabilities when I began coding Ruby. I loved Ruby anyway, but I felt handicapped. With NetBeans, they're back in my arsenal. Life is going to be good.

To switch between Ruby and JRuby, you change a path in a configuration file. That turns out to be important in the early releases, because debugging works better with native Ruby, for now. But in most other respects, you'll probably want JRuby. (More on that subject in a moment.)

For debugging, you get all of NetBeans' normal capabilities:

  • Call stack
  • Local variables view
  • Evaluate an expression
  • See threads and switch between them

To make all of that work in the early releases, there are several things you to need to do:

  • Switch from classic debugger to fast debugger
  • Install the rubydebug-ide gem
  • Use the native Ruby interpreter

Manage the Project with Mingle

Mingle is a web-based application designed for software projects. It includes functions for project management, issue tracking, source code versioning, and requirements analysis.

It's targeted at agile IT projects, and built by agile developers. So it's worth a look. But it holds a special place in the heart of the JRuby developers because, when it came time to create reliable, scalable deployments, they turned to JRuby. Their reasoning is given at: http://studios.thoughtworks.com/2007/5/7/mingle-to-run-on-jruby

Deploy on a Java Application Server like GlassFish

Once you have your application built and tested, you need to deploy it to a production server. But even though it's easy to develop a Rails application, it can require a lot of work to make it perform well.

For serious scalability, you'll probably want to deploy on a Java Application Server--for example, the open source standard in that category, GlassFish. (That will be especially true when JRuby achieves its goal of support for database pools and other enterprise features.)

You may still need to do some performance tuning eventually, but a fast server can delay the day it becomes necessary, and make the tuning pay off that much more when you do it.

As noted by the JRuby speakers, deploying on a Java Application Server also gives you a major advantage when you're sneaking Ruby into the enterprise:

You can deliver a WAR file to the IT department, and they can deploy it the same way they deploy any other Java app. They don't have to implement or support some new infrastructure.

JRuby is just Java byte codes under the covers, after all. And when you're delivering a WAR, that's what you're delivering--Java byte codes.

To make that work, you use "GoldSpike"--the tie that binds the rails from east and west, or in this case, Ruby and Java. The process is pretty simple:

  • Install the GoldSpike gem from the jruby-extra site. (See the Resources).

  • Set up a config file with something like the following:

    maven_library, "rome', "rome'. '0.8'
    
Note: Maven is the Apache Build manager and ROME is a set of Java utilities for Atom/RSS feeds. It's not clear from my notes what this step is doing, but I'm leaving it in with the expectation that I'll be able to clarify later.

You then need to set an environment variable:

RAILS_ENV=production rake db:migrate

Next, you issue the Rake command to create the war file:

rake war:standalone:create

That command pulls in the Rails app, along with any gems and java libraries it uses, and puts everything into a single, standalone WAR file that is ready to deploy on your favorite Java application server.

To deploy the WAR yourself, you can issue a command like this one:

~/glassfish/bin/asadmin deploy myapp.war

Why JRuby on Rails?

So, Rails is good framework for web applications. But why run it on JRuby, rather than native ruby?

Possibly the most important reason is so you can deploy your Rails application on a Java Application Server, as noted above. But there are several other reasons for using JRuby, as well:

  • Installation: Windows installations work fine for native Ruby, and Unix installations work well when they go to the expected location. But when I installed Ruby in a non-standard directory on a Solaris system, several build files had to be modified--and additional modifications were needed to enable gems. I got it working, with the help of the many friendly people on the mailing list, but I can't say I fully understand what I did, or could easily replicate the process. Installing JRuby, on the other hand, is a study in simplicity: Download it. Run it. That's all there is to it, as long you have a Java runtime installed somewhere on your system.
  • Localization: JRuby takes advantage of Java's unicode framework for fully localizable applications.
  • Capability: Java has a huge volume of well-documented, tested libraries, and you can access them all from JRuby.
  • Scalability & Reliability: The Java platform's native threads trump Ruby's green threads. And the HotSpot compiler/interpreter gives JRuby a speed advantage that JRuby's developers have taken advantage of. (Those speed advantages apply to all JRuby scripts, in addition to web apps.) JRuby is basically on a par with native Ruby today, but performance has mostly been secondary to compatibility, until now. That is next major focus for the project. And in the future, byte code changes are under development with JSR 292 that will allow for even more significant code optimization.
  • Startup speed for Java programs: When a JRuby script is launching Java apps, there is no start-up overhead, because the virtual machine is already running. That makes JRuby the ideal way to launch and manage Java platform processes--for example, in a Rake build file.

The one item in that list that needs more elaboration is the way you access the Java libraries from JRuby. Here is a quick snapshot of the process, using the example the JRuby developers presented:

jirb>
include Java -- now have access to java libs
import javax.swing.JFrame
import javax.swing.JButton
import java.awt.event.ActionListener
frame = JFrame.new("Quick App")
frame.set_size(300,300)
frame.show
button = JButton.new("Press Me")
frame.add button
class MyListener
include ActionListener
  def actionPerformed(even)
    event.source.text = "Don't press me again."
  end
end
button.add_action_listener MyListener.new
frame.show

Voila! You now have a little GUI app in a few lines of code.

Notes:

  • jirb is the JRuby version of the interactive Ruby interpreter, irb.
  • You can use Java's CamelCase method names, or the Ruby-standard underscore-versions, like button.add_action_listener.

JRuby Futures

JRuby has shown remarkable progress in the last year or so. It has pretty well achieved it's first goal: Full compatibility with the native Ruby implementation. (No mean feat, considering that the only "spec" is embedded in the C-language sources.)

The developers are now closing in on their second major goal: exceptional performance. (On many measures, it is already faster. So now they're zeroing in on the remaining areas that need improvement.)

Their next major targets are to resolve the only remaining areas of incompatibility: Those modules that use native C extensions. Since they're not written in Ruby, the Ruby compiler doesn't help. They have to be rewritten in Java.

One area in which that impact is keenly felt is in database support. MySQL works great, and Derby works ok, along with some other databases, but there are some that do not work at all. Hopefully, the open source community will be able to help with that endeavor.

Beyond that, JRuby's developers intend to focus on the enterprise-edition capabilities that are needed for massively high-performance, high-reliability apps. For example:

  • Database pools
  • Stronger WAR deployment

Finally, they look forward to integrating with more of the native ruby libraries like the Mongrel web server, Hpricot, and Rmagick.

All told, it's a very strong story that figures to get even stronger, with time.

Resources

Articles

Technologies

Talk Back!

Have an opinion? Readers have already posted 10 comments about this weblog entry. Why not add yours?

RSS Feed

If you'd like to be notified whenever Eric Armstrong adds a new entry to his weblog, subscribe to his RSS feed.

About the Blogger

Eric Armstrong has been programming and writing professionally since before there were personal computers. His production experience includes artificial intelligence (AI) programs, system libraries, real-time programs, and business applications in a variety of languages. He works as a writer and software consultant in the San Francisco Bay Area. He wrote The JBuilder2 Bible and authored the Java/XML programming tutorial available at http://java.sun.com. Eric is also involved in efforts to design knowledge-based collaboration systems.

This weblog entry is Copyright © 2007 Eric Armstrong. All rights reserved.

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use