For the past year I've been working part of my time with Ruby on Rails. I had heard great things about Ruby on Rails and was excited to get a chance to work with it.
Over the time, I've formed some perspectives about RoR that I thought I'd write down.
First of all, I'm working with an older version of RoR, 2.3.11. Upgrading to Rails 3 is a Big Project that our team has not been ready/able to take on. So some of these opinions may be out of date.
My overall first impression - wow, this is really productive. I can make quick changes to web pages very fast and turn around new features quite quickly. I really do think that's the strength of Rails. So I think it's a great choice for an early startup that is quickly trying to get a minimum viable product to market and then start iterating very fast as the company adapts to what it learns.
However, there is a certain point at which the strengths of RoR become weaknesses.
For example, it is easy to rely on Active Record to provide a very simple, fast, easy abstraction to the database. But when you start scaling up, you can be slammed by the incredibly inefficient ways that ActiveRecord talks to the database. So you find yourself writing more and more raw SQL to try and process the data faster, and get the performance you need.
Then there's the dynamic nature of the language. You don't have to mess with the verbose nature of static type definition or time-consuming steps of compilation and deploy.
But the result of that is you end up working without a net. You just can not tell whether a change you make is going to break something, because you get no warnings from a static compiler telling you you're breaking a contract somewhere. We have classes with tons of methods that *seem* to be obsolete, but nobody dares to remove them because you never know if some code path, in production, is going to call that method and cause a stack trace. Even if you search for the signature everywhere, that is no guarantee, because someone could have built up the method call using string concatenation and invoke it using runtime evaluation.
The other problem is the tools just can not reliably do global refactorings like moving classes around or renaming things. This severely limits your ability to adjust and rethink your application as the design reveals itself more and more or your requirements change.
The argument is that to address this you write lots of unit tests, and that gives you the net you need. I think unit tests are invaluable, but I really don't like having to basically write a compiler using unit tests. I'd rather let the compiler do that for me. As much as everyone says they are writing unit tests, can you really rely on that? If you can, well, you must have a collection of very disciplined programmers on your team. I personally have never seen that...
Finally, the performance of Ruby just can not hold a candle to Java. Every time we migrate some logic from Ruby to Java, the difference in performance we get is quite astonishing.
So, here are my thoughts about how to go about building a system...
Fine, use Ruby on Rails to whip out your initial product quickly. But have in your plans moving things over to Java as things stabilize and specific services begin to reveal themselves in your design. This means, in particular, I would implement a domain layer between the front-end code and the Active Record models. This allows you to migrate the underlying implementation of the domain layer from Active Record to backend services written in Java.
Java has the performance, tools, APIs and stability to be the powerhorse of mature, highly scalable, robust middle tier infrastructures. Ruby really can not hold a candle to it. Having this kind of infrastructure becomes essential as a company scales up and matures, and customers begin requiring a high quality of service as well as new features.
In general, if you use a domain-driven design, where you focus on building a domain layer that is well thought through, and then provide APIs to the view and third parties, and pluggable interfaces to your lower-level services, you have the foundation for an architecture that can move through the evolution from a quick Ruby on Rails app to a highly robust, scalable system with numerous independent services written in a strong, high-performance language like Java.