Posts Tagged ‘scripting’
Jruby vs. Groovy For Administrative Scripting
Update (8/8/09): When I was originally comparing Jruby & Groovy, I was under the impression that Jruby was a beta-quality product, and its cryptic error messages seemed to prove this point. After a bit more research, I learned that Jruby is a robust and high-quality Ruby implementation and that all dynamic languages can give you cryptic errors on occasion. Many thanks to the knowledgeable Jruby and Groovy developers who set me straight.
Background
I’m a middleware systems administrator for a living, and I often find that I need to write a script that has to interact with proprietary Java libraries. In the past, this meant writing a small Java program that would use the proprietary libraries, and then wrapping that program in a small shell script. This process was OK, but it did have its warts. For example, Java is a fairly verbose language. Going through all of the syntactic hoops just to write a simple program can be tedious.
A little over a year ago, I then discovered Groovy and Jruby. Both languages were very elegant, and I could see how they could both boost my scripting productivity dramatically. I therefore compared both languages for my scripting tasks, and, in the end, I determined that Groovy was just a better language. Here’s part of my rationale:
- A More Stable Interpreter – Jruby would often give extremely cryptic errors when you made a mistake, while Groovy did a much better job of pointing out any problems.
- A Compiler – At the time, Groovy had a compiler (groovyc) that use could use to compile your scripts into bytecode. This tool made it much easier for me to deploy Groovy code in my environment. Jruby has since introduced a similar tool, but it didn’t exist during my initial evaluation.
Now I’m on a new project, and we need to write a bunch of administrative scripts in a hurry. We have the same requirements as my old project, but just before I could dive into my Groovy interpreter, I found out that a lot of the Java developers on my team were ga-ga for Ruby. I therefore decided that it would be nice to evaluate both languages again, one year later. If Jruby is nearly as stable as Groovy for my needs, then it might be a good idea to start writing my scripts with it.
Evaluation
Before I could start my evaluation, I thought it might be a good idea to re-acquaint myself with Ruby. I read “Everyday Scripting With Ruby” a little over six months ago and thought that it was an excellent tutorial on both Ruby and agile scripting. I therefore decided to try running some of the examples in that book with Jruby to bring myself back up-to-speed.
In “Everyday Scripting With Ruby”, the first chapter encourages you to enter invalid code into irb, which is the Ruby interactive interpreter. This exercise shows you how to read the error messages returned by irb. Here’s the line of code:
100 -= 43
And here’s what the latest-and-greatest (1.1.5) version of jirb (Jruby’s version of irb) returns when you enter that:
irb(main):001:0> 100 -= 43
SyntaxError: (irb):2: , unexpected tOP_ASGN
from E:/apps/jruby-1.1.5/lib/ruby/1.8/irb/workspace.rb:81:in `irb_binding'
from E:/apps/jruby-1.1.5/lib/ruby/1.8/irb/workspace.rb:53:in `eval'
from E:/apps/jruby-1.1.5/lib/ruby/1.8/irb/workspace.rb:81:in `evaluate'
from E:/apps/jruby-1.1.5/lib/ruby/1.8/irb/context.rb:219:in `evaluate'
from E:/apps/jruby-1.1.5/lib/ruby/1.8/irb.rb:150:in `eval_input'
from E:/apps/jruby-1.1.5/lib/ruby/1.8/irb.rb:259:in `signal_status'
from E:/apps/jruby-1.1.5/lib/ruby/1.8/irb.rb:147:in `eval_input'
from E:/apps/jruby-1.1.5/lib/ruby/1.8/irb/ruby-lex.rb:244:in `each_top_level_statement'
from E:/apps/jruby-1.1.5/lib/ruby/1.8/irb/ruby-lex.rb:230:in `loop'
from E:/apps/jruby-1.1.5/lib/ruby/1.8/irb/ruby-lex.rb:230:in `each_top_level_statement'
from E:/apps/jruby-1.1.5/lib/ruby/1.8/irb/ruby-lex.rb:229:in `catch'
from E:/apps/jruby-1.1.5/lib/ruby/1.8/irb/ruby-lex.rb:229:in `each_top_level_statement'
from E:/apps/jruby-1.1.5/lib/ruby/1.8/irb.rb:146:in `eval_input'
from E:/apps/jruby-1.1.5/lib/ruby/1.8/irb.rb:70:in `start'
from E:/apps/jruby-1.1.5/lib/ruby/1.8/irb.rb:69:in `catch'
from E:/apps/jruby-1.1.5/lib/ruby/1.8/irb.rb:69:in `start'
from E:\apps\jruby-1.1.5\bin\jirb:19Maybe IRB bug!!
Yikes. I’ve been reading Java stack traces for seven years, but I really have no idea what this error message is telling me. If I honestly thought that line of code should work, or was tired and trying to meet a deadline, this stack trace would be anything but helpful to me.
Just to compare things a bit, I tried to same line of code in the 1.5.6 version of groovysh, which is the interactive interpreter for Groovy:
groovy:000> 100 -= 43 ERROR org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed, groovysh_evaluate: 2: [100] is a constant expression, but it should be a variable expression at line: 2 column: 5. File: groovysh_evaluate @ line 2, column 5. 1 error
Ok, still a little confusing, but much easier to follow. Basically, it’s telling me that “100″ should be a variable of some type instead of a literal. That makes sense.
I thought this might be an anomaly, and I wanted to give Jruby another shot, so I tried executing the next “broken” line of code from the book in both jirb and groovysh:
(1 + 3) * 2 + 1)
First, let’s try it in Jruby:
irb(main):002:0> (1 + 3) * 2 + 1)
SyntaxError: (irb):3: , unexpected tRPAREN
from E:/apps/jruby-1.1.5/lib/ruby/1.8/irb/workspace.rb:81:in `irb_binding'
from E:/apps/jruby-1.1.5/lib/ruby/1.8/irb/workspace.rb:53:in `eval'
from E:/apps/jruby-1.1.5/lib/ruby/1.8/irb/workspace.rb:81:in `evaluate'
from E:/apps/jruby-1.1.5/lib/ruby/1.8/irb/context.rb:219:in `evaluate'
from E:/apps/jruby-1.1.5/lib/ruby/1.8/irb.rb:150:in `eval_input'
from E:/apps/jruby-1.1.5/lib/ruby/1.8/irb.rb:259:in `signal_status'
from E:/apps/jruby-1.1.5/lib/ruby/1.8/irb.rb:147:in `eval_input'
from E:/apps/jruby-1.1.5/lib/ruby/1.8/irb/ruby-lex.rb:244:in `each_top_level_statement'
from E:/apps/jruby-1.1.5/lib/ruby/1.8/irb/ruby-lex.rb:230:in `loop'
from E:/apps/jruby-1.1.5/lib/ruby/1.8/irb/ruby-lex.rb:230:in `each_top_level_statement'
from E:/apps/jruby-1.1.5/lib/ruby/1.8/irb/ruby-lex.rb:229:in `catch'
from E:/apps/jruby-1.1.5/lib/ruby/1.8/irb/ruby-lex.rb:229:in `each_top_level_statement'
from E:/apps/jruby-1.1.5/lib/ruby/1.8/irb.rb:146:in `eval_input'
from E:/apps/jruby-1.1.5/lib/ruby/1.8/irb.rb:70:in `start'
from E:/apps/jruby-1.1.5/lib/ruby/1.8/irb.rb:69:in `catch'
from E:/apps/jruby-1.1.5/lib/ruby/1.8/irb.rb:69:in `start'
from E:\apps\jruby-1.1.5\bin\jirb:19Maybe IRB bug!!
Ok, again, this is complete giberish. What the heck’s a tRPAREN? Ok, now let’s try it using groovysh:
groovy:000> (1 + 3) * 2 + 1)
ERROR org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed,
groovysh_parse: 1: unexpected token: ) @ line 1, column 16.
(1 + 3) * 2 + 1)
^
Ok, this is exactly what I hoped to see. A nice, clear message telling me what I forgot and what it is associated with.
Shortest. Evaluation. Ever
You may not be saying that this is a weird way to evaluate a language. Well, it wasn’t my plan to evaluate Jruby by looking at its error messages, but it was all that I guess I needed. Here’s why error message quality is important to me:
- Based on my experiences with numerous up-and-coming scripting languages, the quality of the error messages is proportional to the quality of the interpreter. If this assumption is true in this case, then the Groovy interpreter still appears to be more mature than the Jruby interpreter.
- Other programmers won’t know what to do when they see one of the Jruby stack traces. Even if I was able to train myself to read the Jruby stack traces, I doubt that my co-workers would have the time or inclination to follow suit.
So, once again, when it comes to my unusual needs, Groovy wins the battle of stability and ease-of-use. Before I end this post, however, I would like to say a few good things about Jruby so that I don’t appear to be partisan:
- I’m really happy that Jruby finally has a tool that will compile your .rb files into .class files. This will make it much easier for me to deploy Jruby applications in my environment some day.
- Jruby seems to be improving at a rapid pace, and it has a lot of support from companies such as Sun. I think that it will be stable enough for my needs within a year or so.
My First Non-Trivial Groovy App
I am about to finish my first non-trivial application written in Groovy (a medium-sized suite of administrative scripts), and so far I’m pretty happy with the language. I thought I would share some of my notes in case anyone else is considering the language for a similar application.
Development Environment
One nice thing about Groovy is how well it works with a system administrator’s “toolbox” of applications, i.e. a text editor and command shell. The development tools that I specifically used were Vim, the command shell, and ant, and I found the pace of development to be very rapid.
References
Since Groovy is still pretty new for me, I need to read a lot of reference material. Here’s the resources that provided the most value:
- Groovy In Action – From my own experiences and what I’ve read on the groovy-user mailing list, GINA is the best Groovy reference manual available. For me, it answered about 95% of my programming questions, with tons of great examples to boot.
Note: This book is a little expensive, so I purchased the electronic version from the Manning web site. If you’re going to be doing most of you reading on a computer screen anyways, I recommend this option.
- PLEAC-Groovy – The PLEAC project’s goal is to implement the examples in the Perl Cookbook in multiple languages. Groovy is one of those languages and I believe the first one in which 100% of the examples have been implemented. The examples are very useful and easy-to-understand, so I highly recommend this resource.
Note: I recommend downloading a copy of the PLEAC-Groovy web site using something like HTTrack or the Scrapbook plugin for Firefox. You’re probably going to use this reference a lot, so you’ll want to have quick, offline access to it.
- groovy-user Mailing List – This list is very informative, and most of the people with which I’ve interacted on this list have been very knowledgeable and patient. It is highly recommended.
Application Overview
I can’t really say much about it, other than the following:
- It’s designed to run on a server and has a command-line interface.
- It performs a lot of filesystem-related operations.
- It processes a lot of XML.
- It has a lot of unit tests.
- It integrates with a proprietary, third-party library.
First, let me say that the Groovy feature that stood out for me the most was it’s excellent, built-in XML processing libraries. I usually hate processing XML since there’s usually so much “heavy-lifting” and debugging, but Groovy makes the task trivial.
Another feature that I didn’t even know I would like be ended up loving was Groovy’s AntBuilder class, which allows you to use ant tasks in your code in a trivially-simple way. This was especially handy when it came to filesystem-related operations. And of course, the icing on the cake is that Groovy allows me to do all of this while integrating with all of the Java libraries (both standard and third-party) that I need to do my job on a daily basis.
Gripes
Of course, such a new language is going to have a few rough spots. Here’s the ones that I encountered most frequently:
Poor Error Messages
Occasionally, you will get error messages that make no sense whatsoever. My favorite is when it told me that I had a null character on a line that didn’t exist in my document in column 0 (which also doesn’t exist). The good news is that error messages in general are pretty decent, especially when you run Groovy with the debug switch.
Non-Intuitive Behavior
I ran across some truly odd functionality that border on a bug in my opinion. When I asked the mailing list for some clarification, I learned that some of Groovy’s functionality is dependent upon the brand of JDK that you’re using. Yikes. Hopefully the Groovy developers are able to normalize these sorts of anomalies in the future. In the mean time, I recommend decent unit test coverage on any non-trivial application to ensure that everything’s working like you expect it to work.
Conclusion
Even with it’s rough spots, I found Groovy to be incredibly robust, stable, and easy-to-use. Not only did it satisfy 99% of my requirements perfectly, it provided time-saving functionality that I didn’t even know I needed. Now I’m curious to see how the end users like it

