Gears Within Gears

Seek simplicity, and distrust it.

RailsConftroversy

Posted by Brian Guthrie Sat, 02 May 2009 19:10:00 GMT

Tomorrow I’ll be hopping on a plane to Las Vegas for RailsConf ‘09, which comes at an interesting time for the community. The sagging economy, rise of alternative Ruby-like dynamic languages, and recent furor about sexism (about which I and many of my colleagues are pretty upset) make for a challenging set of obstacles for the technology that we all love. I’m curious about what the general mood will be, and I’m sure I’m not the only one.

I don’t know about other companies, but I know that ThoughtWorks has scaled back our involvement in RailsConf rather considerably this year, not because we don’t still like Rails but because sending people to Vegas in the middle of the week at the expense of billable or otherwise productive work is a luxury that all too few companies can afford these days. I’m glad I get to go and hope to repay our investment by blogging frequently about the sessions and sharing my thoughts on the goings-on. If there’s anything in particular you’d like to hear about, drop me a line at btguthrie@gmail.com and let me know. You can also follow me on Twitter.

In particular, if you’re interested in hacking on Ioke while you’re there please do let me know. I think it’s too late to suggest a BOFS session, but I may try to put something together anyway.

As for the recent controversy, my own feelings are perhaps best captured by Martin Fowler’s commentary, who reminds us yet again why we value his advice so much. Liz Keogh’s post is also fascinating. I could go on with more, but so many others have already said it better than I can; suffice it to say that I’m disappointed, and admire the creation but maintain my doubts about the creator.

Posted in | no comments |

Why do type checks in dynamic code smell?

Posted by Brian Guthrie Thu, 09 Apr 2009 23:09:00 GMT

Because if you’re testing comprehensively, in my experience, you almost never need them. Unit and functional tests aren’t a panacea, but failures around incorrect types represent a miniscule proportion of the errors in the Ruby codebases I’ve worked on. You get them every once in a blue moon, but they are fixed easily and quickly, and everyone moves on with their lives. People still ask me sometimes if I miss static types, and my answer is always an unequivocal no. They eliminate a particular type of error that I almost never need to worry about.

Ola is also right that types aren’t the same as classes, and attempting to conflate the two will in all likelihood drive you towards class explosion and, ultimately, madness and penury.

That isn’t to say that interfaces shouldn’t have at least implicit contracts. In my own design, I try to follow the robustness principle whenever possible, and it improves code maintainability dramatically (nor does it does get discussed as a design principle nearly often enough). If it’s generally clear from reading the code what you can expect back from a method call and your types are suitably polymorphic then explicit type checks should be pretty rare.

Posted in | no comments |

Code comments, alias_method_chain, extensions, and the importance of expressing intent

Posted by Brian Guthrie Fri, 27 Mar 2009 17:14:00 GMT

At ThoughtWorks, everyone submits a code sample as part of their interview process. The comment I received from my interviewer about mine struck me, though, and it sticks with me to this day. “The code looks fine,” he said, “but what’s with all the comments?”

My introductory CS course at Northeastern University taught me a lot of things that have resonated in my experience in the industry, but we were taught one thing that, as it turns out, almost none of my colleagues agree with: that all of your methods, classes, and modules should be preceded by a simple, one-line comment that states the purpose of code unit in question. Far be it from me to gainsay Neal Ford, who believes that code comments are a smell, but there are days when I disagree: Even developers with the best intentions and training in the world can’t always write clear code.

A Brief Re-Introduction to Class Re-opening

The problem manifests itself most acutely through the Ruby mechanism of class re-opening (sometimes dismissively referred to as “monkey-patching”). You can go about it in a number of ways, and the codebase I’m working on these days has employed each and every one of them at some point or another. The advantage you gain from being able to reopen classes is that you can patch the framework you’re using unobtrusively in order to fix bugs or improve performance. The downside is that you don’t get to choose the names of the methods you’re overriding: they may make perfect sense in the context of the class you’re overriding, but none whatsoever as an isolated patch.

A reopened class looks something like this:

In the first example, we’ve patched String directly; in the second, class_eval’d it for an added layer of complexity; and finally we’ve defined our own module and added it to String after the fact, which is fact the recommended way of going about it. We can use IRB and the method method to try to figure out where our patch is coming from:

Notice that only the last one gives us a helping hand when we’re trying to figure out where this method was defined.

Overriding, not extending

Now imagine there’s a bug in the String class: a colossally poorly-designed method, something that’s significantly impacting your ability to get something done in the language. (While this doesn’t happen in Ruby very often, it’s like to have occurred at least once in the framework of your choice.) In the bad old days, you’d have had to patch Ruby directly; if you were good about it, you’d submit your patch to Matz, and it’d get integrated as part of some future release. But the language itself gives you an escape valve: override the method, and your implementation gets used.

On my current project, we do this all the time.

But what happens when the framework gets upgraded? Is this extension still necessary? Why did anyone put it there in the first place? What’s with this Subversion check-in comment? Why didn’t anyone say anything in the code?

Enter alias_method_chain

alias_method_chain is a Rails method patched into Ruby that allows you to extend a method without blowing away the old version. You can read Marcel’s post on it on the Rails blog from back in the dawn of time, two years ago, when they added it to the framework. In action, it looks something like this:

Suddenly our extended method has an identity again: it has a name that clearly indicates both the method it’s trying to extend and the feature we’re adding on top of it. Hallelujah!

Why does this matter?

The ability to re-open classes is an insanely powerful tool. I love it, not least because it never means having to write another XUtil (XmlUtil, DateUtil, StringUtil…) class again to make up for the deficiencies of someone else’s API. I could never tell you, in good conscience, not to use it.

But cleaning up becomes a bit of a mess when you have to upgrade frameworks (or language versions, for that matter) as we’ve had to do recently on our project. We carry a copy of Rails around in our vendor directory, like most projects do, but we’ve tried to be good about making our extensions externally, through class re-opening, rather than patching the Rails code directly as men and women did in days of yore. But because, out of habit, none of these extensions carry any comments, we’ve had a devil of a time trying to figure out not what they do (we can always read the code) but why they’re there, and whether we can finally, for the love of God, delete them now that we’re upgrading to Rails 2.2.

But take it from me, one developer to another, who hath had to maintain thine extension, yea, even unto multiple new Rails versions: using the tips above will help me, and those like me, figure out what the dickens you were trying to do. And for Heaven’s sake, when you don’t have the luxury of naming your methods to make it clear what they do or why they’ve changed, leave a quick comment.

Posted in | no comments |

An introduction to mocking and stubbing in Ruby

Posted by Brian Guthrie Wed, 25 Mar 2009 04:11:00 GMT

I gave a presentation on mocking and stubbing in Ruby a couple weeks ago at the Atlanta Ruby Group and the maintainers of the group have been kind enough to put the video online. It’s a large and energetic group and I had a lot of fun presenting, as indeed I always have watching others present there. If you’re new to unit testing in Ruby and you’re wondering what the fuss is about, check it out and let me know what you think at btguthrie@gmail.com. Slides here, or just watch the presentation.

Posted in | no comments |

What the Rails Hosting survey says about the Ruby on Rails community

Posted by Brian Guthrie Tue, 24 Mar 2009 03:07:00 GMT

Some highlights, or anyway things that caught my eye, when I read the 2009 Rails Hosting survey of Ruby on Rails developers:

  • Around 60% of the community has been using Ruby and Ruby on Rails for 2 years or more. It’s not yet a mature community, but there is now a reasonably large body of expertise to draw from in solving problems in and around the framework.
  • Rails developers on average develop two to five new applications per year, and deploy them several times a week to several times a week.
  • Most of these are probably small:
    • Generally respondents either self-host or use a small-scale VPS service like Slicehost (which I myself host this blog on; recommended.)
    • Respondents claim to be highly sensitive to the price of their hosting provider.
    • Most don’t use performance, uptime, or process monitoring.
  • It surprised me to see that almost a quarter don’t use any automated deploy process whatsoever, which sounds painful. Furthermore, 5% claimed they were still using FastCGI+Apache. Crazy.
  • The community has largely moved over to Git as the SCM of choice, although Github is not widely used as a centralized code repository—only a third claim that their source code is hosted there.
  • Passenger has, this year, finally surpassed Mongrel as the rails server of choice.

I see a community that’s still youthful but is starting to mature. I’m still proud to be a Ruby developer, and glad to be a part of the community. Here’s hoping for more good years ahead.

Posted in | no comments |

Do unit tests find bugs?

Posted by Brian Guthrie Tue, 10 Feb 2009 01:50:00 GMT

Suggested controversy background reading: Joel hates tests, Uncle Bob is incredulous, Kent Beck is offended, the VP of software development for Justin.tv shoots proudly from the hip, Jay doesn’t see the big deal but blogs about it anyway, and here’s little old me, exxagerating only slightly. Hat tip to every single developer on Twitter.

So, bugs. Do tests find ‘em? Good lord, yes. I don’t know what kind of unit tests you write, but mine find bugs all the time, though not generally until I try to change something ‘twere better left unchanged. I can’t begin to count the number of times a well-placed test has saved my own individual slice of bacon or the collective bacon of my team. Maybe I’m no rock star, but most of your team members won’t be, and a good rock star may well make a bad teammate. A robust test suite is the critical difference between me being enthusiastic about improving my team’s code and being terrified of doing so for fear of breaking something.

And finding bugs isn’t even the best reason to write tests.

  • They communicate intent and serve as a living, breathing specification for a codebase that may not have one.
  • They allow you to reason about code that hasn’t been written yet.
  • They demonstrate how best to utilize what’s already there.
  • They bring discipline and coordination to your process.

Two things really brought me around on testing:

  • I’ve worked on several large, complicated codebases written in a dynamically-typed high-level language.
  • I’ve had several great mentors who’ve demonstrated to my satisfaction the zen-like benefits thereof.
  • Every time I have written code without testing it as I go I’ve come to regret the decision, without fail, even on personal, why-bother-testing stuff. I honestly don’t know how you people get a decent night’s sleep.

Stuff can break:

  • Tests that once described the behavior of a particular module in a very granular fashion start to inhibit your ability to change evolve code in reasonable ways. Write more robust tests.
  • Slow tests can result in a slow build cycle. There are technical solutions for this. (You do continuously integrate, don’t you?)
  • 100% code coverage is hard to achieve. Code coverage is a funky measurement and a perfect score is no guarantee that you’re actually perfectly tested. I will also happily acknowledge that striving for it seems to yield diminishing returns. I try to stay above 90%, 95% if I can swing it, but I don’t let not hitting 100% bother me.
  • Plus all of the other triumphs and tribulations that go along with maintaining a good test suite, as with any other body of code.

If you’re still undecided, well, it helps to work with someone who’s done it before.

Posted in | no comments |

Ioke mocking, Mocha as exemplar

Posted by Brian Guthrie Tue, 03 Feb 2009 05:32:00 GMT

A little while back I volunteered to work on a mocking framework for Ioke when my friend Carlos suggested it might be helpful. I’m a bit embarrassed that I don’t have more to show for myself after all of my flailing about, but in my defense, it’s been a spare-time sort of a thing. If you’d like to follow my progress you can do so on my Github fork of Ioke.

Building a mocking framework for Ioke has raised a number of interesting questions, which I’ll run through here. If you have any suggestions or questions, I’d love to hear them.

Is full-bore mocking worth it when prototyping makes it so easy to stub?

Ioke is a prototype-based programming language: any object can mimic any other object. You can declare a constant by capitalizing the name of your mock (Foo = Origin mimic) or an “instance” of that constant by lowercasing the reference (someFoo = Foo mimic). Mimicking an object adopts all of its cells, which is to say, its data and behaviors.

if you would like to instantiate an object you need to ensure that the mimic begins life with unique data structures, because if you don’t it will share the same references as its origin. The convention in Ioke as it stands currently is to declare a create method: someFoo = Foo create. That method will often look something like this:

Foo = Origin mimic do(
  create = method("Creates a new Foo", self with(objects: [], name: "A name"))
)

The advantage of this approach is that stubbing is trivially easy: you can mimic any object, any time, and replacing the behavior of one of its cells is as simple as redeclaring it:

someFoo = Foo create          ;; someFoo objects is now an empty list
someFoo objects = set()       ;; someFoo objects is now a set
someFoo objects = method(...) ;; And so on.

So, why do you need a mocking framework?

Steve Yegge, in his article about what he terms the universal design pattern, praises JavaScript (a similarly prototype-based programming language) for making it so easy to test Java classes. This doesn’t quite get at the whole story; mocking frameworks offer at least three distinct advantages over simply replacing the method call:

  • They can set precise expectations in terms of method arity, arguments, and order of invocation, though I confess that I don’t often use the more advanced features of most mocking frameworks.
  • They can enforce certain rules about the mockability of particular cells; for example, that you don’t set an expectation on a cell that doesn’t actually exist. I wish I used these features much, much more often than I do.
  • They can replace the original cell (method) definition when the test has finished running, which is extremely important if you want to stub out behaviors related to domain models that might be reused in other tests.

All of those seem like things worth having.

Should the existence of macros suggest a different API for mocks?

I started out by following a fairly convention syntax:

foo should receive("bar") with(:qux) andReturn(5)

Ola suggested that I deploy a little macro-foo in support of readability, and that’s the way it stands right now:

foo should receive bar(:qux) andReturn(5)

One could imagine further refinements on the form; if you have any, as always, drop me a line.

This syntax bothers me a bit because it runs so counter to what I’m used to seeing in languages where every argument is eagerly evaluated. In the above example, we expect the cell “bar” to be invoked with an argument of :qux. Now, clearly we don’t actually want to invoke the bar method directly; it doesn’t exist right now, certainly not as a receiver on any object that makes any sense. But what about :qux? What if the above had been written as:

expectedArgument = :qux
foo should receive bar(expectedArgument) andReturn(5)

Clearly we need to evaluate the arguments to that method call but leave the call itself alone. Weird? I don’t know. You tell me.

What inspiration can we draw from frameworks in non-prototype languages?

I’ve found that I do my best learning through experience, and so didn’t make a serious attempt to understand the internals of other mocking frameworks; having used them extensively, I figured, I have a pretty good idea of their capabilities, and so dove in unencumbered by reason, research, or even a decent working knowledge of Ioke. It’s been tremendous fun and as usual I’ve gone through my share of pain, but one of the nicest parts has been actually spending time inside Mocha itself after it became clear that I needed a bit of guidance.

It turns out that prototyping doesn’t get you all the way there precisely because there are some features of a mocking framework, as suggested above, that require some deeper thinking about expectations. How do you know if one is satisfied? How do you pick from competing calls with different argument expectations? Multiple or infinitely allowed invocations? Sequenced return values? Block yields? And so forth.

Although there are pieces of it that feel vaguely stitched-together, as though Mocha and Stubba never quite met at the seams, it’s been fun code to read. Mocha’s a good example of a library that does something complex in a reasonably straightforward manner. The methods are brief and readable, and though there’s a bit more indirection than I’d like (what’s the difference between verified? and satisfied? What does it mean to match? or invoke? How do you pick apart three different mock methods in three different places?) I’d happily recommend it to others as a good example of how to pull off some hairy Ruby functionality without writing a whole lot of hairy Ruby code in the process.

What do I mean by that? Here’s the main expects method that gets mixed in to the Object class:
  def expects(symbol)
    mockery = Mocha::Mockery.instance
    mockery.on_stubbing(self, symbol)
    method = stubba_method.new(stubba_object, symbol)
    mockery.stubba.stub(method)
    mocha.expects(symbol, caller)
  end

Each one of those lines is pretty dense: it requires a lot of backtracking to understand why it’s there and what it does. But there aren’t many of them, and they can all be explored methodically, and understanding one leads to understanding the next. Much of Mocha is like that: moderately sized, neither opaque in its density or transparent in its verbosity. Nice, I suppose, for my own definition of nice.

I’ve also learned a lot about the framework that I didn’t know before (for example, I didn’t know that it was possible to configure Mocha to warn against or even disallow mocking nonexistent methods) and will bring that knowledge with me to future projects.

But I don’t regret having not read the source first. Trying and failing gave me the context I needed to understand why Mocha made some of the choices it did, even if I don’t agree with all of them, and in the coming days and weeks I’ll be stealing drawing inspiration from most of them. Thanks and kudos, guys.

Posted in | 2 comments |

Zed Shaw: The Simplest Possible Explanation

Posted by Brian Guthrie Mon, 24 Nov 2008 00:19:00 GMT

A bunch of otherwise nice people apparently dislike Zed Shaw and call him names to his face. I have not met the man but am myself am acquainted with a number of people who are also otherwise nice people but who, having encountered Mr Shaw in the flesh, are inexplicably given over to calling him unpleasant names, though not generally to his face. I humbly posit the following, contra Zed: The simplest possible explanation for this phenomenon is not that everyone Zed Shaw meets is a jerk.

Posted in | 1 comment |

The weirdest code I've seen recently

Posted by Brian Guthrie Sat, 02 Aug 2008 22:15:00 GMT

I was kicking around in ActiveResource::Base recently and it took me a good solid ten minutes to figure out why the prefix method didn’t recur infinitely.

def prefix(options={})
  default = site.path
  default << '/' unless default[-1..-1] == '/'
  # generate the actual method based on the current site path
  self.prefix = default
  prefix(options)
end
def prefix_source
  prefix # generate #prefix and #prefix_source methods first
  prefix_source
end
def prefix=(value = '/')
  # Replace :placeholders with '#{embedded options[:lookups]}'
  prefix_call = value.gsub(/:\w+/) { |key| "\#{options[#{key}]}" }
  # Redefine the new methods.
  code = <<-end_code
    def prefix_source() "#{value}" end
    def prefix(options={}) "#{prefix_call}" end
  end_code
  silence_warnings { instance_eval code, FILE, LINE }
rescue
  logger.error "Couldn't set prefix: #{$!}\n  #{code}" 
  raise
end

Do you see it? When prefix is called, it calls prefix=, which redefines prefix and returns. prefix in turn returns by calling not itself but the newly-created method of the same name.

I am not known for my low tolerance of metalanguage hackery (exhibit). But I do have my limits, and this exceeds them; calling it needlessly obfuscatory would be kind. Or am I wrong? Is there no better way to provide a method with the same semantics?

Posted in | 1 comment |

GitHub, briefly

Posted by Brian Guthrie Mon, 21 Jul 2008 04:54:00 GMT

I know that I’m late to the party here, that all of the cool kids have had accounts for what seems like Internet-decades, and that I can do nothing but add my voice belatedly to an already rapturous chorus; nevertheless, forgive my enthusiasm: GitHub rules, it is worth joining, and, once signed up, it took only a week for my workflow to be forever improved. I am, in short, a believer.

  • It’s never been easier or more convenient to contribute to other open source projects.
  • It’s never been easier to work remotely.
  • It’s never been easier to track the progress of projects and developers you’re interested in.
  • Unicorns! Rainbows! Puppies!

Over the next few weeks I’ll gradually be migrating all of my projects over to it, and I encourage you to do the same.

Posted in | no comments |

Older posts: 1 2 3