Grails vs Rails Performance Benchmarking (Grails.org)

March 31st, 2007

Intro

Recently someone asked the question: “Where are the Grails vs Rails benchmarks??”. Since we actually haven’t got round to optimising Grails I thought it was silly that we should benchmark a 0.4.2 release against Rails which is now at 1.2.x. Nevertheless, to allay concerns about Grails I decided we should do it anyway. This page represents the results.

The reality of this benchmark is that it is actually more like Rails vs Groovy + Spring MVC + Hibernate + Sitemesh. Grails can take some credit of course, but the heavy lifting is being done by Spring & Hibernate in particular.

I am by no means a benchmarking expert, so if you have any changes or recommendations please shout


Update - After feedback from Jared Richardson who detailed how with Rails & Mongrel you actually need multiple Mongrel instances to be equivalent to tomcat I decided to conduct some further tests. This basically showed my naivety when configuring Rails, but there you go, so I apologise for the falseness of the original benchmarks.

To be clear what I have done is do configure Rails with a 10 Mongrel cluster and Pound as per Jared’s tutorial here. To make things fair I also reduced Tomcat to use only 10 Java threads. The results can be seen in the updated benchmarks that follow.

If I have done something wrong in the Rails configuration please point it out, because if you read on, doing the clustering didn’t help much.

Hardware Specs

We are trying to be entirely open about this benchmark. Personally I feel benchmarks are of limited value, but some live by them so there you go. To get some of the details out the way then. The test hardware is as follows:

Apple MacBook
1.83ghz Intel Core Duo
1GB 667 Mhz DDR2 SDRAM

Ok I know, I know it isn’t a server, but I didn’t have one lying around, so this will have to do. It has dual cores after all

Software Specs

Now onto the software platforms:

Grails

  • OS: Mac OS X 10.4.9
  • Server: Apache Tomcat 5.5.20
  • Version: 0.5-SNAPSHOT from 20th of March
  • Environment: Production
  • Database: MySQL 5.0.27
  • Java: Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_07-164)
  • JDBC Driver: mysql-connector-java-3.1.10-bin.jar
    I decided to benchmark with 0.5-SNAPSHOT because it implements the new URL mapping feature and since Rails has routes it evens the playing field out a bit. In other words it would be unfair on Rails if we benchmarked with Grails not having a routing feature, as it does in the upcoming 0.5


Configuration A: Standard Tomcat

The first test was with a standard Apache Tomcat 5.5.20 configuration, with the following settings:

<Connector port=“8080″ maxHttpHeaderSize=“8192″
               maxThreads=“150″ minSpareThreads=“25″ maxSpareThreads=“75″
               enableLookups=“false” redirectPort=“8443″ acceptCount=“100″
               connectionTimeout=“20000″ disableUploadTimeout=“true” />

Configuration B: Tomcat configured with a 10 thread pool

To even things up with Rails having 10 mongrel’s I decided to configure Tomcat with only 10 threads with the following configuration:

<Connector port=“8080″ maxHttpHeaderSize=“8192″
               maxThreads=“10″ minSpareThreads=“1″ maxSpareThreads=“1″
               enableLookups=“false” redirectPort=“8443″ acceptCount=“100″
               connectionTimeout=“20000″ disableUploadTimeout=“true” />

Rails

Set-up according to the article here: http://hivelogic.com/narrative/articles/ruby-rails-mongrel-mysql-osx

  • OS: Mac OS X 10.4.9
  • Server: Mongrel 1.0.1
  • Version 1.2.3
  • Environment: Production (Started with mongrel_rails start -e production)
  • Database: MySQL 5.0.27
  • Other notes: I installed the Ruby MySQL native bindings as per the aforementioned article

So the same database for both and the most commonly deployed container for Grails (there might be faster containers out there, but I’m not here to test containers). As for Rails I have been told by multiple sources that Mongrel is THE container to deploy to for maximum performance, but I’m no expert so please correct me if I’m wrong here.

Also note that I have not bothered to connect Grails or Rails up to Apache using mod_jk or the equivalent Rails FastCGI connector.


Configuration A: A single mongrel instance

The first Rails configuration was using only a single mongrel instance and hitting it directly on port 3000.

Configuration B: 10 mongrels with load balancing by Pound

The second configuration I used a 10 mongrel cluster configured as per Jared Richardson’s instructions here and configured it with this command:

sudo mongrel_rails cluster::configure -e production -p 8001 -N 10

To start-up the cluster I did:

sudo mongrel_rails cluster::start

I then used Pound as a load balancer with the following configuration again setup as per Jared’s instructions:

ListenHTTP
   Address 0.0.0.0
   Port 3000
End

Service
  BackEnd
    Address 127.0.0.1
    Port 8001
  End
  BackEnd
    Address 127.0.0.1
    Port 8002
  End
  .. etc ..
  BackEnd
    Address 127.0.0.1
    Port 8011
  End

Session
Type BASIC
TTL 300
End
End

The Test Applications

Now onto the nature of the tests. So basically I didn’t want to get into anything too fancy, so I’m testing these things:

  1. Read operations
  2. Create operations
  3. Queries
  4. Update operations
  5. View rendering vs. writing directly to the response

I am not going to be testing any really complex operations as the more complex an application is the more it becomes application performance and not framework performance that is being compared. Moving on then I set-up the test with the scaffolding capability of each framework. So with Grails I created a domain class like:

class Book {
	String title
	String author
	String description
	Date  dateCreated = new Date()

	static constraints = {
		title(nullable:false, blank:false)
		author(nullable:false, blank:false)
	}
}


Then ran the following command to generate the base controllers and views:

grails generate-all


Similarly with Rails I created the following table in mysql:

To create this yourself you can do it in MySQL’s tools or by running the DDL:

CREATE TABLE `books`.`books` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `title` VARCHAR( 255 ) NOT NULL,
  `author` VARCHAR( 255 ) NOT NULL,
  `description` TEXT,
  `date_created` TIMESTAMP NOT NULL,
  PRIMARY KEY (`id`)
)
CHARACTER SET utf8;


I then created the following model in Rails:

class Book < ActiveRecord::Base
end


And then ran the command

ruby script/generate scaffold book


The Test Data

With that done, the way I setup some test data was to create an action to do so in each respective controller. In Grails I did this:

def data = {
     def i = 1000
     while( i > 0 ) {
         def book = new Book()
         book.title = “Book ${i}”
         book.author = “Author ${i}”
         book.description = “The description for book ${i}”
         book.save()
         i = i - 1
	 }
     render “Created data!”
	}


In Rails to achieve the same thing I did this:

def data
   i = 1000
   while i > 0
       @book = Book.new
       @book.title = “Book #{i}”
       @book.author = “Author #{i}”
       @book.description = “The description for book #{i}”
       @book.save
       i = i - 1
   end
   render :text => “Created data!”
end


Sending a request to each action created the data. Job done. Now we have some test data and the respective list views of each app look like this:

If you want to download the full test applications they can be downloaded from here:

Test Tools

To perform the tests I used ApacheBench which is available with the “ab” command on Mac OS X. Just for clarity here is the version info

This is ApacheBench, Version 1.3d <$Revision: 1.73 $> apache-1.3
Copyright (c) 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Copyright (c) 1998-2002 The Apache Software Foundation, http://www.apache.org/

The results have then been graphed up using Apple Pages. The full PDF can be download here

Test A: Read Performance

So after creating the test data we now have 1000 records in each applications respective database. Just to be clear the code that renders the above view is the standard scaffolded list view for both apps with the server side code in Grails being:

def list = {
    if(!params.max)params.max = 10
    [ bookList: Book.list( params ) ]
}


And in Rails:

def list
  @book_pages, @books = paginate :books, :per_page => 10
end


To run the read performance test I executed the commands:

// for rails
ab -c 50 -n 1000 -e “rails_list_test.csv” http://localhost:3000/books/list

// for grails
ab -c 50 -n 1000 -e “grails_list_test.csv” http://localhost:8080/books/book/list


Obviously not at the same time!
So what this does is send 1000 requests to the respective servers with 50 concurrency. I made sure all other applications were closed to make sure the figures were as accurate as possible. The results of the read test are below:


Grails is able to handle 40 requests per second to Rails 32. Significantly you can notice Grails has a much poorer worst case response time, but a superior mean response time (The mean time is the average time taken per request over all 1000 requests). This can be put down the Java threading model and the Thread pool in Tomcat at some point running out of available threads and blocking for a moment. It just reflects the differences in architecture more than anything else. If you ran the same test against Grails with a concurrency of 1 you would see linear performance as expected:

ab -c 1 -n 1000 -e “grails_list_test.csv” http://localhost:8080/books/book/list


Interestingly, Grails with only 10 threads is even more performant and is able to cope with 54 requests per second. We also see that the spikes in the max response time are gone with a configuration for less threads. If you think about it this makes sense given the hardware I’m testing on. I only have dual cores on this Macbook, so the more threads there are the more processes have to share the two cores and hence the overall performance degrades with more threads. If I was running a machine with 8 processors then having more threads would obviously be more beneficial.

Rails on the other hand with 10 mongrels and Pound degrades in performance. I guess this is down to more processes having to share the two cores, but if someone can explain if I’ve done anything wrong in the config please say so

Test B: Creating Records

The next test was to test creating new records. In this case I used a simple action for both. The Rails code is:

def createTest
   i = 5
   while i > 0
       @book = Book.new
       @book.title = “Book #{i}”
       @book.author = “Author #{i}”
       @book.description = “The description for book #{i}”
       @book.save
       i = i - 1
   end
   render :text => “Created 5 records data!”
end


As you can see it just creates 5 records in a loop and then renders some text to the response. No view involved. The Grails code for this is:

def createTest = {
 def i = 5
 while( i > 0 ) {
     def book = new Book()
     book.title = “Book ${i}”
     book.author = “Author ${i}”
     book.description = “The description for book ${i}”
     book.save()
     i = i - 1
 }
 render “Created 5 records data!”
}


To run the create performance test I executed the following ab commands framework:

// for rails
ab -c 50 -n 1000 -e “rails_create_test.csv” http://localhost:3000/books/createTest

// for grails
ab -c 50 -n 1000 -e “grails_create_test.csv” http://localhost:8080/books/book/createTest


Again with a 1000 requests, and 50 concurrency. The results are as follows:


The differences here are quite astounding, Grails is able to cope with 140 requests per second and has a mean average of 345ms per request compared to Rails’ 35 (and a half) and 1.3 seconds per request. I believe, without having done any real profiling, the reasons for this can largely put down to Hibernate’s session-based model. Each call to save() in ActiveRecord immediately persists the data whilst Hibernate batches updates up until the end.

Again Grails with only 10 threads is faster, whilst Rails with 10 mongrels degrades performance.

Test C: Querying

The next test tackled querying using a like query. The bottleneck here is likely to be MySQL’s query performance. The code for this test for Rails is as follows:

def queryTest
    @books = Book.find(:all, :conditions => [“title like ?”, “Book 6%”])
end


The view used is the same as the default list view just cloned and renamed to queryTest.rhtml. For Grails the same thing is done:

def queryTest = {
   [bookList:Book.findAllByTitleLike(“Book 6%”)]
}


There is no equivalent to Rails’ :conditions element in Grails so we use a finder expression. Again to execute this test we use similar commands:

// for rails
ab -c 50 -n 1000 -e “rails_query_test.csv” http://localhost:3000/books/queryTest

// for grails
ab -c 50 -n 1000 -e “grails_query_test.csv” http://localhost:8080/books/book/queryTest


The results for this test can be seen below:


As you can see the results here are much more equal as it is really reliant on database performance. Notably we can see Grails’ worst case is poor down to blocking in the thread pool, but overall the mean time of 5.387ms is superior to Rails’ 6.386, which illustrates why Grails’ is able to deal with 8.92 requests per second as oppose to Rails’ 7.65.

Neither framework comes off particularly well here, but in reality if you had this kind of load for queries you would need consider using some sort of caching and/or indexing solution (lucene/ferret).

This is the one test though, where Rails with 10 mongrels gets close to matching the default Grails tomcat configuration and where Grails with 10 threads is slower than the default tomcat config.

Test D: Updating record and rendering a view

For this test we’re trying out updating and then rendering a view. To do so we’re going to retrieve some random records from the database and update each and then store the value. To achieve this in Rails we do:

def updateTest
   count = Book.count
   ids = [rand(count),rand(count),rand(count)]
   @books = []
   ids.each { |id|
     book = Book.find(id)

     if book
        book.author = “Fred Flintstone #{Time.new}”
        book.save
        @books << book
     end
   }
end


To explain this logic we basically create 3 random ids from the total, retrieve them from the database, update the author field and then save. And before you ask I definitely checked that the databases of both were dropped and re-created with fresh test data with the ids on the tables indexing from 1-1000. The view for this action is again copied from the list view and renamed to updateTest.rhtml.

For Grails to achieve the same thing we do:

static final rand = new Random()
def updateTest = {
	def count = Book.count()

	def ids = [rand.nextInt(count), rand.nextInt(count),rand.nextInt(count)]
	def result = []
	ids.each { id ->
		def book = Book.get(id.toLong())
		if(book) {
			book.author = “Fred Flintstone ${new Date()}”
			book.save()
			result << book
		}
	}
	[bookList:result]
}


Again the same logic, instead of the C rand(num) function in Ruby we use Java’s java.util.Random class and calculate a bunch of ids, iterate over each, saving each one to formulate the results.

Again to execute this test we use similar commands:

// for rails
ab -c 50 -n 1000 -e “rails_update_test.csv” http://localhost:3000/books/updateTest

// for grails
ab -c 50 -n 1000 -e “grails_update_test.csv” http://localhost:8080/books/book/updateTest


The outcome of this test can be seen below:


Once again we see a similar graph, Grails having the higher max, but a superior mean average response time. Grails is able to deal with 44.95 requests per second to Rails’ 30.88. This can be put down to a number of things, again I believe it is the difference between Hibernate’s session based approach and ActiveRecord.

Another thing to note is during the Grails test 2 Hibernate StaleObjectExceptions were thrown because Grails uses Hibernate’s optimistic locking feature, which ActiveRecord doesn’t seem to have any concept of (correct me if I’m wrong). In a real circumstance when dealing with high concurrency you would of course catch this exception in Grails, which would actually be a Spring HibernateOptimisticLockingFailureException and deal with it appropriately by getting fresh data or returning an error (the default case).

Again similar to the first two tests, we see Grails with only 10 threads being even more performant and Rails with 10 mongrels degrading.

Test E: Updating 3 random records and return idiomatic XML

So after the above result I wanted to see what the performance would be like when not using a view (RHTML or GSP). So instead we return some XML. In rails the code for this is:

def updateTest2
   count = Book.count
   ids = [rand(count),rand(count),rand(count)]
   @books = []
   ids.each { |id|
     book = Book.find(id)

     if book
        book.author = “Fred Flintstone #{Time.new}”
        book.save
        @books << book
     end
   }
   render_text @books.to_xml
end


Note here we call to to_xml method to auto-convert to XML which is a nice feature. The resulting XML looks something like:

<?xml version=“1.0″ encoding=“UTF-8″?>
<books>
  <book>
    <author>Fred Flintstone Thu Mar 22 15:35:54 +0000 2007</author>
    <date-created type=“timestamp”>Thu Mar 22 12:20:21 +0000 2007</date-created>
    <description>The description for book 3</description>
    <id type=“integer”>5908</id>
    <title>Book 3</title>

  </book></books>


To do the same thing in Grails requires a little more code as Grails doesn’t have a toXML() yet (actually it does, but it is currently in the REST plug-in, see http://grails.org/Plugins). So instead of toXML() we use Groovy mark-up building:

def updateTest2 = {
	def count = Book.count()

	def ids = [rand.nextInt(count), rand.nextInt(count),rand.nextInt(count)]
	def result = []
	render(contentType:“text/xml”) {
		books {
			for( ident in ids ) {
				def b = Book.get(ident.toLong())
				if(b) {
					b.author = “Fred Flintstone ${new Date()}”
					b.save()
                    book {
                    	author(b.author)
               			‘date-created’(b.dateCreated)
               			‘description’(b.description)
						id(b.id)
						title(b.title)
					}
				}
			}
		}
	}
}


The result of the two methods is exactly the same XML (changing data of course). Now for running the tests, again the same commands:

// for rails
ab -c 50 -n 1000 -e “rails_update_test2.csv” http://localhost:3000/books/updateTest2

// for grails
ab -c 50 -n 1000 -e “grails_update_test2.csv” http://localhost:8080/books/book/updateTest2


And the result is:


So that is pretty similar to the first update test. Again Grails is around 40-50% faster. Now there is a lot of dynamic stuff going on when producing the XML from these two actions so I thought I would have a go at building up a String and writing it to the response.

Again similar to the first two tests, we see Grails with only 10 threads being even more performant and Rails with 10 mongrels degrading.

Test F: Updating 3 random records and returning a String generated response

This test actually is more a like for like as we don’t have to deal with the differences between to_xml in Rails and mark-up building in Grails. The Rails code for this is:

def updateTest3
  count = Book.count
   ids = [rand(count),rand(count),rand(count)]
   xml = “<books>”
   ids.each { |id|
     book = Book.find(id)

     if book
       xml << “<book>”

        book.author = “Fred Flintstone #{Time.new}”
        book.save
          xml << “<author>#{book.author}</author>”
          xml << “<date-created>#{book.date_created}</date-created>”
          xml << “<description>#{book.description}</description>”
          xml << “<id>#{book.id}</id>”
          xml << “<title>#{book.title}</title>”
       xml << “</book>”
     end
   }
   xml << “</books>”
   render_text xml
end


The XML that is produced is exactly the same as in the previous test, except constructed manually from a String. The equivalent Grails code looks like:

def updateTest3 = {
	def count = Book.count()

	def ids = [rand.nextInt(count), rand.nextInt(count),rand.nextInt(count)]

	def xml = new StringBuffer(“<books>”)
	ids.each { id ->
		def b = Book.get(id.toLong())
		if(b) {
			b.author = “Fred Flintstone ${new Date()}”
			b.save()
               xml << “<book>”
               	 xml << “<author>${b.author}</author>”
				 xml << “<date-created>${b.dateCreated}</date-created>”
             	 xml << “<description>${b.description}</description>”
             	 xml << “<id>${b.id}</id>”
             	 xml << “<title>${b.title}</title>”
			   xml << “</book>”
		}
	}
	xml << “</books>”
	render xml.toString()
}


Again it uses the static java.util.Random instance and constructs the String from a StringBuffer. Now we execute the commands:

// for rails
ab -c 50 -n 1000 -e “rails_update_test3.csv” http://localhost:3000/books/updateTest3

// for grails
ab -c 50 -n 1000 -e “grails_update_test3.csv” http://localhost:8080/books/book/updateTest3


Again with a 1000 requests, and 50 concurrency. The results are as follows:


Grails in this case is able to process nearly 3 times as many requests as Rails per second. So why are the first 2 update tests so much slower for Grails (although still faster than Rails?). Well what these tests have helped us identify is that with a large amount of load Groovy Server Pages, Grails’ view technology, certainly needs some improvement.

And again similar to the first two tests, we see Grails with only 10 threads being even more performant and Rails with 10 mongrels degrading.

The way GSP works internally with tag libraries is that it uses try/catch blocks to intercept exceptions thrown by Groovy when it doesn’t find a method. These are of course expensive as the JVM has to take a snapshot of the exception when it is thrown which causes all threads to freeze momentarily. So one area where we can improve Grails’ performance is to look at tweaking GSP to not do this (there are other techniques for doing this).

So why does this effect the second example? Groovy’s streaming markup builder is using the same technique!

Summary

Overall, as expected, given its base on solid Java technologies, Grails out performs Rails (100% Ruby) in pretty much every test. As I said at the start I’m no Rails performance tuning wizard, so if someone can suggest ways to get Rails to perform better please say so. We are conducting these tests purely to inform concerned Grails users who are asking for figures, and hope to review them as Grails progresses.

Interestingly, Grails, at least on this machine, sees performance increases when lowering the thread pool to 10, whilst Rails suffers when 10 mongrels are configured with Pound.

Grails hasn’t undergone much optimisation at all yet and there are certainly areas we can improve on, GSP rendering being one. GSP is of course a much more complex view rendering technology in comparison to RHTML due to its support for dynamic tag libraries, plus Sitemesh decoration. However, there are definitely areas in GSP, such as the way it uses exceptions, that can be improved upon.

Another point to remember is performance != scalability. The way you would scale an application to deal with the kind of load we have here differs greatly between Grails & Rails I imagine. With Grails you could stick a Terracotta or Coherence distributed cache on the back of it to implement SSI (singe system image) or use HTTP session replication across a cluster whilst with Rails you could ??? (a Rails user please feel free to provide an answer to this question in the comments, I’m not qualified to answer).

Nevertheless, I am quite satisfied that Grails performs sufficiently well to be competitive and there is little point in optimising prematurely. Our main goals is to focus on getting 1.0 out towards the middle of this year.

Resources

Grails.org

Tags:

Grails vs Rails performance (Refactr)

March 23rd, 2007

Graeme has taken the time to respond to some of the comments floating about in the blogosphere about the performance of Grails vs Rails. This benchmarking comes out very favorably for Grails. In nearly every case, the requests per second and mean response time come out with Grails performing better than Rails. And in some cases, Grails literally blows Rails away (140 vs 35.5 requests/sec on the create test!!). The max response time for Grails is higher in nearly every test case, but this is completely understandable as Graeme points out. I also wonder if he took note of the fact that Grails is always going to be slower for the first hit, but over time will speed up due to the nature of the JVM.

It’s important to keep in mind that Grails has yet to be optimized much (or at all), whereas Rails has been around longer and has been optimized much more. This is the part that makes me feel the best, actually, because it means that there are probably a lot of places where relatively simple changes can improve the performance of a Grails app significantly. Add to that the fact that in Grails you can always drop down and write native Java to increase efficiency (vs. having to write C in Ruby/Rails) and I think it’s clear that Grails is at the very least on par with Rails and likely has even better performance characteristics.

Refactr

Tags:

Where are all the Groovy (and/or Grails) benchmarks? (Thoughtmining)

March 19th, 2007

Ok, I’ve been dipping my toe into Groovy for the past week or so, including some Grails thrown in for good measure. I like what I see. In a previous life, I was a long-time Java developer, and even after a shift to management almost four years ago, I still code on an almost daily basis.

I’ve been searching for awhile now for a dynamic language to use as our “standard” in-house “scripting” tool. We’ve too many perls, pythons, bashes, and more running amok on various boxes and projects across our enterprise. In the last two years, I’ve become quite enamored with Ruby — both with Rails and down at my Linux command prompt, where it finally gave Perl the “don’t have to go home but you can’t code here” hint — but I’ve missed some of the libraries I’d taken for granted in the Java world.

And, for what we do, integration with Java is highly desirable. In my mind (and for the feature set I desire) this points to two possibilities: JRuby and Groovy.

JRuby is very nice. It has my nice comfortable Ruby syntax, open classes, and more. But two things trouble me currently:

  1. Java integration isn’t fully there. You can write Ruby classes that call Java classes, BUT, you can’t develop classes in Ruby and then make use of them from Java as if they were “real” java classes. The JRuby guys are moving in this direction, but it’s not there yet.
  2. While others in our group really like Ruby, a few, especially the more junior guys, are still getting their heads around some of the more interesting (read painful) nuances of our architecture and J2EE technology in general. If I forced Ruby upon them now, they’d probably walk (albeit missing a great opportunity).

Enter Groovy. I’ve eyed it on more than one occasion, but it wasn’t until I picked up a copy of GinA a few weeks ago that I finally gave it a shot. And it’s nice! Many parts feel as if they come directly from Ruby, so much so that it’s not a stretch to pick up very quickly. It also provides the Holy Grail of Java integration: Java->Groovy->Java call capabilities….in other words, your Java can call your Groovy can call your Java. That’s extremely cool, and creates a whole new realm of possibilities for a Java shop like ours. Throw in syntax that is welcoming to a Java developer and compilation to byte code, and the case for Groovy is a strong one!

So, being the good PHB^H^H^H CIO that I am, I began the due diligence process. What due diligence, you ask? When looking at technology that could become a significant part of our development environment, I, as a PHB, look for general indicators that give warm fuzzy feelings (while in reality, could mean nothing):

  1. Review of the architecture and design decisions made by the developers.
  2. Size, responsiveness and general attitude of the community, particularly on the mailing lists.
  3. Current buzz surround the technology on blogs, tech pubs, etc.
  4. Benchmarks comparing the technology to other competing options.
  5. Commercial uptake.

I’ll leave the reasoning behind these questions for another discussion, but over the years I found that (right or wrong) they’ve served me well in assessing new tools or frameworks.

Groovy (and Grails, to a certain extent) scores well on 1, 2, and 3 above. I like the technology so far, and from what I understand of the overall design it is very well thought out. The community is very welcoming, and the lists have been extremely helpful. There is quite a bit of effort to market Groovy and Grails, and with the release of GinA, seems like there is a new article daily.

However, when I went after 4 and 5, I was surprised. Regarding 4: I can’t find a SINGLE benchmark comparing Groovy to competing technologies on the JVM (JRuby, Beanshell, Jython) or dynamic languages in general (Ruby, Python, Perl, and so on). Nor can I find any benchmarks concerning how Grails stacks up to JRuby on Rails, Ruby on Rails, vanilla Hibernate/Spring (something Grails uses under the covers), etc.

Surely, a technology that’s got 1, 2, and 3 down has had someone do this sort of research?!? Surely someone close to the respective projects has asked these hard questions of themselves?

Because I know the previous paragraph has to, has to, be true, then I can only assume one thing: someone has done this as an exercise…and the results were depressing. Why else would the results not be published? If Groovy or Grails was faster, even slightly so, then you can bet it would trumpeted far and wide. The fact that it’s not leaves an unsettling feeling.

I’ve asked the questions on the mailing lists, and I’ve only gotten vague wishful answers, to the tune of “well, we use Java (Spring/Hibernate) under the covers, so we’ve got to be as fast or faster”. Really? Then where are the numbers? Why this gap?

I think it would behoove the Groovy guys (and Grails guys as well) to put some of this research in the public eye. I don’t necessarily care that it’s slower…I just want to know how it compares. It doesn’t rule it out in any way regarding whether we use it or not…it only lets us know where we stand. It gives warm management fuzzies.

So I’m now working on my own benchmarks, but given time limitations it’ll be rough. Don’t hold it against me…after all, I’m just a PHB. I will definitely post the results here when I have them. Anyone with suggestions on the best way to approach this sort of benchmark, please let me know.

Regarding commercial uptake, or number 5 above, the explanations that are offered regarding this in both camps is that many big companies are using Groovy and Grails, but because of competitive advantage they won’t allow themselves to be revealed. That’s a hard point to prove or disprove, but it would help if there were at least a few successful products out there constructed in Groovy or Grails. In the Ruby on Rails world, it seems there are more than a few companies very willing to divulge that they use Rails…no doubt to ride the Rails marketing machine’s coat tails. Why should we accept that, given significant adoption, the adverse would be true for Groovy/Grails?

So, there you have it. It is not my intent to offend anyone in the Groovy or Grails communities…as I said, you’ve been great so far. I’m only trying to give you the perspective of one decision maker, in one company, who is taking a hard look at your projects and assessing the viability of adoption. I really like what you guys are doing, but I need your help in understanding how well it’s working. I’m sure others do as well.

Thoughtmining

Tags:

Ruby on Grails? Why The Hell Not?

, March 10th, 2007

I’ve spent some time this weekend looking over the Grails codebase. After a truly gigantic checkout (Grails bundles production JARs for all the libraries it integrates) and after swimming through a substantial, single-project sea of source files, I think I’m starting to follow it (though a tour by someone familiar with Grails internals would be nice). But there’s something else I’ve learned in the process…

There’s really no reason this couldn’t use Ruby just as easily as Groovy.

Let’s look at some really dumb numbers. Grails, as it turns out, is actually over 2/3 Java code, unlike Rails which is 100% Ruby. Grails contains around 436 Java source files for about 54kloc of code and 273 Groovy source files for about 23kloc of code. So Java outnumbers Groovy by a 2:1 ratio. And yes, Java’s probably more verbose than Groovy in most cases. But my point stands, and I’ll back it up with more…

Then there’s the libraries. The Grails binary release weighs in at a whopping 26MB compressed and 49MB uncompressed (*wow*). But 31MB of that is third-party libraries completely independent of Groovy, things like Hibernate, XFire, Quartz, Apache Commons, and so on. Almost all of which (or perhaps all of which) are pure Java code. So the ratio is even more heavily toward Java.

These numbers and my exploration of the code base lead me to a surprising conclusion: Grails is not a “Groovy on Rails” by any means. It’s a large number of popular, well-established Java libraries stitched together mostly by Java code with a thin layer at the front (20kloc is not much) of Groovy code for end-users to see and work with. And I guarantee you it’s not the Groovy part that’s most interesting here. Hell, you could write that part in Java if you followed enough “convention over configuration”, and you certainly could write it in Ruby.

I decided to do this exploration after realizing there’s nothing about Ruby or JRuby that couldn’t be used to wire a bunch of Java libraries together–indeed, that’s one of the biggest selling points of JRuby, the fact that you can write plain old Ruby code but call Java libraries almost seamlessly (with day-by-day improving integration points and performance numbers). So why not take Grails and do a port to Ruby? Groovy code isn’t far off from Ruby in many ways, and everything you can do in Groovy you can do in Ruby (plus more), so the port should be pretty straightforward, right?

Then I find out that Grails is mostly Java code. And instead of being annoyed or repulsed by this revelation, I was intrigued. Why not make Grails work with Ruby as well? And really, why not make it work with any scripting language? Why limit that nicely-integrated back end by forcing everyone to use Groovy, regardless of preference? Have we learned nothing from a decade of “100% Pure Java”?

So I propose the following.

  • I believe it would be possible to completely isolate Grails’ tastier bits from Groovy. I don’t claim it would be easy, but Grails is fairly well interfacified, injectificated, and abstractilicious, so making that dividing line clear and bold is certainly possible (and heck, that’s the point of dependency injection and component frameworks anyway, isn’t it?). Really, I could start implementing a few of those interfaces right now with Ruby code, but that’s not the right approach.
  • Grails’ value is not in Groovy, but in the clean integration of established libraries behind the “Convention Over Configuration” mantra. There’s nothing specifically Groovy (or Ruby) about that religion, and there’s nothing Groovy does in Grails that another JVM language couldn’t do just as easily. This is *truth*. And Grails would benefit tremendously by expanding to other languages. Being tied to Groovy alone will hold it back (just as a framework tied to any one language will be held back, Ruby included).
  • I also believe that if the Grails project doesn’t make an official effort in this direction, others are likely to take up that mantle themselves. Though the debates will forever rage about which JVM dynlang should carry us into the future, the same facts that have guided programming for half a century still apply today: No one language will be enough to carry us forward; no languages will survive indefinitely; and the language you’ll use in ten years you’ve probably not even heard of yet. Did anyone expect Java to be the most widely-used, widely-deployed language ten years ago? Well today, it is. It won’t always be.
  • There’s also a very interesting angle here for language enthusiasts. Nobody doubts that the Java platform is officially becoming multi-lingual, possibly a complete reversal from years past. But there are going to be growing pains here, and we’re already feeling them on some projects at Sun. We have this wonderful platform with all these wonderful languages…and they all do things differently. We have a first stab at official “Scripting” support in JSR-223, but it only defines the integration point from Java to the language in question…only partially defining the integration points for those languages calling back to Java (a tricky problem) and defining *nothing* related to making those languages interoperate with each other. Again, Java becomes the integration point, and the bottleneck (as in “how do you pass a dynamic-typed object from one language to another by sending it through a statically typed language?”). The very exercise of making Grails (or any other framework) work equally well across multiple user-facing language interfaces will require better interoperability and more clearly-defined integration points for dynamic and static languages on the JVM.
  • The Phobos guys at Sun are already tackling many of these same problems while expanding their JavaScript-mostly Rails-inspired web framework to other JSR-223 languages (notably, Ruby). So anyone taking on the Grails effort would certainly not be alone, and there are some damn smart engineers at Sun interested in tackling these very same problems.

And I guess in the end it’s a question of how visionary we all can be. Can the Grails team envision a future for Grails that doesn’t require the use of Groovy? Are you (and am I) as a non-Groovy developer willing to help them get there? And in the end, isn’t this what thought leaders on a multi-lingual platform are supposed to be doing?

So, enough of the inflammatory bull-baiting. I dare you to tell me why I’m wrong here. Even better, I dare you to look into it yourself. 75kloc of code, only a third of it Groovy. Established libraries you’re sure to have used at some point. Clean integration, following the principals inspired and proven by Rails.

But fronted with your language of choice.

Make it so.

Charles Nutter (Charles is one of the core developers of JRuby)

Tags: ,