Archive for the ‘Learning’ Category

Twitter4R shifts RSpec onto my Front Burner

Thursday, February 5th, 2009

As usual, my day did not pan out as expected. But, also as usual, I learned a lot!

Coming Up To Speed on Rspec

So, learning rspec has been on my list for a while. I finally got around to it. Nice framework. I am familiar with EasyMock, and am aware of JMock. I never had an opportunity to get into Mockito, but I’d give it a glance next time I put on my Java hat.

There is some decent documentation on it out there. I found these links particularly helpful:

During my ramping-up, I took the usual meta-approach of creating a test suite — and yaaay, that’s what rspec is meant for! — which I then used to test out its own range of capabilities. The Modules in the rdoc which I’ve found to provide the most value are:

  • Spec::Expectations::ObjectExpectations for conditionals (eg. should & should_not)
  • Spec::Matchers for expectations (eg. equal(value), be_a(class), respond_to(method_sym), raise_error)
  • Spec::Mocks::Methods for mock method definition (eg. should_receive(method_sym))
  • Spec::Mocks::MessageExpectation for mock behaviour (eg. with(*args), once, exactly(n).times, any_number_of_times)
  • Spec::Mocks::ArgumentConstraints for mock arguments (eg. an_instance_of(class), anything)
  • Spec::Mocks::BaseExpectation for mock responses (eg. and_return(value), and_yield(&block))

I won’t got into the deep details, but here are some examples of conditionals and expectations that I paraphrased into my meta-test:

And here’s a little bit of silly mocking:

These are just ways I thought of to exercise the width and breadth of the library. Very nice. I hope that these are useful examples for people new to this gem.

I recommend the other references from above for filling in the missing details. Once you have a context / specify or a describe / it specification set up, you’ll be good to go. There’s much more to the library — Stories, for instance — but that’s for another day.

An Informative Walk through Twitter4R

No, I didn’t really want to spend time learning rspec — I mean heck, I’m busy — but I had a personal need to expand the Twitter4R gem. Specifically, I wanted to add on some Twitter search features, and I was very impressed with how this library has been built. Contribution-wise, the final step that Susan Potter recommends is to craft up some rspec tests.

Of course, mock testing is only as good as the framework you’re built upon. The assumption is that Net::HTTP is going to do it’s job, so mock it up and you can even test your Twitter features offline. When I built Bitly4R (given that name, my thinking has clearly been influenced), I did everything as full-on functional tests. It was easy; bit.ly has both shorten and expand commands, so I could reverse-test real values without having any fixed expectations.

However, Twitter is live and user-generated, so who knows what you’ll find. Mocking covers that for you. And of course not having to hit the service itself shortest testing time dramatically.

Here’s one of my tests, again foreshortened:

Plus a little mocking of Net::HTTPResponse:

Nothing like having some good inspiration to get you thinking about maintainability. I’m a not a strong adherent to any of the TDD or BDD denominations, but testability itself is close to my heart. Just ask the folks who’ll be looking at the micro-assertion Module that I wrote for my Facebook Puzzle submissions (which work locally under test conditions but fail miserably once thrown over their wall). Then again, I won’t need to write that (and test that) from scratch again.

So, back to talking glowingly about the Twitter4R architecture. Yes, I used that word. Yet regardless of that term’s heavyweightedness, it’s simply the result of carefully thinking out the formalization of a complex design. And once a non-author delves into extending an existing implementation, that impl’s demeanor becomes readily clear :)

Some of the interesting things I saw:

  • An inner bless-ish strategy, to inject the Twitter::Client into instanciated result classes. I’ve seen blessing as an OO-Perl-ism, for self-ication, and that metaphor carries over very nicely to this context.
  • Generous use of blocks / lambdas / closures in methods, for contextual iteration (eg. iterate through each Twitter::Message in a timeline response). Unnecessary, but an excellent convenience for a language that offers that optional capability in a very disposable fashion (from the caller’s perspective).
  • Retroactive sub-object population after construction. Twitter4R relies upon the json gem, which deals primarily in Hashes. Post-injection, the library itereates through Arrays of Hashes and transforms them into suitable Twiltter::User containers, etc. A great place to put such logic in the construction chain, and it doesn’t take long to get really tired of Hash hierarchies.

Good stuff, and learning with in a Ruby-centric mindset was invaluable for me. We all have to start somewhere, eh.

The Acute Long-Term Pain of Staticness

There was one issue that I ran into; static configuration. During my years of using the Spring Framework, my IOC-addled brain started thinking of everything in terms of instances — Factory Beans, POJOs, Observers & Listeners, Chain-of-Responsibility wrappers. Static configuration is a common metaphor, and in this case, there’s a static Twitter::Config instance. Convenient and centralized. Makes perfect sense.

I mean, the fact that it was a configurable library at all was awesome. I was able to easily set up a Twitter::Client to reference search.twitter.com. However, of course as soon as I did that, I whacked the ability for clients to talk to twitter.com in the process. Oops!

On GPs, I refused to modify the original code. And I wanted to make sure that my superficial tweaks to the library would be thread-safe — temporarily swaping out the global Twitter::Config in mid-operation would be an issue. Using Mutex.synchronize seemed like the perfect choice. After finding that the same thread can’t lock a Mutex instance twice — grr!, that’s a great trick if you can work it — I overrode the one method that cared the most about @@config:

It works like a charm. Please, everyone just line up to tell me how I could have done it better. And I don’t mean quicker or cheaper, I mean better. Believe me, I would not have sunk the time into this end-around approach, if not for the fact that:

  1. I don’t want to maintain a local gem code modification (even though my impl is closely coupled to the gem impl already)
  2. I intend to follow that practice, so every opportunity to pull and end-around is a Valuable Learning Experience.

So, now my local Twitter4R has search capability gracefully latched onto it (and implemented much in the flavor of the library itself). I have a mass of rspec examples to work off in the future.

Now, I haven’t spent a great amount of time testing the thread-safeness — no one in their right mind wants to do that — but my sundry Twitter::Client instances play nicely together in between searches and normal status operations.

And I had something useful to blog about!

Learning Ruby through Assertions and Podcasts

Thursday, January 22nd, 2009

I’ve been working with the Ruby language since March 2008. So (as of this writing) I’m still on the n00b path.

Assertions

The first thing I did was to follow the great advice of Dierk Koenig, writer of Groovy in Action and general Groovy / Grails advocate. The book itself doesn’t use the typical print-the-result-based code examples; it encourages the reader to learn the language through assertions. And that’s how I learned Groovy; I took the examples from the book, paraphrased them, tried variations on a theme, and then asserted that my results were true. Now when I need to know how to use a language feature, I simply look back at my assertion code to re-edjumicate myself.

I learned the core Ruby language via Test::Unit. I spent three weeks (please don’t laugh) worth of my daily commute writing assertions for the core language, the standard packages, plus ActiveRecord and other common gems. It allowed me to get a handle on the concepts, syntax, semantics and the sheer range of capabilities of he language. I frequently look back at my language_test_unit.rb to figure out the best use of Array.collect, catch..throw, Regexp quirks, and using declared lambdas as blocks (etc). More importantly, I’ve already written code using all of those techniques, so it’s just a referesher.

I cannot recommend this technique enough for coming up to speed on a language!

Podcasts

With that under my belt, plus some command-line scripts and a solid Rails project, I’m not spending time back-consuming posts from the following Podcast blogs:

Rubyology

Site : Feed

I’m actively back-consuming a lot of content from this wealth that Chris Matthieu has provided. There are some great talks on Journeta, using EC2, great tutorials covering basic and RoR, and some scaling recommendations.

sd.rb Podcast

Site : Feed

Straight from the mouth of the San Diego Ruby Users group. A good variety of topics, focusing more on the Ruby language than on the Rails poster-child itself. Nice talks on rspec, MySQL clustering and Arduino, amongst many others.

Railscasts

Site : Feed

With 145 postings and counting, there’s a lot to be consumed here. However, this is the last on my list, because none of them download to my iPhone 3G :( . Lots of cross coverage on Capistrano, Partials, custom Routes, ruby-debug … the list goes on.

Ruby on Rails Podcast

Site : Feed

Geoffrey Grosenbach’s podcasts are seminal. I’ll leave it up to the reader to pore through the years of accumulated wisdom. How can you go wrong when you’re part of the rubyonrails.org domain!

In Summary

A number of these feeds provide screencasts and/or video. A few of the files are old-school QuickTime MOVs which are problematic for the iPhone, which is annoying (definitely not the podcaster’s fault… get your head in gear, Apple). And unfortunately when I break away to write down something in Evernote.app, and there’s any visuals associated with the cast, the iPhone halts playback. Grr. So I’m getting into the archaic habit of creating a Notes page and mailing it to myself :)

I recommend each and all of these podcasts. Be prepared to sink a lot of time into them, so you might as well upload them onto your iPhone and take them to the beach!