The Ruby vs. Java Experiment

I'm doing an experiment, developing an enterprise application in Java and Ruby in parallel, trying to evaluate whether Ruby is enterprise ready, or Java must still remain my weapon of choice.

Tuesday, January 09, 2007

Elad’s Adventures in Java WebServiceLand

As the title suggests, it turns out that using web services with Java is not as simple as you’d expect.

Executive Summary:

Axis 1.x is no good. I tested Axis2 and in many ways it’s worse. I tried XFire and it’s pretty good, but missing some functionality I needed. Finally, I moved to Sun’s JAX-WS RI (reference implementation), which turned out to be a good solution.

The process took way too long and involved way too much hacking.

And if you’re interested in the subject, here’s the complete story:


Apache Axis 1.x

There’s general agreement that Axis sucks. I’ve been a user since version 1.1, and I was never a happy user L . While it’s widely adopted, I decided to search for an alternative this time, especially since it looks like there isn’t much development effort going on in that project anymore, and Apache Axis2 is supposed to replace it.

Apache Axis2

If at all possible, Axis2 sucks even more than 1 did. The BileBlog sums it up better than I could. In short, I downloaded, played, read some docs, and decided to stay as far as I could. Next solution please.

Codehaus XFire

Now XFire’s a whole different story. Unlike Axis2 the code’s nicely written, and you don’t have to create aar’s out of your jar’s (and a host of other stupid inventions). It also integrates nicely with Spring, and so I managed to write a little test application in no time. Next I began using it with my main project code, and that’s where the problems started.

My data model includes a graph representation and I’ve some circular references between objects there, i.e. a parent referencing a set of children, and each child referencing the parent. It turns out that Aegis – the default XML binding engine for XFire doesn’t handle that situation well: when it serializes a child, it serializes the parent as well, which in turn serializes it’s own children (including the original child), and soon enough you get a StackOverflowError.

The obvious solution seemed to move to JAXB 2.0 which XFire supposedly supports. Unfortunately, it turns out that support isn’t good enough yet, and the WSDLs that I got from XFire using JAXB 2.0 and JSR 181 annotations weren’t readable by SoapUI.

App-Server-Specific Solutions

At this point I started looking at what JBoss and WebLogic are doing, since I heard that they had pretty good solutions of their own for Web Services. I really liked what I saw in WebLogic, but unfortunately one of my requirements for this project is to be app-server agnostic, so I decided not to go there just yet.

JAX-WS RI

In the end I came to Sun’s new open source reference implementation for the JAX-WS spec. I avoided it up until then, since a reference implementation usually does not bode well for scalability etc. Nevertheless, it seems that this time I struck gold!

First of all, exposing web services with JSR 181 annotations really is a breeze. Add Sun’s WSServlet dispatcher servlet to the web.xml and a simple sun-jaxws.xml file (finally, a simple xml configuration file!) to the WEB-INF directory, deploy the war to tomcat, and it just works.

I spent some more time on setting up JAXB 2.0 annotations on my data model classes, and the whole thing turned out just beautiful.

Next I wrote a web service client (since there’s no problem with my client being aware of the model and service packages, there was no point in generating from WSDL).

What took a little longer was building the thing with maven (dependency issues), but Mohan had provided a very helpful solution for that in his blog.

Next I tried to make JAX-WS RI play with Spring, which proved to be more difficult. Kohsuke Kawaguchi has a JAX-WS Commons project dedicated to integrating the two, but I couldn’t make the code work. Instead, I opted for a simpler solution – I load the Spring application context in a glue factory I wrote, rather than in the tomcat’s listener. My service classes call the factory to get Spring managed bean. It’s probably not “the Spring way”, but works for now – I might try Kohsuke’s solution again in the future.

Monday, December 11, 2006

Java & Hibernate vs. Ruby & ActiveRecord

I did a lot of work on our data model the past two weeks, a little with Ruby, a little with Java, and back again. I thought I should share some insights regarding the different approaches they take towards modeling your data, and their pros and cons.

In general, with Java and Hibernate you’re supposed to start with the objects, then add the relational mappings. With Ruby on Rails you start with the relational database, and ActiveRecord builds the object model automatically from that.

It makes perfect sense that each language chose the path it did:

Thinking in Java, it’s natural to start with the objects, carefully design and code your classes and interfaces, then add some XML or annotations (I used the latter) almost as an afterthought, just to enable persistence. Books and manuals treat the need to map between objects to a relational DBMS as a sort of nuisance that you have to deal with.

In Ruby, it not as natural to start by defining properties and their data types for your classes, which may have led to the acceptance of the idea to start with SQL DDL (that’s all about properties and data types), then do the rest with some ruby magic.

After discussing the respective approaches with some Java people I noticed a common perception which I think is a gross mistake. They tend to think that when you design a data model you should only think in objects, and that considering the relational persistence layer doesn’t happen at this stage, and thus the Rails approach is problematic. I think that’s wrong. After all, you have to start by thinking in terms of entities and their relationships. You can call these tables, objects or whatnot, but that’s exactly what you need for a relational model. It’s possible though that it’s just me – I did a lot of work with RDBMSs in the past, so my thinking is effortlessly geared towards the relational representation.

When it comes to simplicity and speed of development, ActiveRecord beats Hibernate hands down. I built my model in Rails (i.e. effectively in SQL) first, which is faster (for me) than defining Java classes. Going deeper into ActiveRecord in order to add the various data access methods I’ll be needing, and writing unit tests for everything took me less than two days. The process I had to go through in Java to achieve the same result has been going on for over a week, and I’m not done yet. Also, there’s far less

Note that in my case that included learning ActiveRecord, and learning Hibernate, EJB 3.0 O/R mapping annotations, HQL, and the various Spring mechanisms that wrap the Hibernate stuff. Much more learning to do on the Java side. On the other hand, I’ve a lot of experience with SQL. For someone with no SQL experience, the Rails part may take longer.

In short, the Ruby part was fast and easy, and thus much more fun.

The thing that annoyed me most with ActiveRecord are related to its lack of expressiveness: just by looking at the code, it’s impossible to tell what data members are hiding in my model - you have to look at the DB or migrations. Another issue is the conventions-based magic. The conventions for DB column names sure make things easy, but are rather annoying if you’re used to different conventions...

As usual, there’s a word of caution: all I did so far was very basic – I defined the model and added some rather naïve access methods. Rails tends to shine when you just start things up. Java and Hibernate may look better when my code gets more complicated.

For a more comprehensive comparison one (though outdated on some points) take a look at Patrick Peak’s Showdown article.

Thursday, November 30, 2006

First Rails Drawback

It had to come at some point, I just didn’t expect it so fast.
I regret to report that I came across my first hurdle with Rails today.
The idea was to quickly finish prototyping my web services (see previous post), so that I could give the client application team a WSDL they can already work with. However, when I took a good look at the WSDL file, I realized that it’s RPC/encoded, rather than the standard today – Document/literal.
That’s bad practice: first of all, this style isn’t WS-I compliant, and second, performance tends to degrade much faster.
I started looking for the way to configure AWS to work doc/lit style, and soon found out that there isn’t one – it’s just not supported at the moment.
Now, since I intend to use doc/lit with my Java system, this issue violates my success criterion #1 – my Rails and Java applications won’t be interchangeable; I can’t do with Rails anything that I can do with Java.
Worse, I’m going to have to integrate with some 3rd party products, and the plan was to do that via their SOAP API. Since they probably use doc/lit, that being the enterprise standard (WS-I compatibility and all), it’s likely that I won’t have a fast way to do that with Ruby.

I realize that for the broad Ruby and Rails community this isn’t much of an issue; most web apps are better off using REST rather than SOAP, and other popular services on the web expose their APIs via SOAP with the RPC/encoded style (Google search).
Nevertheless, from an enterprise development point of view, the lack of doc/lit support is a major drawback.

So, some possible solutions I came up with:
1. Code this myself.
I could try to add doc/lit support to soap4r – solve my problem and make a nice contribution to the community. The main problem with this approach, with regards to my experiment specifically, is that the whole idea was to see if Rails is enterprise-ready, and a better alternative than Java for enterprise development. If I need to invest a lot of time now to implement something that’s already available in Java, that defeats the purpose. Of course, if I did implement and outsource that functionality, then I solved the issue for future generations 

2. Look for libraries other than soap4r/AWS.
Ruby-Amazon could be a good candidate since Amazon’s Alexa Web Search service, which ruby-amazon apparently supports definitely uses doc/lit. The don’t use soap4r, so I might be able to use their code for the basic SOAP support.

I’ll probably try a combination of the two – use the ruby-amazon to speed up my own implementation of a more generic SOAP stack that supports doc/lit. Haven’t decided yet. It’s going to take some more research (and free time).

Wednesday, November 29, 2006

Rapid Prototyping

This week we finally began to do some real work. I focused on designing the services I need to expose to the client application, and figured that it could be a great chance to try Rails out as a platform for rapid prototyping.

The original plan was to write Java code first, Ruby second, but since I’m pretty comfortable with Rails by now, I figured that I should experiment with the other way around as well.

That proved to be a good experience: building a basic relational data model and coding a large number of naïve services that manipulate it took roughly one day’s work, including learning ActiveRecord beyond the basics. On top of that, the Ruby code comes out compact and neat. The ease and agility of the process makes it exceptionally adequate for prototyping when you have a very general idea of what the end result should look like. I felt free to code something, test, then change my mind and change the code over and over again.

The crux of the matter, I think, is that the process involved zero configuration, i.e. XMLs and annotations, and the whole change-build-deploy-test process gets shortened significantly. With the latter, it’s not just the time involved – it’s also the annoyance of waiting for the build and deploy tasks to finish – at this point it takes long enough to be annoying, but too short to go read some blog posts while I wait.

Next, I’ll code the same stuff in Java and report on the comparable experience.

Monday, November 20, 2006

Motivation

So, why am I doing this?

I’ve been using Java for nine years now. I never used it exclusively – I wrote lots of code with C, C++ and Delphi, but Java’s always been my bread and butter. Nevertheless, I’ve become more and more disenchanted with it lately. I’m going to skip the Java rants though – an entire book was written about Java’s problems, and Bruce Tate writes better than I do.

Anyway, not long ago I finally took the plunge and learned Python (this Paul Graham article was the catalyst – after all, I like to program, and I wasn’t satisfied with the languages I already knew). Soon enough I was asking myself what took me so long. I fell in love (Noa - don’t worry, not the way I love you). After the initial crush passed, I decided to look at Ruby as well. I liked it even better. I became convinced that Java’s days are numbered. The question’s not if, it’s when (and with Rails the latter question may have been answered already).

Obviously, I began evangelizing dynamic languages around the office, with some success (i.e. getting some Java programmers to play with Python or Ruby in their spare time).

Around that time I started writing the spec for this new project. However, when I suggested that we try something other than Java, I quickly learned that management would never buy it. To paraphrase the IBM maxim: nobody ever got fired for using Java…

What I realized soon enough was that I don’t stand a fighting chance with Ruby as long as I can’t show that it’s already been used successfully in serious projects in serious enterprises. Unfortunately, I couldn’t find any references. I decided to be that reference for others, and here we are…


Thursday, November 16, 2006

Progress Report #2 - Ruby 1 : Java 0

The first iteration in our project is over, and so is the first part of my experiment. The result: Ruby (Rails actually) wins by knockout!

I’ll start with the summary, in case you don’t want to read through the whole story:

It took me roughly 1 day to implement with Ruby on Rails what took me roughly a week of coding (net) in Java with Spring/Hibernate/Axis.

Actually, that’s not entirely true – the rails version has more functionality since I got the scaffold html CRUD interface for free!

It would have taken less than an hour had I known how to program Ruby…

Is this a knockout or what???

And now for the whole story:

In the past week I spent one day learning Ruby basics (just reading through the pickaxe book), and another half-day learning Rails (reading through to chapter 7 in the Pragmatic Bookshelf’s Rails books). At this point I felt that I’m ready to start.

It took me 20 minutes to get up and running with a scaffold web interface for my single DB table. Of these 20 minutes, 15 were due to the fact that I had to make some schema changes – rename some columns to conform to Rails defaults.

Next, I had to put a SOAP interface on my application. I read through Web Services on Rails, and soon thereafter my application had SOAP services that return 1 record, and all records from the DB table. That took maybe another hour, including learning how to write and run unit tests.

At that point I tried to add a service that adds a new record. That’s where I got stuck, since it turned out that you can’t pass an ActiveRecord::Base descendant as a parameter to an ActionWebService. The docs tell you to use an ActionWebService::Struct object, but I really didn’t feel like writing code that copies properties from my ActiveRecord to the Struct by name – what if I changed my schema and ran generate scaffold again? That meant I had to use reflection. In other words, I finally had to learn some more Ruby…

That was yesterday. It was getting late, and I had a date with some friends to watch football, so I had to go. Today I had a very long meeting that lasted through the morning, so I only went back to the problem after lunch. It took me another two hours to finish the work.

In the next post I’ll try to analyze how come the Java version took me so much longer. We have to keep in mind that this has been a very basic exercise so far. What I built is hardly an enterprise application, and Java definitely stands a good chance to come out on top in the next rounds. We’ll see.

In any case, I learned that there’s real substance behind the Rails hype.

Wednesday, November 08, 2006

Progress Report #1

It’s been roughly 2.5 weeks since the beginning of the project’s first iteration, and it’s time for a little progress report.

The objectives of this first iteration are rather simple: set up the entire stack and see it in action. On the server side that means a single database table, entity bean, DAO, business logic and a few web services. Those services provide basic RUD functionality for objects in the DB table. The client app needs to show that it can use those services.

Java

I’m pretty much done with the Java code for this iteration.

I’m using Spring and Hibernate, both of which I never used before. They were pretty fast to learn.

My DB is MySQL for now – I’ll need to port to MS-SQL and Oracle. Hopefully that’ll work smoothly with Hibernate.

For the web services I’m using Axis 1.4, which I don’t like much, and is giving me some troubles. I might evaluate some alternatives later on.

Ruby

I haven’t started coding the Ruby system yet. So far I spent roughly two days learning the language and the Rails framework.

My job now is to develop a Rails application that works with the same DB on the back end, and exposes services that conform to the same WSDL on the front end.


My missions for the next week and a half are:

  1. help the client team with the code that consumes my services.
  2. plan the next iteration.
  3. and most important – write some Ruby code.