My Impression of Ruby So Far
Tags: programming.ruby, programming.scala, programming.haskell
Background
I’ve recently started programming in Ruby. I’ve inherited a codebase for writing automated-UI tests against a website. The tests make use of Capybara, which provides a high-level “DSL” for interacting with a webpage/browser in the sameway a user would; Capybara itself does this by abstracting over Selenium (or some other driver, like Poltergeist/PhantomJS); Selenium itself allows interaction with different web-browsers, by providing abstractions for different drivers of browsers (e.g. ChromeDriver).
As is also common for tests like these (called “UI tests”, “acceptance tests”, “functional tests”, “specifications”, “end to end tests” depending on who you ask) is use of Cucumber. – But that’s not too important for this post.
Very First Impression
Anyway,
I’d first read a few books before getting my hands dirty. (“Ruby Best
Practices” and some of “The Ruby Way”). What I read was exciting enough: Ruby
seems to be a language with decent pedigree, inheriting aspects from Lisp and
the emphasis on message-passing from SmallTalk (as well as e.g. the power of
Regular Expressions from Perl).
Also cool was e.g. Ruby’s dynamic features. Everything is an object, objects
pass messages between each other. And so by overriding a few magic methods,
some pretty cool things can be done. – e.g. the method_missing
method is
called if the object was called with a method that wasn’t defined on that
object; so an object overriding this can have different behaviour.
That Ruby isn’t a low-pedigree language surprised me. ‘cause I kindof thought
of Ruby as a “slightly prettier Python”. (It really isn’t, the philosophies of
the two languages are quite different).
And while I’d heard Ruby documentation was ’good’, it was ‘good’ by-way-of
“here’s an example of probably what you’ll want to do”.
And, well, if all someone knew was “Ruby on Rails”, then it’s kindof a good
indicator that that person (prob’ly) doesn’t know how to program.
Steve Yegge also gave the language well-nuanced praise: that he didn’t like the language, but he found himself using it for everything when he had the choice; that he didn’t know the language, but he found he didn’t need to read the documentation while writing it (unlike other languages he was more familiar with).
Actually Using It
I’d say, Ruby isn’t as nice a blub language as Python is. To me it feels like a blub language, but with a message-passing system.
I guess I don’t like it as much coming from a Scala background:
“Ruby’s nice ’cause you can map/reduce over lists” … just like Scala. But
without pattern matching.
And Ruby has nice “no brackets” syntax … like Scala. (Except in Ruby, it’s
like o.m(x,y,z)
can be o.m x, y, z
; in Scala it’s more like x.op(y)
can
be written as x op y
; in Haskell it’s f(x,y,z)
must be written as f x y z
). – Also, in Scala, operator overloading works for any symbol which is a
valid method name, whereas Ruby takes C++’s approach.
That Ruby has symbols (like Lisp) is one thing I certainly do like about it, though.
And I guess I don’t like it as much coming from a Haskell background:
Say what you like about how shit Haskell documentation can be; (and I suppose
outside “being too academic”, large-scale shit like Lenses can be god-damn
atrocious to read). But at least it’s clear what types things have.
Ruby documentation makes clear what messages the objects receive. – The
expectation is that the documentation give examples of different ways to use
the method. Fucking good luck to you if the documentation lacks that. – This
is slightly exasperated by Ruby’s “there’s more than one way to skin a monkey”
philosophy, wherein a call to the same method-definition with different kinds
of arguments ought to do the-right-thing.
And I guess it kind-of, sort-of makes sense for those familiar with Ruby, but I
was surprised to learn that methods like map
, etc. accept only procs; even
if an objects method receives the same type of argument as an equivalent proc,
the higher-order methods only take procs.
– The lack of tuples (in the same sense as Haskell or Scala or Python) also
seems strange to me.
But the biggest woe I have with Ruby at the moment is “wtf errors”, presumably
from the magic. – It’s not completely uncommon in statements calling Capybara
(and therefore, Selenium, and ChromeDriver) to throw an "undefined method 'map' for 0:Fixnum
(or nil:NilClass
), when the statement contains no calls
to map, nor any numbers/nil values. (I guess as a hint, the same statement may
sometimes throw other errors about connection problems for some pipe).
– i.e. the call-stack from the exception doesn’t show the actual call-stack.
It’s possible, but very difficult, to debug this sort of thing. I still haven’t
figured it out.
– All that said; this was on an non-idiomatic codebase I’d inherited. And I’m by no means yet comfortable with writing Ruby.
Conclusion / Hopes
So I find the syntax and semantics of Ruby conflict with what I’d expect,
coming from a Scala/Haskell/Python background.
I’m not saying Ruby is a bad language. It looks like it’s pretty nice at
writing message-passing paradigm programs. – But I don’t yet have love for the
Ruby environment.
Btw, About Cucumber
Cucumber is a tool to help write “executable specifications”. The specification
is written in e.g. Gherkin; the main aspect of a Gherkin specification is its
sequence of Given/When/Then steps, written in a natural-language like English.
– Cucumber tests will then bind these steps to code by matching the steps
against a regex, and executing some code for that.
(In terms of “does the program pass tests”, this is kindof a costly abstraction
to make, and for programmers-only, it’s easier to just write the executed code
directly. – The purported benefit of writing executable specifications is more
about communication: first that those involved in writing/reviewing the
specification come up with an agreement of what the program ‘is’, & what
terminology/phrases to use when discussing it; second that you get a
(readable!) “living document” which describes what features the program has).
The automated testing suite is still quite young (currently working on getting it stable). I’m interested in seeing what difficulties come up in maintaining it (both from a technical and ‘social’ standpoint).