Introduction to Ruby on Rails for Java developers
A couple of weeks ago I talked to a bunch of Java developers at Sogeti about Ruby on Rails. I promised to approximate the talk as a blog post so here it is. (This was due to me mostly using pictures and code in the slides and had not that much text in them. So just passing on the slides wouldn't have helped much. Trying to apply presentation zen whenever possible...) I have only used Rails for a couple of spare time projects so I don't really know all the details. I know enough though to contrast it against enterprise Java. I have worked with Java and J2EE for about 10 years. For many of those years I have had a distinct feeling that we are complicating things all the time. We have the unified process that is supposed to solve all our cases but most of the time obfuscates the real purpose of projects. Documents and methodology become more important than the code that is the system. The technology we pick for our projects - most often J2EE or .net - is most of the time too much for the task at hand. I want you to start questioning these absolutes and start striving for alternative solutions.
public String
did you write the last year? Or public static final int
? And how many of those were really necessary. Java is fine as a programming language but do we really need a strongly typed language all the time? I think not. What is strongly typing really? It is just a way of testing the code to make sure that the developer has made the correct decisions. And the fine thing is that we have to do these tests to even compile the program. Using a strongly typed and compiled language is a kind of test driven development in the small. Now think about a developer that always write nice tests for all his code. Wouldn't those tests cover typing errors regardless of whether the language is typed or not? So if we can guarantee that we always have developers that test an untyped language like Ruby or Smalltalk might be used. Unfortunatley most developers are either lazy, careless or ignorant when it comes to test. More about this later.Another thing I just have to whine about is J2EE. We all know that J2EE solves all problems in the entire universe. Is this a good or a bad thing? It might be a good thing for big systems with many disparate needs. But do we really need all this complexity for the common semi-large system? Probably not. It seems to me that J2EE was manufactured by architects that have a need to point out how extremely complex their work is. And maybe sometimes it is but hardly all the time. Most systems I have worked with have been forced to use a complex solution - "because that's the way we do it in this organization" - where a much simpler solution would have worked just as well and might have resulted in less lines of code and hence less maintenance cost. But instead of whining I will suggest an alternative that makes it more fun to develop. Ruby on Rails. Keep in mind that this is just one of several light weight frameworks that increases productivity and makes it fun to be a developer again. I will comment on several other frameworks towards the end of this post.
I will start with a brief discussion about the language (1) itself and then turn to the framework (2). Code will be used to show the simplicity compared to Java. Then I will tell you how to generate a sample application in just a few minutes (3) and lastly we will look at some tools (4) and take a look at the broader picture (5).
The language
It is important to look into the language when choosing a framework. A less mature language might give you unanticipated problems down the road. Questions to ask regarding this is:
- does the target organization know the language or will it be able to learn?
- is the resulting code easy to maintain?
- is the standard library good enough?
Ruby is a dynamically typed and object oriented language. Everything is an object and the standard library features instance methods all the time instead of the numerous class methods seen in Java. For example - in Java you would get the absolute value of a number by doing:
Math.abs(42);
while in Ruby you go:42.abs
Which one is nicer? I know what I think! In Ruby you could even add your own method to a class in the standard library if you think there is a need for it. So it is a highly dynamic language. This could pose a problem if your developers are the lazy kind that doesn't do testing and doesn't adhere to coding guidelines agreed upon. Since the language is interpreted there is no compiler to catch small errors. With a strongly typed and compiled language there is always a first guard that catches typing errors. If you do test driven though - it shouldn't really make a difference at all. Another example that also illustrates is the following method that adds the items in an array and returns the results. In Java I would do something like:Note that we typically type the content of an array or a list in Java. Now look at the same method written in Ruby:public int sum( int[] a ) { int y = 0; for( i = 0; i < a.length; i++ ) { y = y + a[i]; } return y; }
This method accept any argument that has a method called "each" that can apply a code block to each item. The amount of code that is needed to solve a problem is less than in Java and in my opinion easier to read. It is also more flexible. You only need one method for parameters that has the method "each". In Java you would need an interface. This should mean something for the maintainability of a system.def sum a y = 0 a.each do |x| y = y + x end y end
Downsides of Ruby then? It might look like Perl due to a number of shortcuts that probably should be used sparsely and wisely if at all. It is a rather different looking language compared to C-ish languages. It might be hard to learn for unmotivated programmers. The standard library is not as fully featured as that of Java. If that is a problem - take a look a jruby - ruby that runs on the Java VM.
The framework
There are many kind of frameworks. In Java we often deploy several to solve different problems. We might use a web framework like Struts or JSF for the front end and Hibernate for database connectivity. Spring is a bit unique - it helps us all the way. Ruby on Rails is an MVC web and database framework. In some ways it resembles Struts. Model, controller and view have basically the same responsibilities. It would be possible to bind a Struts model directly to the database in the same way as Rails does. We seldom do it that way and if we did it would surely result in much more code than the equivalent code in Rails. The model in Rails is not defined in terms of classes - instead, database tables defines the model. And Ruby classes without much content are used to bind the database to the code.
In our example we will build a site for web bookmarks. In this section I will walk you through the classes that are involved and in a later section I will show you how to generate these classes on the command line. In this extremely simple example there are 2 fields on a bookmark; a url and a description. The SQL to create a bookmarks table might look something like this:
Nothing fancy there. To access this table from Rails we create a model class called Bookmark that extends ActiveRecord - one of the corner stones of Rails. The code looks like this:CREATE TABLE "bookmarks" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "url" varchar(255), "description" text, "created_at" datetime, "updated_at" datetime);
Yepp - that's right. No code at all. All the magic is dynamically created by the base class ActiveRecord. It makes sure that there are accessors and mutators for the fields and has several nice methods to create, update, find and destroy a database entry. Some examples on how to use this class from a controller:class Bookmark < ActiveRecord::Base end
To create and save a new bookmark:
To create and save a new bookmark getting the data from an HTML form:b = Bookmark.new( :url => “http://www.dn.se”, :description => “en tidning” ) b.save
To find a bookmark with an id:b = Bookmark.new( params[:bookmark] ) b.save
To find all bookmarks:id = 42 Bookmark.find 42
If SQL is needed anyway:Bookmark.find :all
On to controller code. All code needed for a web request is put in the controller class. It is similar to action classes in Struts. An index action that gets all the bookmarks could look like this:Bookmark.find_by_sql “select * from bookmarks”
The code just glues together the model and the view which in this case would look something like this:class BookmarksController < ApplicationController def index @bookmarks = Bookmark.find(:all) end end
<h1>Listing bookmarks</h1> <% for bookmark in @bookmarks %> <table><tbody><tr> <th>Url</th> <th>Description</th> </tr> <tr> <td><%=h bookmark.url %></td> <td><%=h bookmark.description %></td> </tr></tbody></table> <% end %>
This is very similar to JSP. If you really don't like embedded code like this in your web page (you use tag libraries all the time) you should probably look elsewhere. Personally I think Ruby is much better embedded than Java.
Scaffolding
To generate this code (and some more...) you first need to install Rails. (There are one click installers for both Windows and Mac or you can use the nice built-in installer in Ruby called gem. For a working Ruby environment just go gem install rails
.) Then generate a Rails project:
This generates a directory structure with all the defaults of Rails. Go into the generated root directory and then generate code for a bookmark with an url and a description:rails demo
This will generate the code displayed earlier in this post together with some tests. In the directory db/migrate there will be a Ruby script that defines the database. To install the database - run:cd demo script/generate scaffold bookmark url:string description:text
Then start the server withrake db:migrate
script/server
and direct your browser to http://localhost:3000/bookmarks
where you will have a complete admin application for the bookmarks table. Empty tests are generated in
test/integration and test/unit ready to be run with rake test
.
Toolbox
So - are there any tools for this nice framework? I have been using TextMate for editing. It is a multi purpose text editor and works fine most of the time. It lacks code completion and refactoring support. The only IDE that I tried and that seems to work as good as Eclipse or NetBeans for Java is RadRails. NetBeans has support for Rails in its latest version but most of the stuff doesn't work (at least not on MacOS....). It probably will in the future.
The classic way of deploying Rails applications is in Apache with either Mongrel or Lighttpd. Now with jruby it is possible to deploy Rails applications in J2EE app servers like JBoss, WebLogic and WebSphere. This might be a nice alternative when trying to introduce Rails in a J2EE organization. It is just another kind of code running on the same infrastructure.
What about the others?
There are several other ways of building web applications fast. While Rails might be a really good choice for most web applications there might be cases when the J2EE stack adds value somehow. And at the other end there might be even simpler application that is easily built with PHP. Easy and cheap as it is with many ISPs providing PHP support out of the box. PHP has several well supported CMS solutions that are morphing into web framworks. Take a look at Drupal and Joomla. For Python there is Django - similar to Rails but without the database driven model of Rails. For Smalltalk (the coolest language?) users there is Seaside - a very interesting option that takes the concept of Rails one notch further. Read more about the differences here. In the Java world there is Grails - a Rails copy built on Groovy. Other options with different strengths and weaknesses are GWT, Wicket and Struts 2. Even JSF may be an option if you are tying different components together. When choosing a framework - it is important to look at several factors:
- the current knowledge of the organization
- the possibillity of learning in the organization
- maintainability
- productivity
Old comments