Skip to content

Phenomenal Cosmic Power

Jeff Atwood thinks monkeypatching should frighten you:

But if wielding that power doesn’t scare and humble you a little, too, then maybe you should leave the monkeypatching to the really smart monkeys.

Reg Braithwaite thinks it should exhilarate you:
And ultimately, that is what this line of code says to me about Ruby. It says that this is a language where the fringe is inventing new things. And to embrace ruby is to embrace the idea of a language being propelled by its user base.

I’m okay with either reaction. Metaprogramming may be pure and godlike, but then again, thou art God. It’s the people who have no reaction whatsoever that scare me. Use of power should be conscious and intentional. Otherwise you’re like a woodworker who addresses a mismatched joint by just hammering harder.

Revision-Stamp Your Rails Apps

One of my biggest pet peeves in doing QA is when I spend half a day trying to track down why a bug I thought I’d fixed has cropped up again, only to discover that the reporter was looking at an old version of the application. Good revision tracking is vital to doing efficient QA. Here’s a little trick for removing any uncertainty about what version of the app you’re looking at.

Capistrano, after it exports an application from an SCM repository (such as a Subversion repository), writes an extra file to the application’s root directory. The file is named “REVISION”, and, as you might imagine, it contains the revision number that was exported. Displaying this information in your application’s UI is straightforward. Here’s the addition I made to a view partial that is displayed on the application’s home page:

  <p>Application revision <%= app_revision %></p>

And here’s the app_revision helper method:

module ApplicationHelper
  # ...
  def app_revision
    revision_file = File.join(RAILS_ROOT, "REVISION")
    if File.readable?(revision_file)
      IO.read(revision_file)
    else
      "unknown"
    end
  end
end

Of course, this isn’t very efficient – it will re-load the file every time a page is rendered. Optimization is left as an exercise to the reader. But it accomplishes its purpose: now whenever someone reports a bug in the app, I can ask them to go to the application home page and tell me what the revision number is. No more trying to remember whether I pushed out the latest changes to the beta server.

Epic Fail, or, why the users hate us.

[I’m reposting this from my personal journal as it has development applicability – in so much as it is a tale about how NOT to design software.]

So I’ve been trying to wire money to Kenya. No, I haven’t been contacted by the wife of a former dictator who needs my urgent assistance in moving large sums of money. Just doing someone a favor.

I go to the website. I’ve used it before, so I figure I’ll log in to my account. Try to log in with my usual credentials. Uh oh.

W0500 Sorry you’re having trouble. Please try again later.

This does not bode well. I’m having trouble? News to me. And if the trouble is on my end, what good will trying again later do? Are they suggesting that I am having brain issues which will resolve themselves in a few hours?

OK, assume this is just their eccentric way of saying “login failed”. I have a dim recollection of not being able to use one of my regular passwords because they don’t allow special characters in their passwords (why is it always institutions which handle large sums of money that have poor password policies?) Email customer service, and meanwhile, click the “retrieve password” link. Notice while emailing customer service the lengthy backlog of previous Western Union customer service mail from the last time I tried to wire money through them. Oh dear, I must have blocked those memories.

OK, well, chin up and keep trying. While waiting for customer service, hit the “forgot password” link. Go through the first step, email address, date of birth… that’s odd. This is probably the first site I’ve ever seen where the “Date of Birth” field is a password-style field. Presumably so no potential identity thieves peering over my shoulder witness that top-secret information, and I have to go through all the hassle of changing my birth date to something new.



Anyway, moving on, ah, the Security Question.  OK, what’s it going to be – good ole’ mother’s maiden name?  First pet?  Model of car in which I first got to third base? Nope, not good enough for Western Union security.  They’ve gone the extra mile and required me to guess the question before supplying the answer. Now that’s secure!



Email customer service again. Looks like there’s a response to my first query already.  They are prompt, I’ll give them that.  Let’s see…

We apologize for the inconvenience, due to security reasons the system blocks the access after 2 or more unsuccesfull attempts.

Reply to customer service informing them that that’s nice, but this happened the very first time I’d logged in in months.

Oh look, a reply to my second problem.  They sure are on the ball over there.

We apologize for any problems you experienced with our site. However, if you are not being able to sign in with your current e-mail address and password, we may offer to deactivate your account so you may register again. Please keep in mind that no one at Western Union knows or can retrieve your password for you. If you wish to have your account deactivated, please send your request in an email to messaging@westernunion.com from the email address you used when you registered, and include your registered name, address and telephone number. Please note that if you have another e-mail address, you may use it to create a new account.

Ah, form letters detailing how to work around the flaws in the system.  Always a promising sign.

OK, let’s try setting up a new account under a different email address.  Let’s see, click “Sign UP”, enter name, rank, and serial number.  Like nearly every user interaction page in this system, the page has a CAPTCHA at the bottom.  Except this CAPTCHA has a difference: there’s no CAPTCHA, just the alt text.



Click little “reload” icon, no good.  Click the “audible captcha” icon – leads to a blank page.  I think they’ve hit upon an unbeatable anti-spam strategy here – a CAPTCHA you have to interpret via mental telepathy.

Deep breath.  Let’s take a time out and check our email, shall we?

Unfortunately, your e-mail has arrived blank.  Please resubmit your question or comment and we will be happy to assist you. Also, please keep in mind that we are unable to view attachments, enclosures, or hyperlinks.

Looks like they left something out of that list of things they are unable to view – replies to their own useless boilerplate messages.  It appears that Western Union has adopted the time-tested “hear no evil, see no evil”  approach to technical support.  If the techs can’t view the problem, it doesn’t exist!

While we’re checking email, let’s email them about their amazing vanishing CAPTCHA.  Prompt reply, as usual.

Usually when this happens, it is because of problems with the server. You may wish to double-check your Internet settings, or try again later. Please note that our site works best with Internet Explorer version 6.0. We are currently not compatible with Mozilla, Firefox nor Safari.
Western Union, after doing a costly internal audit to discover where their inefficiencies lay, discovered that 99% of their problems with online transactions stemmed from those annoying customers.  Excluding 20-30% of the web browsing population by limiting the web site to IE6 compatibility neatly alleviated the problem, and the assistant vice-president who thought of the idea was immediately promoted.  He is now working on a grand enterprise-wide plan to enhance the customer experience by requiring all requests to be submitted on Sumerian cuneiform tablets.

So let’s review.  I can’t log in.  I can’t reset my password. And I can’t register a new account.  Well, we gave it our best shot. Time to fall back on ye olde reliable wireless telephone.

Call Western Union… you can probably guess by now where this is going.  I’ll spare you the play-by-play and sum up.  I called, I punched in my information. I was put on hold for 15 minutes while screechy distorted musaak drilled slowly into my ear canal.  Then they disconnected me.  I called back and discovered that while I was on hold they had helpfully cancelled my transaction.  I spoke to a manager, re-started the transaction.  Gave them all my information over again, then sat on hold for another ten minutes or so.  Finally, after a total of 50 minutes on the phone, they informed me that my transaction had been rejected by the ineffable machines which sometimes grant, and sometimes deny, and no one can say why… for security reasons.

EPIC FAIL.

Does anyone know of a method for transferring funds overseas that doesn’t leave one with an urge to bash one’s forhead repeatedly into a concrete post?

You should be on ruby-talk

Working as I do in the Rails world these days, I’m periodically reminded of the difference between me and most Rails programmers. That is, the fact that I came to Rails via Ruby, rather than vice-versa. Usually this happens when someone at work or in the blog world expresses delight (or perplexity) about some Ruby feature that I thought everyone knew about. This then prompts me to put on my best “old coot” voice and ramble on about “young whippersnappers” with their Rails and their fancy conferences and their big pants and… get off my lawn, ya darned kids!

One of the biggest disconnects for me is the fact that almost no one I know in the Railsverse reads ruby-talk regularly. Having gotten into Ruby somewhere between five and seven years ago, it’s difficult for me to imagine being a part of the Ruby community and not being privy to the discussions in ruby-talk. Ruby-talk was one of the first programming communities I ever regularly participated in (the other one was the Pragmatic Programmer mailing list). It was a warm and welcoming place compared to, say, the Perl communities of the time; full of the spirit of joyous discovery and show-and-tell that this amazing new language from Japan tended to inspire.

The S/N ratio has declined somewhat since some joker hooked up a conduit between ruby-forum and the mailing list, leading in a steady stream of Rails newbies who have it confused with the RoR forum. But it’s still one of the friendliest and most helpful programming communities out there. And nowhere else – not on blogs, not on Reddit, nor on Twitter – will you find better and more thoughtful discussions on Ruby style, idioms, alternate ways of accomplishing tasks, gotchas, and just plain fun Ruby tricks. And, because new Ruby libraries and frameworks are usually announced there, it’s also a great place to find out about what’s going on in the wider Ruby universe – beyond Rails, beyond web development entirely.

I’m going to make a bold statement here:

If you are a developer working in Ruby, you should be reading ruby-talk.

No, let me amend that:

If you are a developer working in Ruby, you should be reading contributing to ruby-talk.

Because apart from being a great place to pick up new techniques, it’s also one of the easiest opportunities to give back to the Ruby community. Check in from time to time, and if a newbie asks a simple question you know the answer to, help them out! It takes five minutes, and it helps perpetuate the culture of supportiveness that is a big part of what makes Ruby so special.

It’s easy to get involved with ruby-talk. There are multiple interfaces. There is the mailing list itself, which is how I interact with it. Then there is the mail-to-news gateway, which enables you to read it as the Usenet newsgroup comp.lang.ruby. You can get to it through Gmane if your ISP doesn’t provide NNTP service. Or you can interact via the Google Groups frontend. And finally, there’s the aforementioned ruby-forum gateway.

Whichever route you choose, I hope to see you on ruby-talk soon!

Everything Old…

A passage in Charles Nutter’s reaction to MagLev caught my eye today:

First off, they demonstrated its distributed object database automatically synchronizing globally-reachable state across multiple VMs. It’s an amazing new idea that the world has never really seen…
except that it isn’t. This is based on existing OODB technology that Gemstone and others have been promoting for better than a decade. It’s cool stuff, no doubt, but it’s been available in Gemstone’s Smalltalk product and in their Java product for years, and hasn’t seen widespread adoption. Maybe it’s on the rise, I really don’t know. It’s certainly cool, but it’s certainly not new.

True enough. But what really is new in software development, anyway? Quite a few people have noted that the feature sets of modern programming languages are gradually converging on the feature set of Lisp, a language that is over fifty years old. Ruby itself has been around as long as Java, believe it or not. And Ruby is essentially a Perl-ish syntax veneer over Smalltalk, a thirty-year-old language.

Why does Ruby seem to be succeeding in ways that Smalltalk didn’t? Well first of all, Smalltalk did have a fair amount of success in it’s time. It remains to be seen whether Ruby will have better staying power. My guess, though, is that it will. The momentum Ruby has accumulated is pretty impressive.

Why? I can think of a lot of possible reasons. Ruby came of age in a time when Moore’s law had finally made the trade-off in increased development productivity versus relatively slow execution time economically justifiable. The primary Ruby implementation was free and open-source, not proprietary. For that matter, Ruby matured during a time when the Open Source community was exploding into relevance and even dominance, as opposed to the proprietary dominance of previous decades. And Ruby arrived at an inflection point in software development, a time when developers were still finding their legs on a new platform (the Web); and a new Web framework using the power of Ruby to accomplish Web programming tasks more easily had the opportunity to revolutionize the industry.

It could have been some combination of the above, or it could have been other factors entirely. Whatever the reason, a ten year old language based on thirty year old technology suddenly took off. Now turn to the field of data storage: developers are looking at novel new(?) document-oriented systems like CouchDB and StrokeDB, despite the fact that SQL is The Standard. Coders primed by Ruby and Rails to look to unfamiliar sources for solutions are questioning the conventional wisdom in other areas as well. Maybe it is time to reconsider the much-maligned OODB as well.

I guess the point I’m getting at, if there is one, is that sometimes the best new idea is an old one reconsidered in the light of current needs.

The Lotus Desk


I’ve been increasingly dissatisfied with office chairs both at the office and at home lately. I just can’t seem to find a configuration that gives me the back support I need for hours-long coding sessions. I’ve considered joining the standing-desk crowd but I’m not sure that would be any more comfortable.

If there’s one thing I’ve learned from meditation it’s that the lotus (or half-lotus) position is remarkably stable and conducive to good posture over extended periods of time, at least for me. Combine that knowledge with a beautiful sunny day, and voila, the Lotus Desk. I still need to work out a few kinks, but I think I could get used to this. I wonder if I can find someone to do some custom woodwork for me…

Rock’em Sock’em Ockham

Inspired by this talk by Jim Weirich:

Image by scottfeldstein, some rights reserved.

(For the shaving nerds, this poster features the Merkur Hefty Classic, a razor I recently acquired and am so far pretty happy with.)

On Beauty in Code

I was thinking about the topic of beautiful code this morning. There’s a lot of disagreement about what constitutes beauty in code. I’ve watched Marcel Molina Jr. talk about Plato and Pythagoras. O’Reilly has published a whole book on the subject. On the other hand, Jeff Atwood thinks that there’s no such thing.. I disagree with Jeff on this – I definitely think there is such a thing as beautiful code. But I’m not sure if my idea of what makes code beautiful is the same as others’.

What do I even mean when I say something is “beautiful”, anyway? Beauty is in the eye of the beholder, after all – there is no objective standard. For my purposes, I consider something beautiful when it triggers a certain emotional response. A flower is beautiful because I enjoy the simple act of observing it for its own sake.

When it comes to functional human-created objects, I’ve noticed that certain properties tend to trigger this emotional reaction. Here are a few products I find beautiful:

These are all products which are extroardinarily well engineered for their respective tasks. Out of that engineering emerges a kind of clean, austere beauty. I guess you could say my esthetic runs toward the Bauhaus school of thought.

By contrast, a lot of the code I have seen held up as “beautiful” has more in common with MC Escher or a Zen garden. In the case of the former, the beauty is all about intricate, brain-twisting cleverness. In the latter case, divine purity of expression takes precedence over more worldly concerns.

To me, beautiful code – code that I can enjoy reading for its own sake – has the quality of expressing its function simply and clearly. Like a Mag-Lite, its form reflects its function in a way that is elegant, straightforward, and easy to grasp.

One of the projects that has recently impressed me as having this property in its code is the Ramaze web framework. The Ramaze source code is clean, straightforward, well-commented (but not excessively so). Most methods are only a few lines long, and the lines themselves are short. White space is in abundance, setting off stanzas of code. And the logic itself is usually easy to follow.

Routing is traditionally a thorny area in web application frameworks. Here is the Ramaze routing code, in its entirety (minus some documentation):

#          Copyright (c) 2008 Michael Fellinger m.fellinger@gmail.com
# All files in this distribution are subject to the terms of the Ruby license.
 
module Ramaze
 
  class Route
    trait[:routes] ||= Dictionary.new
 
    class << self
      # Retrieve key from trait
      def [](key)
        trait[:routes][key]
      end
 
      # Set key to value in trait
      def []=(key, value)
        trait[:routes][key] = value
      end
 
      # remove all routes
      def clear
        trait[:routes].clear
      end
 
      # Resolve path according to routes.
      def resolve(path)
        trait[:routes].each do |key, val|
          if key.is_a?(Regexp)
            if md = path.match(key)
              return val % md.to_a[1..-1]
            end
 
          elsif val.respond_to?(:call)
            if new_path = val.call(path, Request.current)
              return new_path
            end
 
          elsif val.is_a?(String)
            return val if path == key
 
          else
            Log.error "Invalid route #{key} => #{val}"
          end
        end
 
        nil
      end
    end
  end
 
  # Shortcut for defining new routes.
  def self.Route(name, &block)
    Route[name] = block
  end
end

There is only one method of any length, #resolve. And that method has an easily recognizable cadence – if path matches some predicate, then perform some transformation, and return. Else move on to the next clearly-delineated stanza. This is another quality of beautiful code: each method body has a recognizable, almost archetypal “shape” which is not littered by special cases and digressions.

If you enjoy reading code, I recommend taking a stroll through the Ramaze source code. It is very nicely presented online in a custom source browser. And most of it demonstrates a similar clean elegance to the code above.

So that’s an example of what beautiful code means to me. What about you? What code do you consider beautiful?

Sustainable Development in Ruby, Part 3: Delegation

In our last episode we were augmenting FMTP::Message classes to deal with messages split across multiple packets. As is often the case, fixing one problem revlealed another. What with the unstable weather patterns in Oz – you never know when a spacetime-ripping tornado will appear out of nowhere – our flying monkeys sometimes get blown off course, and arrive out of order. This results in jumbled messages and angry Wicked Witches.

We’ve submitted a revised FMTP RFC to the Flying Monkey Transport Protocol Working Group, but it’s anyone’s guess how long that will take to become an offcial recommendation. Until then, we’ve taken to embedding another bit of metadata in the message text itself. Messages now look like this:

  {{3 OF 5}}
  .... MESSAGE TEXT ...

In order to work conveniently with these enhanced messages, we need some new accessors on the FMTP::Message class:

  1. A revised #end? method which uses the new header instead of the now-deprecated “ENDENDEND” token.
  2. A new #seq_num accessor to tell us which message in a multi-message sequence this is.
  3. A new #total_num accessor to tell us how many total messages are expected as part of the sequence.
  1. A modified #data accessor which will return just the message data, minus the message ordering header.

Sounds like it’s time to inject some more methods. But not so fast. I prefer to use the inject method pattern when I only need to add one trivial method. When I need to add or modify more than one method, a few other techniques are better suited. One of the most powerful techniques is delegation.

Delegation has a long history of use in object-oriented languages. In some languages using it can be quite labor-intensive to implement. In Ruby it is so trivially easy that it’s a little surprising it isn’t used more often.

Here’s an example of a delegate class that implements the requirements above:

  require 'delegate'
  class OrderedMessage < DelegateClass(FMTP::Message)
    HEADER_PATTERN = /\{\{(\d+) OF (\d+)\}\}/
 
    def seq_num
      @seq_num ||= matches[1].to_i
    end
 
    def total_num
      @total_num ||= matches[2].to_i
    end
 
    def data
      # Implemented this way to demonstrate use of 'super'
      @data ||= super.gsub(HEADER_PATTERN,'').strip
    end
 
    def end?
      seq_num == total_num
    end
 
    private
 
    def matches
      HEADER_PATTERN.match(__getobj__.data)
    end
  end

We use this class by replacing the line that previously read:

  message = extend_message(super)

With this code:

  message = OrderedMessage.new(message)

There are a few things worth noting about this approach:

  1. Using a delegate gives us a safe namespace sandbox to play in. This code defines four methods, a constant, and three instance variables. In particular, note that we define our own @data instance variable. If we were monkey patching, or even subclassing, FMTP:Message, we would run the risk of inadvertently overriding or overwriting one of the FMTP::Message constants, methods, or instance variables. With delegation, however, we can define pretty much anything we want without having to be concerned with collisions.
  2. Note that #data uses super to delegate to FMTP::Message, just as if we were writing a subclass. This is a convenience of using the standard delegate library.
  3. [NEW] While it’s not really demonstrated in the code above, I should point out that any FMTP::Message methods not explicitly overridden on OrderedMessage will be delegated directly to the wrapped FMTP::Message object.
  1. An added benefit of using the delegate pattern is that it is very easy to test our additions to FMTP::Message in isolation. Here is the actual RSpec spec I used to develop the code above:
  describe "any ordered message", :shared => true do
     it "should have the correct sequence number" do
      @it.seq_num.should == @m
    end
 
    it "should report the correct total of messages" do
      @it.total_num.should == @n
    end
 
    it "should have the correct data" do
      @it.data.should == @payload
    end
  end
 
  describe OrderedMessage do
 
    def construct_test_data(m, n, data)
      <<-END
  {{#{m} OF #{n}}}
  #{data}
  END
    end
 
    def make_message
      @data = construct_test_data(@m, @n, @payload)
      @base_message = stub("Base", :data => @data)
      @it = OrderedMessage.new(@base_message)
    end
 
    describe "given message 1 of 3 with data FOO" do
      before :each do
        @m       = 1
        @n       = 3
        @payload = "FOO"
        make_message
      end
 
      it_should_behave_like "any ordered message"
 
      it "should not be the last message" do
        # Using '@it.should_not be_end' interacts badly with DelegateClass
        @it.end?.should_not be_true
      end
    end
 
    describe "given message 3 of 5 with data BAR" do
      before :each do
        @m       = 3
        @n       = 5
        @payload = "BAR"
        make_message
      end
 
      it_should_behave_like "any ordered message"
 
      it "should not be the last message" do
        # Using '@it.should_not be_end' interacts badly with DelegateClass
        @it.end?.should_not be_true
      end
    end
 
    describe "given message 4 of 4 with data BAZ" do
      before :each do
        @m       = 4
        @n       = 4
        @payload = "BAZ"
        make_message
    end
 
      it_should_behave_like "any ordered message"
 
      it "should be the last message" do
        # Using '@it.should_not be_end' interacts badly with DelegateClass
        @it.end?.should be_true
      end
    end
  end

Using delegation to extend FMTP::Message, we don’t need to instantiate an actual FMTP::Message object in order to test our modifications. All we have to do is stub the methods of FMTP::Message that we actually use in the delegate. This can be a real win when we are working with a third-party library which has extensive and/or poorly-documented dependencies.

Applicability

Consider using delegation when:

  • Vendor code controls instantiation of the target.
  • Your code is the primary client of the target.
  • You need to make more than one addition or modification to the target’s interface.

Caveats

Be aware that delegates produces with the delegate library are not perfect stand-ins for their target objects. In particular, by default the delegate object will have a different id and object_id. This is easy to correct, but you should be aware of it, especially when working with ActiveRecord, which uses id to associate objects with rows in the DB.

Why Your Social Website Should Support OpenID

On Twitter I bitched about GitHub not supporting OpenID, and both Chris Wanstrath and Giles Bowkett chided me for not making an better argument for it than “it makes my life easier”.  The benefits of OpenID seem self-evident to me; but if I have to spell it out, here goes.

When I go to a site that supports OpenID:

 
  • I don’t have to spend even a millisecond wondering about how good their password security protocols are. With OpenID, they will never see my password.
  • I don’t have to weigh whether to use one of my standard web passwords.
  • I don’t have to make up a new password and remember to write it down somewhere.
  • I don’t have to use some 3rd-party program or Firefox extension to generate and manage random password, only to be locked out when I have to access the site from a public terminal and my thumbdrive is in my other pants.
  • On many sites, I don’t have to type in my name, email address, and zip code for the hojillionth time, because they are automatically fetched via OpenID.
  • Lastly, if I ever decide that I made the wrong decision about my password policy, I don’t have to remember and revisit the site in order to change my credentials.
In short, OpenID makes my life easier, and therefore I am more inclined to use web apps that support it than those that don’t.