Friday, April 04, 2008

BDD: Book Driven Development

recipes.jpg(This one is also on the Pathfinder blog, but since it fits in here, I wanted the full text here...)

Jay Fields, who has been posting a very nice sequence of nuts-and-bolts Ruby and Rails guidelines, pauses to talk about creating examples. It's a topic I've wanted to write about here for a while, and this is as good a lead-in as any. Plus, I'm generally interested in how principles of software development apply or don't apply in odd cases, and software being developed specifically for example purposes certainly qualifies as an odd case.

For Professional Ruby On Rails, I knew that I wanted to run a single example application through the book. I had some grand visions of it being a "real" application or at least a real example of coding best practices. For best practices, I think it's pretty good on a method-by-method bases, but has some weaknesses as an entire app, for reasons that I think will become clear.

The first question was exactly what I wanted the sample application to do. On some level, this is a superficial question -- who really cares what the fake app in the book does? At the same time, certain application structures would make it easier or more plausible to discuss certain features. And I had a list of features I wanted to cover -- legacy databases, users and roles, navigation, and graphics. Ideally, the sample app would have some kind of consistency that would make it reasonable to have these features.

In addition, I didn't want it to be a thinly-veiled version of a site that everybody would recognize, and I wanted it to be something that I could type every day for six months without going crazy.

One of my first ideas was to resurrect an old Web 1.0 joke for my killer e-commerce plan: a web-based store for selling and delivering gasoline. But I decided that the gag was a lot less funny with gas in the $3 per gallon range, and I also decided that I didn't want the fake site to be primarily an e-commerce site.

Brainstorming ensued. I almost did a social networking site for pets, but I decided that was too silly, subsequently discovering that there are already a zillion pet social networking sites...

Eventually, I settled on Soups OnLine, a soup recipe-sharing site. It had the advantages of:

  1. Having a data model that could plausibly handle RESTful nested resources (recipe and ingredients)

  2. Having an actual user model.

  3. Being a plausible site, while still being silly enough to keep anybody from taking the whole thing too seriously.

The first problem came up almost immediately -- site design. I felt that a site that was just dull HTML would not be credible or interesting, but at the same time, I didn't really have the time or resources to create a full site design from scratch, nor did I want the book to become about site design. My solution, which I'm not prepared to defend to the death, was to integrate a template from This kind of sideswipes the whole issue, providing reasonably good-looking site without having to get into the weeds debating CSS minutia.

Over time, the example mutated away from a normal application development process in a few interesting ways.

The nature of the book-writing itself was a strong anti-agile push, in much the same way that any large body of documentation is. Changes in code structure affect the tests, which is fine, but also affect some amount of text in the previous 300 pages, which there's no easy way to find. (As you can read in this post, the issue affected not just me, but also the editors on the book). At least once, a late change in Rails invalidated a helper method I used in an early chapter. Not a big deal, except I also used that helper method to demonstrate a test structure later in the book -- I wound up keeping a shell of the original method redirecting to the new Rails method.

Also, some features that I had hoped to get in, didn't quite get there -- because I ran out of time or because they didn't with the chapter structure. (If you read the book, you'll see some early structures that imply that the app will eventually convert between English and Metric, which I never quite got to.) Again, this is the kind of thing that happens in all the time in real projects, but is hard to smoothly redirect when there's all that pre-existing text describing the earlier plans.

Sometimes, the sample app has more features than a real app would, rather than less. Since the book tries to cover multiple plugins or ways to accomplish things, Soups OnLine wound up with far more plugin load than a normal app would -- a regular app wouldn't normally have RSpec and Shoulda and Dust, or RMagick and MiniMagick and ImageScience. Inevitably some conflicts happened between multiple plugins trying to cover the same space, making the final code somewhat wilder than I'd really like. (If you've read the book and want to experiment with the outstanding code, it's probably easiest to work with around chapter 9, before Globalize and the image plugins are added...)

Ultimately, of course, as Fields concludes, it's the author's fault if the example doesn't help the user understand the issues at hand. It's my job to understand the constraints of the form and still try to present as realistic an application as possible while explaining how to to build similar applications.