Sunday, November 22, 2009

Learning Japanese, I Think I'm Learning Japanese ...

The gauntlet is thrown.

In my prior blog post about the disappointing contents of some of the sessions at day one of RubyConf 2009 (which is a great conference overall, btw; try to go next year!), I mentioned that some of the presentations were below a standard that I would have expected at the premier international conference for this language/community. As it happens, all of the presenters of the sessions I called out speak English as a second language, and they are all in fact Japanese.

In my defense, I was not talking about the presenters' English skills. Lord knows their English is better than my (heretofore non-existent) Japanese. As an American who has made a point of learning and trying to function in the native language of the countries I've visited (Germany, France, and Italy to-date), I have nothing but respect for anyone brave enough to go anywhere and speak in a non-native tongue to an audience of native speakers.

That's why I've accepted John Mettraux's gentle challenge to gain full perspective by submitting a proposal to RubyKaigi 2010, Japan's version of RubyConf. John assures me that I would not be expected to present in Japanese, but that strikes me as being less than "full perspective". So I'm going to try to learn enough Japanese to not make a total fool of myself (assuming my proposal is accepted). If any of the three of you reading this blog (hi, Mom!) has any ideas for good learning resources, please do let me know.

Ah, but a man's reach should exceed his grasp, Or what's a heaven for? -- Robert Browning

Friday, November 20, 2009

RubyConf Day Two: I Have Seen The Future, And It Is ...

MacRuby.

So day two of RubyConf went much better for me, content-wise. Caleb Clausen gave a subdued, but very interesting, presentation on Ocelot, his version of a Ruby compiler. Yehuda Katz brought down the house with his presentation "Polishing Rubygems", which was primarily about his project, Bundler. Andy Keep had a different take on the topic of partial evaluation to make Ruby more amenable to compiling. And Charlie Nutter was very engaging in his presentation with Thomas Enebo on the status of JRuby, including a cool demo of jirb running on an Android phone (simulator).

But my favorite talk by far was Laurent Sansonetti of Apple, talking about MacRuby. Laurent, who is clearly not a native English speaker -- are you reading this, jmettraux? -- gave a professional, content-laden presentation on MacRuby, which is pretty much his baby at Apple. He had some cool demos -- one of which was nearly thwarted by the hotel's abyssmal internet setup -- of MacRuby's integration with Cocoa/Objective-C, which also demonstrated that MacRuby has already solved the problem of compiling Ruby. XCode will build executables with the MacRuby framework embedded, and it will ship the MacRuby code as binary .rbo files, not Ruby source files. No need to obfuscate or simply give your code away; MacRuby takes care of it all.

Now if only we could get Apple to open up the iPhone to this. Or perhaps build a tablet of some sort ...

Thursday, November 19, 2009

RubyConf 2009: Day One

In a word: disappointing.

Oh, the venue (the Embassy Suites at the San Francisco Airport) is nice enough. And yes, there are problems finding power and getting on the internet, but that's to be expected. Anyone who attends a gathering of more than about ten people and actually believes the claims of abundant power and speedy WiFi for all is asking for a let-down. So it's not that.

Maybe it was just my bad luck in the sessions I chose to attend. I was very much looking forward to hearing some of the Ruby core team speak, so I made sure to catch Matz's keynote, "East meets West", and "Hacking parse.y", the latter being interesting to me in its own right since it was about Ruby implementation internals.

Matz has decent presence as a speaker, and the crowd dutifully laughed at all his good-natured, pro-forma digs at other languages' foibles (Java is lame. Lisp has too many parentheses. Et cetera.). But he didn't have anything particularly new or interesting to say about Ruby or language design, just that there can be no "one true" programming language, that the best we can hope for is one that's "close enough", and in his opinion Ruby is currently the best candidate. Go figure. Still and all, the man did invent the language that I currently use to make a living, so major props to him.

The other two were just not up to any reasonable standard for a conference at this level.

Look -- I know the Ruby community prides itself on being edgy. I get that RubyConf is deliberately kept small and scruffy and non-RailsConf-y. But is it really asking so much that the people who present talks at The Premier Conference for their language/community have some basic skill in the art of talking to an audience?

I did find the talk on using Ruby to write DSLs and code generation tools for hybrid systems simulation and scientific computing pretty interesting. And tomorrow's schedule looks good on paper.

Here's hoping it goes better than today.

Wednesday, November 18, 2009

Dear RVM: It's Not Me. It's You.

Dear Ruby Version Manager,

It's over. I tried. But I just can't do it any more. I though I could let you back into my life after that unfortunate 'sudo gem install rvm' spat we had on our first date. That's on me. But even after I moved you into my home directory, you still couldn't make it work.

I wanted it to work. Really, I did. I mean, a chance to have an open relationship with multiple Ruby's, all painlessly and seamlessly installed and switchable through you? Who wouldn't want that?

But you just couldn't handle my prior relationship with my self-compiled, self-installed /usr/local/bin/ruby, could you? I mean, you ... you ... it hurts just to type it ... you hijacked my $PATH, RVM! You locked me out of my gems! I mean, they weren't all switchable and fancy and all, they were just plain gems, but they were my gems, you know? How was I supposed to trust you after that?

Was it jealousy? Was it ignorance? I guess I'll never really know.

But -- for now at least -- I have to give you up. I have to lash myself to the mast of my virtual Argo, and forego your sweet, seductive siren song.

It's a pity. We could've been something, you and me.

Wednesday, October 14, 2009

Ruby's inject(): Putting the 'Fun' in 'Functional Programming' Since ... Oh, About 4:15 This Morning

Yesterday at work, I ran across the need to convert a number of seconds into its equivalent in days, hours, minutes, and seconds. The canonical imperative way to do this is something like:
seconds = 356521
days = seconds / (24 * 60 * 60)
seconds = seconds % (24 * 60 * 60)
hours = seconds / (60 * 60)
seconds = seconds % (60 * 60)
minutes = seconds / 60
seconds = seconds % 60
N.B.: This relies on Ruby's integer division -- dividing an integer by an integer results in an integer, with any fractional remainder discarded.

My pair and I ended up implementing something very much like this, but it left a bad taste in my mouth. I mean, it works and all, but it feels kind of ... non-functional. Ya know?

So, after much fretting and sleeplessness last night ... behold:
seconds = 356521

days, hours, minutes, seconds =
[1.day, 1.hour, 1.minute, 1.second].inject([]) do |acc, unit|
quotient, seconds = seconds.divmod unit
acc << quotient
end
This version needs to be run in a Rails script/console rather than irb, because it makes use of the Rails shortcut definitions of the number of seconds in various units of time. You could easily convert to plain irb-able Ruby by replacing 1.day et al above with their numeric equivalents.

The resulting code is both (more) functional, and more quintessentially Ruby-ish. divmod and multiple assignment let us figure out the quotient and the remainder of the division in one go, and inject lets us accumulate the results and ultimately multiply assign them to their respective units.

Neato.

I'm a little bummed, though, that this version has the side effect of destroying the original contents of seconds, as well as requiring seconds to be defined outside the scope of the inject. What would be really cool would be to have a version of inject that allowed for multiple accumulators (or, really, a 'decumulator' in this case) such that all side effects could be contained within the inject.

Wednesday, September 09, 2009

Fun With Metaprogramming: hash_initializer()

Earlier this week I was doing a code review for a candidate for ThoughtWorks. One of the bits I ran across was an object constructor that looked something like this:

class MyClass
def initialize(name, price, is_cool, is_neato, is_rad)
@name = name
# et cetera
end
end

Not so bad, really, when you're looking right at the signature for the constructor. But when it's called from another file...

MyClass.new("bob", "1.00", true, false, true)
MyClass.new("fred", "2.00", false, true, true)
# et cetera

... the purpose of the first two parameters may be easy to infer, but the last three? Which order were those descriptors in anyway? To really be sure, one has to keep referring to the class definition. In my review, I opined that perhaps the constructor should take a single argument -- a hash with keys named after the objects instance variables and their corresponding values. Thusly:

class MyClass
def initialize(args)
args ||= {} # in case MyClass#new is called without any args
@name = args[:name] || ""
# et cetera
end
end

This frees things up a bit, and allows for parameters to be specified in any order, with reasonable defaults for any that might be left out. It also makes calls to the constructor a little more self-documenting.

But what would really be nice would be not having to write out this boilerplate code for everything that we want this kind of constructor for.

Enter metaprogramming, in the form of hash_initializer -- a nifty little class extension I found in Brian Guthrie's Awsymandias library (as used at my current ThoughtWorks gig). Behold:

1. module ClassExtension
2.
3. if !Class.respond_to?("hash_initializer")
4. def hash_initializer(*attribute_names, &block)
5. define_method(:initialize) do |*args|
6. data = args.first || {}
7. data.symbolize_keys!
8. attribute_names.each do |attribute_name|
9. instance_variable_set "@#{attribute_name}", data[attribute_name]
10. end
11. instance_eval &block if block
12. end
13. end
14. end
15.
16. end
17.
18. Class.send :include, ClassExtension

Lines 5 through 12 correspond pretty much to my second version of MyClass#initialize above. Line 6 does the same defensive guard against a nil first parameter. Lines 8 through 10 pull each attribute, create an instance variable with the same name, and set it to the desired value. The extra bits? Line 7 does something I should have done in my "improved" version -- it forces the keys of the params has to be symbols, avoiding the awkwardness of blowing up when a key is a String when it should be a symbol or vice versa. Line 11 allows for the execution of a block along with initialization, if you're into that sort of thing. And the rest just opens up the class Class and makes Class#hash_initializer available to all objects.

With Class thus extended, the boilerplate for MyClass becomes simply:

class MyClass
hash_initializer :name, :price, :is_cool, :is_neato, :is_rad
end

And instantiating a MyClass stays what you would expect:

MyClass.new :name => "bob", :price => "1.00" # et cetera.

I like it.

irb(main):001:0> Class#hash_initializer.is_neato?
=> true

Monday, August 10, 2009

Code Artistry: The Negative Space

So I've been reading The Merb Way this week. I like it so far -- Foy Savas does a pretty good job of making his discussion of the technical internals interesting to read, and generally elevates the material above today's standard grind-it-out, dress-up-the-man-page-or-the-public-API-docs, tech book farce. Fare. I meant "fare".

One of the standout features of this book, though, that I'm finding myself drawn to is a marked lack of comparison between Merb and Rails. I can't tell if Savas intended this, but I find reading about, say, Merb's routing architecture easier to follow than if it were interrupted every other paragraph by an "as compared to Rails, which does this..." interlude. I'm not sure many other authors would have avoided that trap as neatly.

If you think about it, it's a sensible approach to take, although maybe not the most obvious one. If I'm reading a book on Merb, what I want to read about is ... you know ... Merb. I may already know some of the internals of Rails. I may not. If I do, chances are that I will make those comparisons myself. If I don't, chances are a constant barrage of interruptions would just turn me off of Merb, and possibly Rails too. Either way, interleaving a discussion of Rails within a discussion of Merb would be counterproductive.

Reading this book makes me wish more of us technologists would learn the value of the artistic concept of the negative space -- the bizarre and intriguing shapes formed *between* the familiar ones that are the nominal focus of the picture. That what the artist leaves out can contribute as much to the picture as what he puts in. Sometimes more.

I was going to write out a list of how this concept applies to and enhances other artistic and quasi-artistic disciplines like architecture, music, literature, and film-making.

But now I'm not. :-)

Monday, February 16, 2009

Recommended Reading: Flex on Rails (Addison-Wesley)

Disclaimer: Addison-Wesley sent me (unsolicited) a review copy of this book at no charge, with the tacit assumption being that I would read it and review it publicly. There are no conditions, however, on the content of said review. What you are about to read is my unbiased, unvarnished take on this book, written to inform you, not to curry favor with the publisher or the authors. Also, I do not have any business relationship with any of the parties involved in the publication of this book; I will not gain in any way if you choose to buy it. But, as it happens with this book, I believe you will gain if you choose to buy it. Here's why:

The Good

Flex on Rails, by Tony Hillerson and Daniel Wanja, does many important things right, tech-book-wise, which I find astonishing; more so given that it's the first book by both authors. The material strikes an effective balance between easy-to-absorb and useful-in-real-life, without spending too much time at either extreme, and -- mercifully -- no time at all in "Hello World".

Aside to would-be (and a lot of already-are) tech book authors: Read Chapter 1 of this book -- all seven pages of it -- to see how it's done. Notice how much (read: "how little") time and print is expended on rehashing yet again the minute details of installing Ruby, RubyGems, Rails, and other requirements. This is not one of those books that has chosen to pad its page count by wallowing in the comfort zone of a twenty-page "Getting Started" tutorial.

Chapter 1 sets the tone. Subsequent material flows naturally, and never overwhelms. Chapters 2 and 3 combine effectively to introduce the concepts of Flex and Rails' use of XML and REST to communicate betwixt themselves, but without the seemingly-obligatory over-exposition of the history and motivation of either XML or REST.

The authors introduce testing early on (Chapter 4); not quite TDD, but not bad either, for a tech book. A brief detour into RubyAMF (Chapter 5) follows, and then we get another key topic, Debugging (Chapter 6), early enough to be useful but not so early as to be overwhelming.

Throughout this first part of the book, the authors assume a fair amount of Rails knowledge/experience. For example, Chapter 2 ("Passing Data with XML") jumps right in with a sample Rails app, complete with (minimal) scaffolding and a simple database migration. Rather than bog the reader down with minutiae, as far too many other tech books do, this material is presented with an unforced, matter-of-fact tone that assumes reader familiarity, but doesn't condescend. Now I concede that I'm an experienced Rails developer, so I take this stuff for granted. But I believe that someone new to Rails would not be overwhelmed. And -- key point here -- there are other, better resources for learning about Rails' scaffolding and migrations. An ill-timed dissertation here would just turn off seasoned developers entirely and distract any new kids in the audience. Good for Tony and Daniel (and whatever wise editors they worked with) for avoiding this all-too-familiar trap.

The second half of the book demonstrates another key concept that too many tech books don't bother with, and one that I think this team just nailed: Flex on Rails is not an introductory tutorial, and it's not an advanced recipe book: it's both! Each of Chapters 10 through 22 presents a solution to a problem that is very likely to crop up in any real-world usage of this technology. To name a few:

  • Source Control (Chapter 10), including Subversion and Git

  • Deployment (Chapter 12), largely with Capistrano

  • Authenticating (Chapter 15)

  • Communicating between Flex and JavaScript (Chapter 21)

  • File Upload (Chapter 22)


I've saved mentioning my favorite chapter for last, and I think it is just way too cool that it's in the book, because it reflects a personal mantra of mine -- Chapter 13: "Read the Source!" I am constantly preaching this, whether it's Rails, or Capistrano, or JRuby, or even Ruby. Open source software is a treasure trove of HOWTO: Write Code in all its glory. It is a cornucopia, constantly replenished by the experience and learnings and mistakes and refactorings and holy wars of a horde of extremely bright and capable programmers. Is it sometimes flawed? Sure. But it's there. And it's the best source of education in computer programming -- both how to and how not to -- that you have available to you. Use it.

The Bad

Not a lot to write here. I've long since ceased to be as outraged as I used to be about the computer publishing industry's contempt for (okay -- let's be charitable and call it "indifference towards") the English language. Let's just say I won't be letting my son use this or any tech book as a primer in either spelling or grammar. This book is not as bad as some, but it still has its share of sloppy copy editing -- typos here, unfortunate typesetting choices there (primarily inconsistent/inadequate use of fixed-width fonts or otherwise visually highlighting stuff that's best viewed as code and not prose).

The Meh

For a book that seems to have been designed deliberately to respect its target audience's intelligence and skill level, Chapter 8 ("Flex MVC Frameworks") takes a bit of a detour into Probably Should Be Obvious Land in its coverage of the Model-View-Controller paradigm. Yes, it's in the context of describing how Cairngorm and PureMVC specifically do MVC, but come on -- it's MVC. Even here, though, the authors rise above the average tech book experience, by implementing the same app using both frameworks, so you can compare and contrast and maybe get a sense for which framework fits your needs better.

Gratuitous Name-Dropping Reference

Tony Hillerson and I worked on a Rails project (my first) together a few years ago, and even then he was valiantly (but alas, in vain) trying to convince his partners to let us use Flex for the UI. I'm glad to see him realizing that dream and in fact thriving on it. I've met Daniel briefly, at the Pragmatic Studio's Cocoa Programming class in Denver, but I don't think he knows who I am. Other than that, I have no business relationship with either, and I do not stand to benefit in any way from the sales of their book. But, as I said in my disclaimer above, I believe that you will benefit from buying it. Let me know if you do. And let me know how it goes.

Saturday, January 10, 2009

A Gem Is Born: Announcing Gemviz

Final (potentially) update: Now appearing on github:
git://github.com/davidrupp/gemviz.git

Update to first update: I realized that I did not specify a gem dependency on ruby-graphviz in my hoe-generated Rakefile. This is in place as of version 0.1.2.

To quote Groundskeeper Willie in The Simpsons - Treehouse of Horror V: "Och, I'm bad at this!"

We now return you to the first update.

Update: Peter Cooper correctly points out in his comment that Gemviz has a hard dependency on Graphviz, which isn't installed by default on Macs. I tend to take it for granted because it's one of the first things on my checklist to install when breaking in a new Mac. I use The Mac OS X Edition of Graphviz, as referenced on the Graphviz home page.

We now return you to the regularly scheduled original post.

Original Post: I can't really call myself a hotshot Ruby programmer until I release a RubyGem, now can I? Well, I still won't call myself a hotshot Ruby programmer yet...but, as of today -- and the release of versions 0.1.0 and 0.1.1 (for documentation purposes) of my new gem gemviz to rubyforge.org -- at least I'm one step closer!

Check it out, yo:
[sudo] gem install gemviz
Now you can do e.g.,
gemviz rails
(assuming you have Rails installed as a gem which, if you don't by now: huh?), which produces this graph on my system:


In fairness, I should disclose that Gemviz is only about 30 lines of code, and makes heavy use of other people's work to do its magic. Here's how it works:

* it scrapes the output of the system command gem dep gem_name --pipe.
* for each dependency thus listed, it adds that dependency to the list of dependent gems.
* it does the same recursively for each dependent gem until it finds that the current gem has no dependencies, or that some (recursively) dependent gem is not installed on the system.
* it builds a Graphviz graph from the graph so built.
* it runs the awesome tred utility on the resulting Graphviz graph, which translates the original messy graph into one that properly represents all of the transitive dependencies.

If you're not sure what that last bit is about, don't feel bad: I didn't either at first. So here's the picture that's worth a thousand words (give or take):

The difference is subtle, but telling. The second graph shows that the rails gem has dependencies on activesupport and actionpack. Which is true, as far as it goes, and is reflected in the output of the gem dep command thusly:
gem dep rails
Gem rails-2.2.2
rake (>= 0.8.3, runtime)
activesupport (= 2.2.2, runtime)
activerecord (= 2.2.2, runtime)
actionpack (= 2.2.2, runtime)
actionmailer (= 2.2.2, runtime)
activeresource (= 2.2.2, runtime)

But it turns out that gem dep doesn't tell the whole story. rails does depend on those other gems, but only through its dependencies on activerecord, actionmailer, and activeresource, as shown in the first graph. That's what the tred utility (part of the Graphviz package) does: reduce the second graph to its minimal equivalent representation in the first graph.

Here's another more fun example, for merb, prior to transitive reduction:


And post tred:

This implementation owes much to the existing DepGraph, especially its use of Graphviz and tred. I basically just extracted the simple use case of graphing a gem at a time, and neglected to implement a bunch of DepGraph's options. For instance, the output of gemviz is always a single .png file per requested gem, named after the gem and placed in the current directory.

Keep in mind that this is a very simple initial release. Please let me know if you find it useful, and especially what improvements you can think of.