After a whole lifetime of ranting against it (cite, cite, cite, cite), I finally have to eat my words, come out, and say it: Ruby is the language of the future.
Now, I don’t specifically mean Ruby itself will be the most used language in the future, but I believe Ruby is the future now like C++ was the future in the 80s — all mainstream production languages that come next will be, at their heart, a Ruby derivative. And it’s easy to see why.
Those that have known me the longest shouldn’t find this announcement as a shocker. My programming career started in Perl. And while in Perl, I routinely used its features to meta-meta-meta-program, which allowed me to code at a high enough level that I both saved a lot of typing and guarantied my own job security. I left the Perl world for Java and pretty much stuck there, with occasional visits to dot-Net and OCaml. For a long while, I became enamored with static typing (cite, cite, cite), but through my work with Cornerstone and working with Scala, I’ve had a realization: every piece of static typing is, basically, intentionally getting in the programmer’s way.
Ruby’s beauty is that it doesn’t get in the programmer’s way. The type system is ultimately open — much like my beloved Perl — and that means that whatever the programmer wants to do is what the programmer can go ahead and do. Hell, even the private keyword isn’t a keyword at all, but a method (its documentation is here), and so if you wanted your code to go exhibitionist and dump its privates in public, all you need to do is override private to be an alias for public (but make sure to hook in early enough that you get your code run before the method you want to make public!). Sure, the developer who wrote the original code probably had a reason they wanted that code to be private, but a new programmer is driving this application now, and if the new programmer thinks it was a mistake, then why should the type system get in the way of retroactively fixing the library? Further, by fixing the library in application code, later upgrades to the library don’t need to be re-fixed: the one-time patch will automatically get re-applied by application code automatically!
[ Before I let the point go, the public/private by method bears one more point of praise: as a mathematician by training, the conceptual purity of everything being an object or method is extremely attractive. Okay, well, in Ruby only *almost* everything is an object or method (i.e. +.class fails), but that's one of those points that can get touched up in a later language. ]
The class-definition-as-script approach is another aspect of the type that I’m very fond of. Those who worked on my Perl projects know that I would regularly read configuration files and build objects dynamically based on that, including configuring behavior by overriding method definitions in the symbol table. In Ruby, things can work pretty much the same way. This is a mandatory kind of behavior for our enterprise environments, where things tend to work one of two ways: either they change so quickly that a normal code release cycle can’t keep up, or they are so restrictive that changes can’t be made to the code itself in a timely way. In both cases, since code is data, the normal release cycle can be completely undercut by storing code definition in the database (or an easy-to-change config file) and changing it there. The result will be a brand new and arbitrary configuration of code, but unit tests should have caught any problems that might come up.
Which brings us to the key change that I had to accept before my conversion: development is made up of unit tests and code tracing. Unit tests are basically the safety replacement for all those limitations that static typing places on the programmer. So unit tests need to be applied aggressively, but they need to be applied aggressively in any language. Given the Ruby type system, it’s simply not feasible to test all possible inputs and outputs, and YAGNI says that writing code to validate for those inputs is unnecessary until/unless they become a problem. This leaves us with writing unit tests only for the good usages (and the bad usages when we have a specific example): these tests are the easiest to write, because they’re most in line with how the developer is thinking when they’re in the flow. So this is another case where Ruby’s way of doing thing is most in line with the natural way a software developer works — FTW!
Now, detractors out there (like me yesterday) would argue that the lack of error checking leads to difficult (if not impossible) to understand messages and errors. While there is some validity there, the response to this is twofold: First, unit testing will isolate the particular line being called that, which at least tells you what you’re doing wrong, so you can stop doing it; Second, the fact that Ruby is not compiled means that it is easy to walk through the source in order to figure out what is going on. This means that you can dig into the library/framework you’re learning and really learn what’s going on, which is an educational opportunity. This difficult to understand message or error is a sign that you don’t really grok how your library/framework works, which you really need to do before you go ahead and just use it willy-nilly in your application! After all, that library could be redefining 1 to be 2 for all you know!
The last major complaint that people (like I was) have against Ruby is that it is basically unmaintainable over the long haul. I’ve admitted before that there’s less trouble on that front in Ruby than there was back in Perl, but I want to offer four more responses at this point. Three are in short form: one, any maintainability problem is obviously a failure of writing out your test specifications; two, the number of bugs per line of code is a constant, and so Ruby having fewer lines of code than Java means that Ruby has fewer bugs than Java; and three, the Ruby allows you to implement the big re-write with unprecedented speed — why bother maintaining all that old ugly code when it’s just as easy to rebuild it from scratch? The fourth point, however, is really where Ruby’s power shines: seeing as how the life expectancy of a Ruby gem (all the way from conception through hype to passe) is about 6 months, and whatever Rails app that’s being written should be bought by Twitter or Google or Amazon for $$$ within 9 months, then clearly maintainability isn’t all that important after all. The speed of writing the code is the only important part, because you don’t want someone to beat you to the punch!
I hope at this point it is clear that Ruby is the language for 21st century Real Programmers.
[ Edit: More on this at the post "Ruby is the Future 2".]
Related posts:
Pingback: April Fails or April Fools Epic Win? On “Ruby is the Future” | Enfranchised Mind
Pingback: Consumer-Developers and Contributor-Developers | Enfranchised Mind