Monday, March 5, 2012

Why critics of Rails have it all wrong (and Ruby's bright multicore future)

Edit: Contrary to what I said here, José Valim is not stepping down from Rails core, he is merely on sabbatical. My bad.

Lately I've been getting the feeling the Ruby community has gotten a bit emo. The enthusiasm surrounding how easy Ruby makes it to write clean, concise, well-tested web applications quickly is fading. Rails has become merely a day job for many. Whatever hype surrounded Rails at its inception has died down into people who are just getting work done.

Meanwhile, Node.js is the new hotness, and many in the Node community have sought to build Node up by bringing Ruby and Rails down. I know that once upon a time Ruby enthusiasts were doing this sort of thing to Java. However, the tables have turned, and where Ruby used to be the mudslinging hype-monkey, it's now become the whipping boy and Node.js the new provocateur.

The sad thing is many of these people are former or current Rubyists who have taken a liking to Node and build it up by spreading blatant untruths about Ruby. I won't go as far as to call them liars, but at the very least, they are extremely misinformed, ignorant of the state of the Ruby ecosystem, and pushing their own agendas.

Jeremy Ashkenas, the creator of CoffeeScript, recently trashed Rails 3 and claimed "Node.js won":


The idea that Rails 3 was a major step backward was recently reiterated by both Giles Bowkett and Matt Aimonetti. Both of them painted building ActionController::Metal applications as some sort of byzantine, impossible task which can only be accomplished by a Rails core member. Are people actually building lightweight Rails applications using the newfound modularity of Rails 3?


Jose Valim, (now former) Rails core member, published a small, simple gist illustrating how to build barebones apps on ActionController::Metal (one of the most forked gists I've ever seen) which is further documented in his book Crafting Rails Applications. In just 50 lines of code you can strip Rails down to its core, making it ideal for use in modern client-heavy HTML5 applications. The funny thing about this gist is that while the idea of a 50 line Rails app seems pretty impressive, the basis of that gist is what Rails 3 puts into your config/boot.rb, environment.rb, and application.rb, just combined into a single file. Did I just blow your mind? Sadly, all the (in my opinion completely undeserved) bad press seems to have made Jose emo as well, and he has stepped down from Rails to pursue his Elixir language.

ActionController::Metal-based applications (along with apps written in Clojure) were the basis of our backend at Strobe, where we sought to ease the pains of people building modern client-heavy HTML5/JS applications with frameworks including SproutCore/Ember, Backbone, and Spine. ActionController::Metal provided a great, fully-featured, mature, and modular platform for us to build applications on top of, and Strobe's ActionController::Metal stack for client-heavy HTML5/JS applications is available on Github. The apps we built with the Strobe ActionController::Metal stack talked only JSON and our frontend was an HTML5/JS application written with SproutCore.

Before Strobe, I worked at a company building rich HTML/JS applications for digital television. Our backend was written in Rails. Our frontends were Flash and HTML/JS applications, the latter of which were single-page client-heavy HTML/JS apps that were packaged in .zip files and installed onto digital televisions and set top boxes, a sort of weird hybrid of web technologies and installable applications. Our Rails application didn't have any views, but provided only a JSON API for the HTML/JS frontend to consume.

Rails was great for this, because it provided the sort of high level abstractions we needed in order to be productive, ensure our application was well-tested, and above all else provided the necessary foundation for clean, maintainable code. I was doing this in 2008, and even then this was already considered old hat in the Rails community. In case you're not paying attention, that's one year before Node even existed.

Modern HTML5/JS apps depend on beautiful, consistent RESTful JSON APIs. This is a great way to develop rich interactive applications, because it separates the concerns of what the backend business logic is doing from the view layer entirely. Separate teams, each specialized in their role, can develop the frontend and backend independently, the frontend people concerned with creating a great user experience, and the backend people concerned with building a great API the frontend application can consume.

Rails is great for JSON APIs.

And yet this meme persists, that somehow Rails is actually bad at JSON APIs. Those who propagate this meme insist that Rails has lost its edge, and that only Node understands the needs of these sorts of modern client-heavy web applications. Giles recently attempted to argue this position:


Giles recently blogged about this issue at length. Let's look at what he has to say about ActionController::Metal and the new level of modularity and clean design that Rails 3 brings to the table:


So Jose wrote a great book about the incredible power of Rails 3's new modular APIs... but... but... but what?

WARD CUNNINGHAM BITCHES. TWEETS > BOOKS. NODE WINS. QED.

Hurrrrrrrr? Ward Cunningham is a cool guy and his concept of a Wiki was a transformative technology for the web, but what the fuck does that have to do with Rails 3's new modular APIs or Jose's book? I think that's what people in logical debate circles call a "non-sequitur".

Perhaps there's still a cogent argument to be had here. Let's dig deeper:


Okay, so the problem is there's not a damn simple way to do websockets. OH WAIT, THERE IS:


Cramp is an awesome, easy-to-use websockets/server-sent events framework (with socket.io support) which runs on Rainbows or Thin, and Thin is a great web server. According to my benchmarks it's approximately the same speed as Node's web server:

Web Server            Throughput  Latency
----------            ----------  -------
Thin    (1.2.11)      8747 reqs/s (7.3 ms/req)
Node.js (0.6.5)       9023 reqs/s (7.1 ms/req)
Yes folks, Node isn't significantly faster than Ruby at web server performance. They're about the same.

Giles also bemoans bundler, because typing "bundle exec" represents ceremony, and using any of the myriad solutions to avoid typing "bundle exec", such as bundler binstubs or rvm gemsets, represents configuration which violates the Rails mantra of "convention over configuration", and how npm is that much easier. I'm sure we would all love to not have to add a one line .rvmrc file to each project to avoid typing "bundle exec", but uhh Giles, bro, mountain out of a molehill much?

Meanwhile, let's check out how convention over configuration is going in the JavaScript world:


But enough about Giles... what kinds of awesome, modern HTML5 applications are people using Rails to build?

I think one of the best examples of this sort of application is Travis CI. Travis is an open source distributed build system with an Ember-based frontend and a Rails backend. Travis's interface shows, in real time, the state of all builds across the entire (distributed) system, allows you to interactively explore the history, see the distributed build matrix completing jobs in realtime, and even have it stream the console output of builds in progress directly to your browser as they complete. It's an amazing, modern client-heavy HTML5/JS application, and it's built on Rails.

Who else is using Ruby/Rails for their frontend? Oh, just Twitter, LivingSocial, Groupon, Heroku, EngineYard, Github, Square, Zendesk, Shopify, Yammer, Braintree, Boundary, Stripe, Parse, Simple, and of course let's not forget 37signals. Rails is the technology underlying the frontend web stack of many huge businesses. Many of these companies have client-heavy HTML5/JS applications which consume a JSON API coming out of Rails. Many of them have APIs that are routinely cited as archetypical RESTful JSON APIs. Many of them have top notch engineering teams that choose the best tools for the job and use many languages for many different tasks. Many of them were founded "post-Node" and had the opportunity to choose Node as their frontend web technology, and while they may use Node in some capacity, their main consumer-facing sites are written with Rails.

Node is three years old now. Where are the Node.js success stories? Who's built a brand on top of Node?  Nodejitsu? Hubot? Is Node anything more than a pyramid scheme or a platform for Campfire bots? Where Rails selling points eschewed performance and instead focused on clear code, rapid development, extensive testing, and quick time-to-market, Node's selling points seem to universally revolve around its insanely fast, destroy the internet fast performance (benchmarks not provided). Meanwhile code quality is de-emphasized and large Node programs degrade into incomprehensible, byzantine structures of callbacks and flow-control libraries, instead of being written in sequential code, you know, the code you can read:

 

What about Ruby in general? What advancements in the Ruby ecosystem are worth getting excited about?

JRuby is maturing into a high-performance Ruby implementation which taps the JVM's advanced features including the HotSpot compiler, multiple pluggable garbage collectors, and parallel multithreading which makes it suitable for multicore applications. One thing I think sets JRuby apart is that it's the most mature language on the JVM which didn't start there. Other projects to implement non-JVM languages on top of the JVM, such as Rhino and Jython, have languished, while JRuby keeps going strong.

The most exciting development in JRuby is Java 7's new InvokeDynamic feature. The Java Virtual Machine was originally designed for the statically-typed Java language, but has its roots in dynamic languages, namely Smalltalk. With InvokeDynamic, the JVM has come full circle and now natively supports dynamic languages like Ruby. InvokeDynamic provides the necessary information to the JVM's HotSpot compiler to generate clean native code whenever Ruby methods are called, in addition to many other potential optimizations. So how much faster will InvokeDynamic make Ruby?


Rubinius, a clean-room Ruby virtual machine based on the Smalltalk-80 architecture, is also a very exciting prospect for the Ruby community as it matures and reaches production quality. It features an LLVM-based JIT compiler, parallel thread execution, and advanced garbage collection, also making it suitable for multicore applications. Beyond being an awesome Ruby implementation, Rubinius has evolved into a true polyglot platform and now features multiple Rubinius-specific language implementations including Fancy and Atomy.

MacRuby also eliminated the GIL from their implementation and now supports parallel thread execution along with an LLVM-based JIT compiler.

There are no less than three Ruby implementations which now support thread-level parallelism and thus multicore CPUs. This is especially relevant in a time when computing is undergoing a sort of phase transition from single-threaded sequential applications to massively multithreaded concurrent applications and distributed systems made out of these multithreaded applications.

It wasn't too long ago that having even four CPU cores in your home computer seemed like a lot, and now 16-core commodity AMD CPUs are available. The future is multicore, and if your programming language doesn't have a multicore strategy, its usefulness is vanishing. Following Moore's Law, the number of cores in a CPU is set to explode exponentially. Is your programming language prepared?

Thanks to JRuby and Rubinius, Ruby can take advantage of multicore CPUs. This still leaves the small matter that multithreaded programming is, uhh, hard. Fortunately I have some ideas about that.

Celluloid is an actor-based concurrent object system that tries to pick up on the concurrent object research that was hot in the mid-90's but died shortly after the web gained popularity. In the '90s concurrent objects were ahead of their time, but with the advent of massively multicore CPUs I believe it's an area of computer science research that's worth reviving.

Celluloid packages up Ruby's core concurrency features into a simple, easy-to-use package that doesn't require any modifications to the language. Where many functional languages solve the issues surrounding concurrency with immutable state, Celluloid solves it with encapsulation (more information is available on the Celluloid github page).

Celluloid takes advantage of many of the features of Ruby, including parallel threads, fibers (coroutines), method_missing (proxy objects), and duck typing. There aren't many other languages with this particular mix of features. Python probably comes the closest, aside from multicore execution due to its GIL. Jython supports parallel thread execution thanks to the JVM but seems abandoned. For what it's worth, Python once had a concurrent object system quite similar to Celluloid back in the '90s called ATOM, unfortunately the source code has been lost.

Ruby is by far the best language available today to implement a system like Celluloid, and that alone makes me excited to be a Rubyist. Where Node.js gives you a hammer, the single-threaded event loop, Celluloid gives you a large toolbox and provides a singular framework of interoperable components which can be used to build arbitrary hybrids of concurrent multithreaded applications, event-based nonblocking applications (that are callback-free!), and distributed systems.

Ruby is a language which can survive the massively multicore future. Whether Node will stick around remains to be seen.

27 comments:

Dan Carper said...

Great write up.

Who's built a brand on top of Node? is truly the only thing that matters in the end.

konsi said...

Great post. I didn't know about cramp before.

Stevan Little said...

I think this is just the ebbs and flows of our fashion driven industry. If you substitute "Perl" for "Ruby" and "Node.js" for "Ruby" in first three paragraphs, this echoes much of what was going on 5 years ago in those communities. Meanwhile the Perl community is still here and flourishing as Perl approaches its 25th year.

... said...

Excelent write-up! This exodus of Rubysts to node.js is actually a good thing. Now that the hype is leaving Ruby's side it will be easier for it to grow and mature as a language and platform.

... said...
This comment has been removed by the author.
... said...
This comment has been removed by the author.
... said...
This comment has been removed by the author.
Caio Tiago said...

Hey, I love Ruby but I have something to show you.

Google for: Erlang concurrency

Well, you can also search for scala concurrency or smalltalk concurrency.

Ruby is not the only language with actors concurrency out there.

Tony said...

Yeah, I'm familiar with Erlang: http://www.unlimitednovelty.com/search/label/erlang

Celso_ said...

Caio, he's didn't say Ruby was the only whom implements Actor concurrency.

Philip Jenvey said...

FYI Jython is not abandoned: http://fwierzbicki.blogspot.com/2012/03/adconion-to-fund-jython-27.html

JRuby has certainly had much more funding over the past few years, though

BigJason said...

Hey great post thanks. I use rails and node.js both in my personal projects and at my day job. Frankly I don't understand why people seem to think you can only like one or the other. They work well together and compliment each other very nicely. Node makes things like websockets and asynchronous network programming pleasant, but I would not want to write a full web site in it. Rails solves that problem so much better.

Just my 2 cents.

Kris Leech said...

Torquebox (Rack on JBoss) also supports web sockets.

KAMiKZ said...

Hi there I can probably understand half of what you wrote but I can't agree more that writing apps in rails or ruby is a joy , I have no cs background at all coming from group math , I stil don't know what public void stands for but ruby really cuts down on all that code noise when learning programming. And writing everything in JavaScript or simply writing anything in one language is against my personal mantra of horses for courses. Cheers !

Unknown said...

Contrary to the title, on closer reading,

the author means that while Ruby is surging, the rest of Rails, the framework itself, is dead.

Unknown said...

Contrary to the title, on closer reading,

the author means that while Ruby is surging, the rest of Rails, the framework itself, is dead.

secondhand bicycles in uk said...

Excellent Working Dear Friend Nice Information Share all over the world.God Bless You..
bicycle shops near london olympic village
used bicycle shops in london

daniel king said...
This comment has been removed by the author.
daniel king said...

so now it's not worth to learn rails and use rails now?

Bertrand said...

I'm a Rails developer and god knows I love the framework and the underlying technologies so I get where you're coming from and getting at, but Rails DEFINITELY doesn't make it easy to do websockets.

Cramp is nice and all, but it's not Rails now is it.

Look at any article by either Mike Perham or Ilya Grigorik from 2/3 years ago and it's suddenly obvious has a long way to go in the asynchronous/sockets department. All of which turned out to become ubiquitous in today's web programming.

So yeah, Rails is awesome is MANY ways, but it still has a way to go in some others.

Abhishek Mishra said...

Also you forgot Rubymotion - write iOS apps in Ruby. The ecosystem is growing at a good pace. It's moving towards being a very productive way of making apps :)

Blake Barnett said...

Kind hard to "forget" something that was released months after this post was made.

Christopher Rueber said...

Very well put. While I think a person could build a brand on top of any sufficiently mature system, Ruby is one of the few out there that have people constantly pushing the envelope.

Nikos Dimitrakopoulos said...

Nice writing. But still - don't take it too personal. In life there is hardly pure black and pure white. Usually it's somewhere in between them. For example I would try Node for concurrent and cutting edge stuff but as said from others I wouldn't (yet) build a real big web application on top of it.

Steve Phillips said...

Your claim: "JRuby is maturing into a high-performance Ruby implementation which taps the JVM's advanced features including the HotSpot compiler, multiple pluggable garbage collectors, and parallel multithreading which makes it suitable for multicore applications."

What the benchmarks say: JRuby running on a quad-core machine is no faster than Ruby (which can only run on 1 core)... and uses 30x the memory -- http://shootout.alioth.debian.org/u64q/jruby.php

Steve Phillips said...

"The future is multicore, and if your programming language doesn't have a multicore strategy, its usefulness is vanishing."

Absolutely! And where does Ruby fit into this, you say?

"Thanks to JRuby and Rubinius, Ruby can take advantage of multicore CPUs."

Re JRuby: as pointed out in my previous comment, JRuby is no faster than Ruby, even when running on 4 cores instead of 1. Not a good sign.

Re Rubinius: on its roadmap (http://rubini.us/roadmap), the maintainers say they plan to support Ruby 1.9 with the next major release. That's right -- Rubinius doesn't even support 1.9, even though 1.9.0 was released almost 5 years ago (December 2007).

"That's OK," you may think, "they probably iterate quickly." Well, their latest release of any kind, no matter how minor, is over a year old. Their last major release is many years old.

The future isn't looking so bright for Ruby.

(My fav scripting language, Python, also has its chances at being relevant in a multicore world, but is also in trouble. I don't use Node.js and will continue using Go for my multicore needs, at least for a while. Python's JIT, PyPy, is in very active development -- much further along than Rubinius, AFAICT -- but that doesn't solve the multicore issue! PyPy is ~17x faster than CPython... but the GIL remains.)

wordalchemist said...

I was reading up on Rubinius and came across your great post. Excellent read.