Wednesday, April 29, 2009

So I'm in this Ruby on Rails class...

**This was a draft written in April 2009**
I'm publishing it now because, even though it isn't done, it will never get any more done. So that makes it done.

We use Ruby on Rails at work to manage our internal IT. Basically, we have a bunch of government regulated quality control stuff to keep track of, and no existing solution had the features we needed. So, we rolled our own using Rails. Rails made it possible to do this quick enough for it to be cost effective, and the end result is actually very pleasant to use. Rails has built in AJAX features, which we use extensively.

I've known a little about Ruby since it's quite similar to Python. It didn't really do anything for me beyond that though, so I never fully checked it out. But, being given the opportunity to do that and pick up 3 credits in an applications graduate course was too much to pass up.

Programmers are Expensive, Computers are Cheap

Matz's belief in this statement is fundamental to what Ruby is. Ruby is a very flexible programming language which allows a developer to do a lot while writing very little. The main difference between Ruby and Python is that Ruby has been a bit... infected... by Matz's use of Perl in his youth. This actually isn't really bad, as I'll explain in a bit.

The Good

There are some things about Ruby/Rails that are just patently awesome.
  • Symbols - These are awesome and every language probably should have them. Basically, they separate the semantic difference between "This is a string of text," and :programming_construct. This means you can do something like:

    redirect_to :action=>:view
    to cause the current action of a controller to do the same thing as the view action. Why is this better than Strings? It separates two semantically different ideas: I want to tell a person something (string) and I want to tell the computer something (symbol). This is nicer than the keyword args some languages have.
  • @localVariable - Probably the biggest wart in Python's syntax is explicit self. Not that it is bad; I think it is a very pure way of doing OOP. On the other hand, Python is supposed to be a pragmatic language, and 5 letters is clearly worse than one. Using @ to denote a class's field also has the nice advantage of making field's readily apparent when browsing code. This is compounded by the problem that neither vim nor pydev actually do syntax based field color changes. Using @ to make makes this trivial (and the ruby highlighter for vim handles this)
  • AJAX - Rails makes ajax almost as easy to do as a normal action. The one exception is when a call needs to update multiple parts of a page (for example, toggle a button and display a result). I couldn't figure out a way to do this without resorting to javascript hackery.
  • Regex Literals - One of the things that makes Perl sweet, I think this is a great idea. None of this java "\\\\" to match a backslash in a regex crap. Since regex are built into the language, the standard library strings use them nicely.
  • Open Classes - Hell ya. Wish this was making it into Java 7.

The Bad

There are some things about Ruby that suck.
  • Interpreters - There are more Ruby interpreters than bugs in my code. Seriously. Here's a short list:
    • MRI (ruby 1.8.x)
    • YARV (ruby 1.9.x)
    • JRuby (ruby on the JVM, more on this in a sec)
    • MagLev (based on some smalltalk VM, not much real info)
    • IronRuby (ruby on the CLR)
    • Rubinius (pure ruby VM)
    • MacRuby (ruby on OS X using llvm and the objective-c runtime)
    Now, Python has it's own VM harem, but there is one important difference: the mainline implementation is adequate. MRI has been the subject of much abuse due to memory leaks and such and is of course now on life support.
  • JRuby - I was really psyched to use JRuby for a few reasons. First, I do a lot of programming on the JVM and follow it pretty closely. Thus, I've been watching JSR 292 and generally the work the JRuby team has been doing with much anticipation. Secondly, I think that having a VM platform for many languages is a good idea, since it allows us to more efficiently apply optimization resources. Finally, I had heard bad things about MRI. The reality is that while MRI might not be as solid as CPython, it's still more than sufficient for a student. JRuby on the other hand, was slow to start up and had compatibility issues that a novice ran into in only a few minutes.
  • Errors - Both Ruby and Rails tend to emit some pretty cryptic messages sometimes.
  • End Statements - I blame Python for this entirely, but it's convinced me that whitespace is probably the optimal way to delimit code blocks. End is actually kind of worse than braces, since you can't match an end back to what it is ending in most text editors. Since ruby doesn't like to use braces or parens as much, it's actually a little worse than C-like languages since it's a little easier to get confused. And, of course, I managed to write some code that was wrong because the logical indentation was different than the physical one. I also managed to put an extra end statement into my code which took me forever to find...
  • Does Mongrel really need do a printout everytime the DB is hit? How am I supposed to make sure my params are correct?

Things that the Jury's Still Out On
  • GIL - sucks in Python, sucks in Ruby. We'll see if unladen swallow, pypy, parrot, or somebody manages to develop a better dynamic language VM
  • ERB - I don't like templating systems. They suck for readability of your high level language, they suck for the readability for your output language, and they require way too many start and end tags. Trying to write ruby to write javascript to manipulate strings leaves you in a complete mess. Of course, I'm not sure of a better way to acheive this; I guess I'd like a templating language more closely integrated with HTML or JavaScript.
  • Blocks - Generally, I like the idea of passing code around as little bits. At least, I like anonymous functors a lot (why do I code in C, Python, and Java again?). Using blocks for iteration is a little weird, but I suppose I can see why if you've already got blocks and don't want to add a keyword for looping. I am going to criticize the syntax though... bars? semantic newlines? A do which isn't vertically aligned with it's end? In the end, the following was always unclean:

    thing for thing in (x for x in y if z):
  • Dropping () {} - I can't decide whether I like this or not. On one hand, I really hate typing all of these crappy symbols while coding. On the other hand, it's annoying if you start a function call without (), and then decide you want to chain invocations or pass the result as an argument to another function. You'll have to go back and add them in again. After dealing with Objective-C's stupid smalltalk square brackets, I'm trying to decide what the best function call syntax would be. I suppose something like this:

    func1 arg1, arg2 .func2

    The idea here is that we want to end the argument list of first function call; this is usually done with the closing paren. It's really annoying to have move back over to func1 and add the matching paren, and clearly you can't have unbalanced parens, so I think a different symbol would be ideal.
  • Pervasive Metaprogramming - While metaprogramming is pretty cool, and I do like the rails magic functions, they have their downsides. Specifically if you are trying to find one, it won't be there in .methods.
The WTF
  • Why does calling a class method use the dot notation, but accessing a class constant use the name space operator ::?
  • Exactly why does my ubuntu install want to open .rb files with WINE? I don't even use WINE on this machine.