Thursday, March 01, 2007

Rails deployment for a Java developer

As some might know, lately I have been given the chance to work seriously with the Ruby on Rails framework in a real world project for a customer. Besides me loving most--but not all--of Rails, I am now giving the production deployment environment a serious look.

Through many years now, I've been developing mostly using Java, and as a consequence of this, I have in depth-knowledge on packaging and deployment of Java applications. I will do a couple of posts here about my experience on deploying and hosting my rails application in a real production environment.

Comparing to Java, what's different?
Well, lots. When developing, you get the feeling of speed real quick. It is really nice to keep delivering business value. Now, when I am going to deploy, I feel less productive than in Java.

No Standardized Deployment Unit
Personally, I think other platforms, including Rails and .Net, can learn a lot from the Java platform, with respect to deployment. The standardization of deployment units like the .jar, .war and .ear files are very nice. You do not really know what you have got, until it is gone.

In Rails, there is no such thing. The simplest way is to just upload your directory structure to the production server, and then, it is deployed. That is the simple way. But it is not good enough. Some files should not go into production. Some are different in the development environment, and should not be copied, but merged into deployment environment.

Then, there is Capistrano, which can help you. But when compared to a .war file, it lacks a lot. What is so great about Java deployment is the standardization. You can drop one .war file in any compliant web container, and it will deploy.

Setting up environment around Ruby is a manual process
Another thing is the need to install third party libs in all environments you deploy to. My rails application happens to use RedCloth, so before deploying a version of my application, that needs this, I must remember to do a gem install redcloth. In Java, this is simply packaged as a part of the deployment unit in WEB-INF/lib, much nicer.

Also, some ruby libraries depend on native libraries being installed. These must be installed too, in correct versions, as are their dependencies. We are not used to this is Java. So much is available on the Java platform, so it is very rare, that any deployment depend on anything native being installed outside the deployment unit.

Actually, these problems can quickly make it a problem developing on one platform, like Windows, and deploying on another, like Linux.

Thread-safety - not in Rails
A last thing is the problem of simultaneous requests and thread-safety. The Rails framework is not thread-safe. I acknowledge, that this can make both developing the framework itself and developing the applications using the framework, simpler, but it sure makes the deployment harder.

You cannot rely on simply starting and monitoring one multi-threaded server to serve all requests. We are back to multi-processes for scaling the number of simultaneous requests, which seems so yesterday to me. This means CGI, Fast-CGI or some other solution like mongrel.

Not so bad, afterall
But then again, I guess this is the Rails way. You only need to setup deployment environments a limited number of times. So it is okay, for this to be a bit harder. On the other hand, actually developing the applications using Rails must be easy, which it is, as this is where we produce actual value.

Posts coming up
My next post will be about my first, naive attemt on deploying Rails using CGI. Yes, I know, it is said to be slow. But it seemed the simplest solution, and the site was not going to take a lot of hits.

See how that went, in my next post.


Gock said...

I found this post interesting. I discovered it in the context of thinking about building my test framework for a Rails application. Thinking about frameworks that I've built in the past for Java and .Net, I had the luxury of being able to load a deployment unit, an associated test unit, and use reflection to inspect the degree of coverage that the test unit had on the deployment unit.

Over the next couple of weeks, I'll be working on figuring out how to accomplish something like that in Rails (I'm a total noob in ruby & rails.)

yagmurunsesi said...