Why I Still Like Ruby (and a Few Things I Don’t Like)

David Eisinger, Development Director

Article Categories: #Code, #Back-end Engineering

Posted on

A long-time Ruby developer takes stock of the language's strengths and weaknesses.

(Illustration by roseannepage)

The Stack Overflow 2020 Developer Survey came out a couple months back, and while I don’t put a ton of stock in surveys like this, I was surprised to see Ruby seem to fare so poorly – most notably its rank on the “most dreaded” list. Again, who cares right, but it did make me take a step back and try to take an honest assessment of Ruby’s pros and cons, as someone who’s been using Ruby professionally for 13 years but loves playing around with other languages and paradigms. First off, some things I really like.

It’s a great scripting language

Matz’s original goal in creating Ruby was to build a truly object-oriented scripting language1, and that’s my favorite use of the language: simple, reusable programs that automate repetitive tasks. It has fantastic regex and unix support (check out Open3 as an example). I might not always build Ruby apps, but I’ll probably always reach for it for scripting and glue code.

A class is a little program

This one took me awhile to get my head around, and I’m not sure I’ll do a perfect job explaining it, but when a Ruby class gets loaded, it’s evaluated as a series of expressions from top-to-bottom, like a normal program. This means you can, for example, define a class method and then turn around and call it in the class’ top-level source; in fact, this is how things like has_many in Rails works – you’re just calling a class method defined in the parent class. In other languages, you’d have to reach for something like macros to accomplish this same functionality.

Here’s an alternate explanation of what I’m getting at and here’s a cool post that illustrates what sort of power this unlocks.

The community is open source-focused

Ruby has a rich ecosystem of third-party code that Viget both benefits from and contributes to, and with a few notable exceptions2, it’s all made available without the expectation of direct profit. This means that you can pull a library into your codebase and not have to worry about the funding status of the company that built it (contrast with venture-funded open-source like Gatsby and Strapi). Granted, with time, money, and a dedicated staff, the potential is there to build better open source products than what small teams can do in their free time, but in my experience, open source development and the profit motive tend not to mix well.

Bundler is good

It’s simple, universal, and works well, and it makes it tough to get into other languages that haven’t figured this stuff out.

It has a nice aesthetic

It’s easy to make code that looks good (at least to my eye) and is easy to understand. There’s less temptation to spend a lot of time polishing code the way I’ve experienced with some functional languages.

And some things I don’t like as much

Lest ye think I’m some diehard Ruby fan, I’ve got some gripes, as well.

It’s not universal

As I said, my favorite use of Ruby is as a scripting language, so it’s unfortunate that it doesn’t come installed by default on most unix-y systems, unlike Perl, Python, and Bash. If you want to share some Ruby code with someone who isn’t already a Ruby dev, you have to talk about, like, asdf, rbenv, or Docker first.

Functions aren’t really first-class

You can write code in an FP style in Ruby, but there’s a difference between that and what you get in a truly functional language. I guess the biggest difference is that a method and a lambda/block (I know they’re a little different don’t @ me) are distinct things, and the block/yield syntax, while nice, isn’t as nice as just passing functions around. I wish I could just do:

square = -> (x) { x * x }
[1, 2, 3].map(square)

Or even!

[1, 2, 3].map(@object.square)

(Where @object.square gives me the handle to a function that then gets passed each item in the array. I recognize this is incompatible with optional parentheses but let me dream.)

It is probably too flexible

Just like skiing, the most dangerous time to be a Ruby developer is the “early intermediate” phase – you’ve learned the syntax and language features, and all of a sudden EVERYTHING is possible. Want to craft the perfect DSL? Do it. Want to redefine what + does for your Integer subclass? Do it. Want to open up a third-party library and inject a custom header? You get my point.

As I’ve said, Ruby makes it easy to write nice-looking code, but it takes restraint (and mistakes) to write maintanable code. I suppose the same could be said about the programming discipline in general, but I can see the appeal of simpler languages like Go.

Type checking is cool and Ruby doesn’t have it

The first languages I learned were C++ and Java, which formed my opinions of explicit typing and compilation and made Ruby such a revelation, but a lot has changed in the subsequent decade, and modern typed languages are awesome. It’d be neat to be able to compile a project and have some level of confidence about its correctness before running the test suite. That said, I sure do appreciate the readability of things like RSpec that rely on the dynamic/message-passing nature of Ruby. Hard to imagine writing something as nice as this in, like, Haskell:

it { is_expected.not_to allow_values("Landlord", "Tenant").for(:client_type) }

(As I was putting this post together, I became aware of a lot of movement in the “typed Ruby” space, so we’ll see where that goes. Check out RBS and Sorbet for more info.)

So those are my thoughts. In the end, it’s probably best to know several languages well in order to really be able to understand strengths/weaknesses and pick the appropriate one for the task at hand. If you’re interested in other thoughts along these lines, you could check out this Reddit thread (and this comment in particular) or this blog post, but what really matters is whether or not Ruby is suitable for your needs and tastes, not what bloggers/commenters/survey-takers think.

  1. The History of Ruby
  2. I.e. Phusion Passenger
David Eisinger

David is Viget's managing development director. From our Durham, NC, office, he builds high-quality, forward-thinking software for PUMA, the World Wildlife Fund, NFLPA, and many others.

More articles by David

Related Articles