“Cargo Culting in ruby”
July 4, 2008
“Cargo culting”, when used in a computer-programming context, refers
to the practice of using techniques (or even entire blocks of code)
seen elsewhere without wholly understanding how they work. (The term
“cargo cult”, if you are unfamiliar with it, has its own fascinating
etymology, which is covered nicely at wikipedia.)
Cargo culting is a dangerous phenomenon, watering down the state of the
art and encouraging cookie-cutter code shoved blindly into black boxes.
Consider
the following snippet of code, taken from a project that was submitted
to us some time ago. (Alas, I cannot find the original submitter—I
apologize for that!)
1<tt><br /></tt>2<tt><br /></tt>3<tt> </tt></pre></td> <td class="code"><pre><span class="r">def</span> <span class="fu">account_code?</span><tt><br /></tt> !! <span class="iv">@account_code</span>.nil?<tt><br /></tt><span class="r">end</span><tt> </tt></pre></td> </tr></tbody></table> <p>To me, this looks cargo-culted, since it is seems that the programmer did not understand what the ”!!” idiom was all about. They probably saw it used somewhere and “cargo culted” it, using it without knowledge, assuming that it was, for some reason, “necessary”.</p> <p>Now, the way ”!!” works is this: take the value behind the ”!!”, negate it, and negate it again. It’s just double-negation: <code>!(!(@account_code.nil?))</code>. The ultimate effect is to take some value, and convert it into an honest-to-goodness “true” or “false”. (In my ever-so-humble opinion, the ”!!” idiom is an abomination: it’s far too clever for its own good. First of all, you rarely ever need a real boolean value, and for those times you do, it is better to be explicit in the conversion, by using a ternary operator or full-blown <code>if</code> statement, for instance.)</p> <p>In other words, the double-negation of <code>nil?</code> results in absolutely no difference from the use of <code>nil?</code> by itself, since <code>nil?</code> will return a true/false value. This, in turn, means the effect in the original is actually not what was intended for the <code>account_code?</code> predicate. It should have returned “true” if the account code existed (was “non-nil”), not “false”. Thus, the method should have actually been written thus:</p> <table class="CodeRay"><tbody><tr> <td title="click to toggle" class="line_numbers"><pre>1<tt><br /></tt>2<tt><br /></tt>3<tt> </tt></pre></td> <td class="code"><pre><span class="r">def</span> <span class="fu">account_code?</span><tt><br /></tt> ! <span class="iv">@account_code</span>.nil?<tt><br /></tt><span class="r">end</span><tt> </tt></pre></td> </tr></tbody></table> <p>In this case, cargo-culting resulted in the code being buggy. This is not an uncommon outcome of using techniques or code without understanding their purpose. If you ever find yourself copying something into your own code, with a justfying “I-don’t-know-what-it-does, but-it-appears-to-work”, <em>stop immediately</em>. Do some research. Figure it out. Learn what it means.</p> <p>Further, note that unless you actually <em>need</em> a true boolean value from that, you can shorten the implementation of the <code>account_code?</code> predicate even further:</p> <table class="CodeRay"><tbody><tr> <td title="click to toggle" class="line_numbers"><pre>1<tt><br /></tt>2<tt><br /></tt>3<tt> </tt></pre></td> <td class="code"><pre><span class="r">def</span> <span class="fu">account_code?</span><tt><br /></tt> <span class="iv">@account_code</span><tt><br /></tt><span class="r">end</span><tt> </tt> |
This works because Ruby treats nil and false as false, and everything else as true.
If there is one thing that Koz and I want you, our readers, to come away from this site with, it is an understanding of why
you should do things one way and not another. Ultimately, it makes the
difference between being a mediocre programmer, and becoming a great
programmer.
Entry Filed under: Cargo Culting in ruby, rails, ruby on rails. Tags: Cargo Culting in ruby, rails, ruby on rails.
Trackback this post | Subscribe to the comments via RSS Feed