Testing Rails Apps at the Rails Edge Reston

Stu Halloway is speaking about testing. Mike Clark is pairing.

assert_raise plus a block helps you verify that code will fail – which is hard to do in languages *cough* Java *cough* without blocks.

assert_respond_to allows you to verify duck typing.

Think about if your collections are ordered or unordered. Unordered will let you use assert_equal. You can write an assert_collection_equal for ordered collections.

We should probably write an assert_belongs_to, an assert_has_one, an assert_has_many as a community.

BTW unrelated to tests, but a tidbit from yesterday – to see all the routes in your Rails app, type in script/console

puts ActionController::Routing::Routes.routes

Test everything in sight, at least at first.

Ruby is more information dense than Java. Stu has measured and seen that some of his Ruby code is 10x more dense the equivalent in Java.

Fixtures should be valid objects, because they will get used by other tests. I had to correct some people fixtures in client code recently because they had invalid email addresses.

assert_select is new in 1.2 and deprecates (mostly) assert_tag and assert_dom. Don’t get too crazy going into the DOM or else you can make really brittle tests.

Stu shared some of his special mojo: Witch. (Someone asked when they saw something flash by on the screen yesterday.)

Try to make your test suites fast enough so you can run your entire suite, instead of using rake recent.

Using transactional fixtures is a good practice.

How can Rails testing improve?

Naked tests i.e real unit testing, without the database. This can make your test suite go faster but more importantly isolates your model behavior from database side effects.

System tests and continuous integration are also missing. Rails integration tests are like poor man system tests.

What can help fill in those 3 areas? (Unit tests, system tests, and continuous integration.)

Flexmock (a gem) by Jim Weirich can help you do unit tests by isolating your models with the help of mock objects. Flexstub (another gem) helps when you want an object very similar to another one but is slightly different. Martin Fowler defines in his bliki article Mock’s Aren’t Stubs the terms: Dummy (a placeholder), Stub (an object that returns a canned response), Fake (an object that returns non-production-quality data), and Mock (an object which returns canned responses and verifies what you did to it.) Mocha can also help here, its like Flexstub.

Selenium helps you drive a browser to write a real system test. There’s a plugin and gem called SeleniumOnRails. You could use Watir, which only runs in IE. Watch this space.

rcov can help tell you when you’re done testing. But 100% doesn’t mean that its a well-tested app esp since it strictly looks at lines of code. I’d add the same thing is true about rake stats, just because you have a 1:1 Code to Test Ratio doesn’t mean your app is well-tested. Nevertheless, like the inaccurate body fat monitoring scales on the market, I think they’re good rules of thumb to let you know if you’re on the right track to a well tested Rails app with 100% code coverage and a balanced code to test ratio. As Stu says, its not an absolute metric, its a trending indicator.

All the sample code from the presentation is available in Rails for Java Developers.

Creating Rails Plugins, Refactoring Helpers and Deploying Rails at Rails Edge Reston

It’s day 2 of Rails Edge Reston. Right now we’re in the middle of the Rails Golden Deployment Path talk by James Duncan Davidson. Jim Weyrich is pair-presenting. Jim told an interesting story: sometime last year he tried to get a Rails app going with FastCGI at his local Ruby group. They had several different approaches and it took quite a while to get it up and running. The next day Mongrel was released and he got his Rails app running on it right away. Needless to say, FastCGI is not the way to go anymore.

Duncan recommends using the MacPorts package manager for installing Rails. I completely agree though I would augment it slightly:

If you can install a Rails plugin, do that. If you can’t, then install a Ruby gem. If you can’t do that, then install using MacPorts. If you can’t do that, then download, configure, make and make install. The reasoning is because I want to do a) less work (i.e. be more efficient) and b) limit the scope of environment changes.

Tip from JDD: Create a different database user per Rails application. This helps isolate your app and protect your users.

More security tips: JDD: “Use either really huge database passwords or even better, get it from a secure file on the deployment system.” Jim W: “Don’t check your passwords into an open source svn repo.” Marcel Molina: “Put your passwords in environment variables.” Tom Copeland agrees with Marcel.

OK… going back in time, Chad Fowler and Bruce Williams showed us how to write a Rails plug-in and also incidentally how to write a Rails generator. They re-wrote acts_as_ratable which shows you how to add Netflix-like rating functionality to your app, complete with stars. Very cool stuff.

Why should you write Rails plugins? Chad gave 3 reasons: to share functionality that is generic (like acts_as_tree which will be extracted from Rails Core), to monkeypatch Rails (since plugins are loaded later in the initialization), to share models among your apps (we’re doing this at one of my clients.)

Marcel M (who btw is much more mellow in real life than his picture) gave a vapourware talk about the Presenter Pattern which is a proposal for solving the problem of Rails Helpers becoming a dumping ground for methods and getting huge and full of smelly fish. (Well ok maybe I’m taking his slides too literally.) Seems like a good idea – large classes are generally a bad smell as Martin Fowler would say.

By the way – all 9 presenters are here. So the Rails Edge experience is a complete one – you don’t get a subset, you get the complete set. Oh and the wireless rocks – which is what lets me blog from here. I think that’s the new standard for conferences – you gotta have good wireless net access.

Rails Edge Reston – Day 1

Rails Edge Reston is here. The first day was excellent and I can’t wait for tomorrow. It wasn’t just a conference – it was an event. Like Woodstock for Ruby on Rails developers. It was sold out with about 125 attendees. Interestingly, when Mike Clark asked who was hiring Rails developers, about a dozen people stood up. Everyone was pretty friendly and it seemed like a good little community – sorta like an East Coast RailsConf. I met people from as far as Connecticut in the Northeast, Santa Barbara from the West Coast, and also a fellow named Cedric all the way from Belgium.

It was appropriate that Dave Thomas started and ended Day One. As far as I’m concerned, he is the Godfather of Ruby on Rails in the USA. Of course, Matz is the driver of Ruby from Japan and DHH is the fearless leader of Rails from Denmark (tho I guess he’s in Chicago now.) But Dave is the guy who introduced Ruby to the current generation of Java programmers, myself included with his intriguing “Ruby for Java Programmers” presentation.

Dave exploded everyone’s brains in the morning with his Metaprogramming Ruby talk. I felt I was prepared as anyone for the intellectual enlightenment because of my experience with Smalltalk, which shares a lot of semantics with Ruby. I also have read Ruby for Rails by David Black which has good coverage of how Ruby handles classes, objects and methods. Reading the Rails source code also makes you more interested in how to do metaprogramming because otherwise you really can’t understand a lot of it. And I think understanding the details of your frameworks is essential (well, assuming its open source – *cough* Cocoa *cough*.)

Dave summed up his talk by saying that by practicing metaprogramming, you can code in your user’s domain. I would rephrase that slightly by saying that you can create DSLs (Domain Specific Languages) and program in those DSLs. Also you can make your code more compact by DRYing it up with metaprogramming.

BTW Rails Edge has a cool format – its one big room, one stage, pairs of presenters, and one track. Makes conference planning easy for the attendee. Stu Halloway was pair-presenting with Dave and had some insights for Java programmers making the transition to Ruby: you try to make object models exactly right in Java because its hard to fix later. But in Ruby, its easy to change them later. I think this helps with doing agile development.

I think I’ll have to blog the rest of day 1 later… gotta get some sleep so I’m ready for day 2. So here’s some parting thoughts:

Dave gave a motivational keynote called “Fear of Flying” that to me said don’t waste your time acknowleding and defending the FUD that is coming out against Ruby on Rails. Instead, use your skills for assessing risk which software devs do all the time and are good at. Embrace risk. Do what you love because passion dissolves risk.

Or as Dave put it: “If you can’t be with the one you love, don’t settle for loving the one you’re with. Get on your bike and go find the one you love!”

I think that’s why I see so many of my peers leaving their corporate jobs and going independent to do Ruby on Rails consulting and Mac app development in Cocoa.

Technorati tags:

Northern Virginia Ruby Users Group – January 2007 notes

David Bock gave a presentation about his experience deploying a Ruby on Rails app at the recent January 2007 Northern Virginia Ruby Users Group meeting. He created an app for wallhogs.com, a site where people can upload their own high-res pictures to print in a huge poster format that they can then stick up on their wall. I think we might order a big poster of DHH for the NOVARUG club room.

Dave faced some interesting challenges with deployment. The pictures required to make these huge sticky poster prints aren’t the ones that you get from your average cell phone. No, these are 8-10 MB monsters. So he knew that if this site was successful, it would need some good bandwidth and horsepower. He had some bad experiences with shared hosting and Rails, so they shopped around and ended up with a dedicated machine at rimuhosting.

Dave opted to use the currently recommended Rails stack – Apache 2.2+ -> mod_proxy_balancer -> mongrel cluster. Apache serves up the static files and does balancing, while mongrel (all hail zed, king of the internet) powers the Rails instances. For historical reference, the deprecated Rails stack is Lighttpd -> FastCGI.

Capistrano was of course used for making deployment easy and repeatable. They used two different targets, acceptance and production with slightly different recipes for each. I think that’s a good practice.

The exception notification emailer can really help you keep on top of issues and may impress your customers. I highly recommend it as well.

Random tidbits: X_FORWARDED_PROTO helped fix a problem with https. You can use a before_filter to force https on certain actions that need security. SOAP4R stable doesn’t work with Paypal – use the trunk. You can change the Paypal workflow a little bit but you have to approve it with a Paypal representative.

Interesting plugins used: acts_as_statemachine, acts_as_taggable_on_steroids, annotate_models, dollars_and_cents, exception_notification, google_analystics, query_trace, redbox, and ziya.

Cool hack: Since UPS Worldship doesn’t provide a webservice, Dave wrote his own using Ruby on Rails + ODBC.

Afterwards there was a debate about the GPL and MySQL after Dave mentioned that he was considering moving to Postgres to clear up the licensing. That was an interesting take – I hadn’t thought that using MySQL in a web app might trigger the GPL, but there are rumors that GPL 3 will clarify this.

Give aways: We gave out Ajax on Rails by Scott Raymond. We also gave out a coupon for a PeepCode screencast. Thanks to Geoffrey Grosenbach and O’Reilly for supporting us!

And of course, the obligatory Ruby code snippet:

assert_equal 45, attendees.count

Next meeting: 2/21/2007 – FGM HQ in Reston, VA – Chad Fowler will be presenting. See you there!

Rails 1.2.1 is here!

Yes, there’s nothing like the smell of freshly released software. Rails 1.2.1 was just released earlier today! Congrats to the Rails Core team and all the contributors! What a great start to 2007 for the Rails community.

Get it while its hot! I prefer freezing my Rails apps myself, because then I absolutely know what version of Rails each one is running. To get the official 1.2.1 release (1.2.0, we hardly knew ya), I prefer using “freezing” each app to it, because:

1. you know exactly what that app is running (and if you forget you can type in “script/about”)

2. you can still support apps that require 1.1.6 with the rails out of the gem

Now here’s the command to freeze your Rails app to the official 1.2.1 release:

rake rails:freeze:edge TAG=rel_1-2-1

Silicon Valley Ruby on Rails meeting tonight

My friend Zack is helping to organize and host the Silicon Valley Ruby on Rails (Redwood City, CA) Meetup. It’s tonight at 6pm PST.

On January 18th, the Silicon Valley Ruby on Rails Meetup returns from hiatus! Please join us at Insider Pages’ Redwood Shores office for another fun evening. We’ll continue our focus on real-world Rails development and bootstrapped startups with the guys from Likebetter, an addictive game that guesses what you are from asking what you like.

Its good to see Rails get-togethers happening from coast to coast! (And of course, all around the world.) Speaking of which, we had a great NOVA Ruby Group meeting last night. I’ll type up my notes tonight.

NovaRUG Meeting next week on January 17

when_at_novarug_january_17_2007_meeting do |attendee|
  attendee.observe :david_bock => "Rails Deployment"
  attendee.observe :douglas_sellers => "Selenium"

OK enough DSL fun – if anyone needs a ride to there from the Metro, I can pick you up from the East Falls Church Metro at around 6pm. Should give us enough time to zoom down the Dulles Access Toll Road to the meeting.

Different ways to write “I will not throw paper airplanes in class.” 500 times in Ruby

Someone sent me this FoxTrot cartoon that compares how to write 500 times “I will not throw paper airplanes in class.”

They didn’t have any Ruby in there, so I thought I’d share…

# Simplest and my favorite.
500.times {puts "I will not throw paper airplanes in class."}

# Uses range, but ignores the block parameter.
(1..500).each {|n| puts "I will not throw paper airplanes in class."}

# Fancy:
(1..500).each {|n| puts "I will not throw paper airplanes in class for the #{n}th time."}