Don't get me wrong, Ruby is a great language. I've been around the block plenty. Ruby code can be beautiful, concise, expressive. Blocks were the gateway drug to functional programming for me. Programming in most other languages after significant Ruby exposure is painful. Why then, is Ruby not my favorite programming language?
Programming in the Large
Anyone working on an application with a reasonably long lifetime or sufficient number of versions knows the pain of "unwrapping the onion" when diagnosing or fixing a bug. Is it the client to server XML? The PHP talking to the database? The stored procedure being run? The screen-scraping utility driving a legacy green screen app? As the number of possible causes for a given bug goes up, my ability to track all of them at once gets worse. The more I have to "deduce" about my code's behavior (and all the layers its built on), the longer its going to take me to figure to what's going on. Its not that the bug won't be fixed - it's that the level of effort required is just going to group.
Now, let's step back. Separation of concerns, allowing each individual to focus on their own area of responsibility, is a key tenet in any large project. Most modern programming languages, and many not-so modern, directly support this. The motivation and benefit is obvious - when I'm working in my area of responsibility, I want to worry about as few other areas as possible. In a language or framework properly supporting a separation of concerns I can reasonably deduce the behavior of my code by looking at the source. The meaning of the code isn't going to change underneath me. The behavior of a given piece of code is constrained by the fixed definition of the elements used and varies in well-known ways. The amount of deduction required of me is limited to the definitions I can read in front of me or look up in other areas of the source. Further, the location of those definitions is generally well known and obvious from the code in front of me.
This brings us to Ruby. Loading up irb, what methods existing on every object?
irb(main):001:0> Object.methods.sort => ["<", "<=", "<=>", "==", ...
In my Ruby version (ruby 1.8.5), Object.methods has 73 elements:
irb(main):001:0> Object.methods.length => 73
Let's load 'rubygems' and see what methods we have now:
irb(main):002:0> Object.methods.length => 79
Nice, six new methods. I wonder what they do or which they are? I leave it to vigilant readers to compare the two lists and point out the differences.
Now let's load 'activesupport', used in the Rails framework, and see what we get;
irb(main):003:0> require 'activesupport' => true irb(main):004:0> Object.methods.length => 172
I think the only reasonable response here is OMFG. And we haven't even addressed the issue where a method's behavior has been fundamentally changed.
Sometimes Less IS More
Ruby's flexibility is amazing but also it's Achilles heel. Understanding the behavior of any given piece of code means understanding the changes made by any previously executed code. The world is no longer fixed - even the concept of "class" doesn't mean much, except as a nice place to attach functions you'd like to be able to find again (if you are lucky).
I've seen PHP used for large scale development and it's not pretty. Every "required" or "included" file can introduce variables into global scope. Tracking down the last piece of code that set one of those variables is a nightmare. But it's nothing like what Ruby allows - at least in PHP you aren't able to redefine the meaning of a function or the definition of a class. PHP is dangerous enough to make life difficult but not so much it is unusable. Ruby "in the large", even when executed by a team of very disciplined programmers, will require Herculean effort. Tracking down the source of a breaking change will demand powers of deduction beyond most mere mortals. Not every developer thinks that way or or wants to. Of course all bugs are solvable (well, almost all) but Ruby can only increase the resources and time required to do it.
Don't Let the Door Hit You ...
Ruby is a beautiful language and it's changing the world. I just hope it isn't here to stay, because I don't want to be debugging legacy Ruby apps ten years from now. My brain already hurts.