[RAD stands for Ruby Ape Diaries, of which this is part VIII.] Programming is supposed to be an engineering discipline, or maybe a branch of mathematics. But, as Don Box memorably said: “the only people who should do it are those who can't not do it”, calling us “those few people who absolutely must live in the world of executable abstractions”. One consequence is that we’re passionate about the content and the form. Herewith some remarks on appearances; the way Ruby code looks and how you store it and so on; issues as important, perhaps, as any other.
As I wrote a few days ago, Ruby has a TMTOWTDI culture; for anything that’s worth doing, there are lots of different ways. This has made me alternately uncomfortable and happy.
Files ·
When I’m Rubying, I have to think about how to deal the code out into
files. A few years of Java have apparently atrophied the part of my brain that
does this. In Java, for those who don’t know, if you’ve got a
class called com.textuality.Lark
, the source has to live in
com/textuality/Lark.java
, and the compiler will generate
com/textuality/Lark.class
, and that’s all there is to it. If
you’re living in an IDE like NetBeans, this means that you totally never think
about files; you think in terms of classes and packages and the IDE puts the
code where the code needs to go.
In Ruby, it’s perfectly legitimate (and common) to have four or five
different classes, perhaps only loosely related, in a file.
I’ve done it, my REXML-for-Java stand-in has Element
and
Attribute
and Document
classes all in one file and
it seems natural and convenient.
Even if you wanted to, you probably
couldn’t impose a Java-like discipline because in the middle of your
FishFrying
module you might decide to add some new methods to
File
or String
.
Still, I’m not entirely convinced that it’s a good use of my time to think about where to put the code.
Names ·
Which is better, removeCamisole
or
remove_camisole
?
In Java, you never have to ask yourself this question because the
first option, “lowerCamelCase”, is so deeply wired into the culture that doing
anything else would amount to egregious abuse of anyone who might have to
maintain the code you write.
Ruby uses CamelCase for classes and leans to underbars elsewhere; although I’ve run across a few instances of CamelCase in method and module names. In the Ape code, I started up doing things in the Java style, but pretty quickly decided this was wrong, and have tried to stay in underbar territory, although there are a few lingering camels in the underbrush.
I think that for JRuby, in particular, this convention should be taken very seriously, so that by looking at something’s name you’ll know which side of the fence it comes from.
Parentheses · This one drives me nuts. I have actually spent nontrivial amounts of time looking at my code and agonizing over whether some method call should have them or not.
It’d be tempting to impose a simple policy: Parentheses always! Because this kind of thinking seems like a waste of time. On the other hand, the judicious omission of parentheses is one reason that Ruby code can be so readable. It seems pretty clear to me that for straightforward conditionals, compulsory parentheses are just static. Here are some ifs from the Ape code:
if uri =~ /^https?:/
if type == 'text' || type == 'html'
if collections.length > 0
On the other other hand, as a matter of principle I have refused to learn the precedence rules of any language I’ve ever used, and applied a Draconian policy of parenthesize-on-the-slightest-doubt. Once again, from the Ape:
if (!found_entry_coll) && collection.accept.index('entry')
But it’s method calls and declarations where the
to-()
-or-not-to-()
angst really bites.
One-argument calls and declarations generally don’t seem to need parentheses,
with the exception of Whatever.new(foo)
, where they for some
inchoate reason feel necessary. Do zero-argument calls ever need
parentheses? I think not.
I went through the Ape code and looked at all the places where I’d put
parentheses on one-argument calls, and they were all either new
or some sort of factory method, or “retrieval” methods that take an arg and
emit a value:
ids << entry.child_content('id')
Maybe the right answer is to figure out how to turn these into instances of
[]
so I’d be saying entry.child_content['id']
and
not sweating the parentheses.
Domain-Specific Languages ·
The Rubyists are always talking about creating them and what a great thing
this is.
As far as I can tell, they’re mostly just pimped-out method calls without
benefit of ()
.
Readability · It’s all about readability. It’s really all about readability. Code is maintained much longer than it’s written, and anything that makes it more readable is a really, really big deal.
Readability is important enough that maybe it’s OK that I have to stop and think about parentheses.
Readability is important enough that Ruby is right to allow, and Java wrong
to forbid, the use of nil
as false
and non-nil
as
true
in conditionals, so Ruby allows this
useful, highly-readable idiom, originally invented for C:
if handler && handler.check_content(message)
(Note that Perl is wrong in allowing ""
and 0
to
stand for false
, as I think most PerlMongers would now agree.)
Readability is important enough that incorporating Perl’s abbreviated-conditional syntax is good:
return true unless content_type == 'application/atom+xml'
Readibility is important enough to make Ruby’s method/block idiom a better way to iterate than anything else I’ve seen anywhere.