There are two types of lazy people in the world

From Wired: http://www.wired.com/underwire/2011/07/alt-text-good-laziness/

There are two types of lazy people in the world: those who don’t want to do anything they don’t have to and those who don’t want to learn anything they don’t have to.The former group drives progress. The latter impedes it.

For the record, I would prefer to belong to the former. We're lazy in the way that says that tired old process you're using could likely be cut in half with some work.

There is no special feature

In the post “There are no special cases” by James Hunt, it's argued that when we add a feature to an existing codebase, it should be as simple and integrated when we're finished as when we started. In other words, adding a new feature isn't a special case, the design should be adjusted to account for it. I would contend that if you're using a tool like cucumber that is meant to communicate behaviour, new functionality should be fully integrated into existing features and scenarios rather than treated as a special case. While it's easy (and occasionally correct) to just tack a new scenario onto a feature, we really need to look at the existing scenarios and be sure that we're describing the functionality in the best way possible, taking into account what's already there.

How to choose your testing tools - what are these tests supposed to do again?

There's been a lot of talk lately about what tools should be used for testing and communication, notably with dhh disliking rspec and cucumber. I realize I'm late to the game on that argument, but I don't really care - I like to mull things over for a while until they crystallize.

I was talking with @alkema today about testing tools from the perspective of a developer inheriting a project, we identified a few different jobs that a suite could be doing:

  1. regression testing - being able to refactor code without breaking existing functionality is a huge deal, but before you can do that, you need to know how the application ought to be behaving
  2. communicate functionality to future developers - I think this is where rspec really shines. Most clients would never be reading rspec tests, though I could see sharing the formatted results as reports in some cases.
  3. communicate functionality to clients - this is arguably more about communication than "testing" (which I think was dhh's contention). This would also be used more in the design phase but it can and should also be used continually as customers request changes. This is where a tool like cucumber really kicks butt. There is so much power in a client being able to work with their developer in describing some functionality before anything get written. When they see their design come to life, it's golden.

I could certainly be missing some things here, feel free to correct me in any way :)

Ideally, the testing tool(s) you use should cover all 3 of those things. Test unit can do regression testing like a champion, assuming you have the coverage, but from what I've seen, it's a lot harder to convey an applications functionality in a human readable way. RSpec has more overhead than test unit, certainly, but it really forces you to state behaviour rather than just test functionality. If used well, an RSpec reports can describe all the functionality in an app - perfect for developer communication. If used well, it can be used as a design tool for the developer and can also provide a full regression suite. Cucumber is primarily a client communication tool that also provides good full-stack testing. It helps with regression testing, but in most cases doesn't go far enough to catch all the cases (and as a communication tool, it shouldn't have to).

At the end of the day, I think you need more than one tool to really convey an application's functionality. For me, that's the mix of RSpec and cucumber. If I had to choose one tool alone that gets as close as possible to covering all three areas, I'd have to go with RSpec. For me, the readability alone is worth it.

Filed under  //   cucumber   rspec   testing  

Using Pow with Rails 2.3.x

Are you one of the faithful development masses trying out 37signal's new Pow development server? Me too! I'm loving it so far, with a couple of minor issues.

Trouble is, I went to boot up one of my existing rails apps (a rails 2 maintenance app), and it totally didn't work. After a bit of searching, I added a config.ru file to the root folder with this:

require "config/environment"
use Rails::Rack::LogTailer
run ActionController::Dispatcher.new

The initial post I found also had a `use ActionDispatch::Static` line in there, but that error'd out on me and appears to work just fine without it.

Note: remember/notice that Pow takes over port 80 on your machine, so if you have a lot invested into a local apache/nginx install, you may not want to use it. There may be a way around it in the firewall rules, but you'd need to fork the project and dabble on your own (pow github repository).

Filed under  //   development   pow   rails  

Living your resolution as a story

I realize I'm late to the game here, but I was sent a blog post the other day describing how to actually live out a new year's resolutions. 

Resolutions like "lose weight" or "code more" or "exercise for 45 minutes 5 days a week" are ultimately useless. Very few of us can keep up with them. I know I can't. At best, I can do them for a few months before falling off the proverbial wagon.

Stories, however, we are very good at living out. Instead of saying I want to lose a few pounds, I'm going to sign up for a half marathon to run in the spring. In doing so, I'm doing a few things:

  1. Creating a tangible goal - run a half marathon in less than 2 hours.
  2. envisioning myself actually crossing the finish line
  3. creating the social pressure by signing up and posting here that will cause me to actual get off my butt and train. Because I have to! I'll even post my results, I promise.

If I want to lose weight, I can create "goal" that will cause me to do so by living out the story I've created. Doing the training to run a half marathon in that time will get me there. To me, this makes a lot more sense than resolving to do an arbitrary thing with no reachable target. i can write my own story, with me crossing the finish line victoriously at the end :)

We'll see if this works. Check out the article if you want:

Living a Good Story, an Alternative to New Years Resolutions

Now I have to go find a race to sign up for...

The value of rest

I was told a maxim lately: "to avoid burnout, 1 hour a day, 1 day a week, 2 weeks a year".

1 hour a day of real relaxation, whether that's through time alone, significant connection with somebody else or just resting (while awake)

1 day a week where you don't have a list of tasks. Where you don't check your email comulsively every 20 minutes. Where you don't, dare I say, even open your computer

2 weeks a year - and they must be back to back! - where you actually unplug from your work. A couple of days here and there won't do it.

I have been burnt out before. I hope to avoid ever doing so again, so I'm following this advice as faithfully as I can. I just took two weeks off. In those two weeks, I think I picked up my computer maybe three times, and that was to watch a movie. I managed my email by junking whatever I could, but let my autoresponder take care of the rest until I got back. It was a great holiday. I got to spend time with my wife & kids, I read 12 books (yes, twelve), watched a few movies, got together with friends and had some fun doing home renovations. It was worth every penny. 

I highly recommend it to you.

Filed under  //   burnout   business  

DRY Bundler

Just saw this tweet RT'd by @wycats

Given that I am doing an initial deploy of an app today using bundler, it's perfect timing for me:
http://rails-bestpractices.com/posts/51-dry-bundler-in-capistrano

so much easier than before

On trying something new

Just came across this. It's very apt for me right now:

Suffering is the gateway to true knowledge of one's self, and therefore humility. Season the physical with psychological difficulty and risk and administer at the proper dosage to achieve higher consciousness. What is this spice? It is the unknown, the new and different, an uncertain outcome, a consequence or penalty, competition, comparison, or perhaps it's as simple as changing expectations, being held to a higher standard.
http://www.gymjones.com/knowledge.php?id=40

Struct and form_for: Together at last

Sometimes, you have to create a form that doesn't really apply to a specific Resource in your project, but you still want to use form_for. In my case, I use formtastic, which essentially leverages form_for to make forms tasty.

One option would be to create a small class with accessors and a wee bit of logic. This would work, but feels somehow dirty. Enter “Struct

The description of a Struct is thus: A Struct is a convenient way to bundle a number of attributes together, using accessor methods, without having to write an explicit class.

In other words, it's a way to create an ad-hoc class with pre-defined, free-form accessors. Perfect for use in a form_for. As an example, here's my form (warning, this is formtastic):

<% semantic_form_for :date, report_dates, :url => reports_path do |f| %>
  <% f.inputs "Choose Dates" do %>
    <%= f.input :start_date, :as => :date, :include_blank => true %>
    <%= f.input :end_date, :as => :date, :include_blank => true %>
    <% f.buttons do %>
      <%= f.commit_button "View Report" %>
    <% end %>
  <% end %>
<% end %>

This is my sample helper. The #report_dates method is called in the first line of the form. In this case, I wanted to default to some dates if they weren't passed in explicitly:

module ReportHelper
  def report_dates(start_date=nil, end_date=nil)
    Struct.new("ReportDates", :start_date, :end_date) unless defined?(Struct::ReportDates)
    start_date ||= Date.today.beginning_of_year
    end_date ||= Date.today.end_of_year
    Struct::ReportDates.new(start_date, end_date)
  end
end

Now the form pre-selects those dates just like they were values in an ActiveRecord model. Tasty and simple

Cucumber, Capybara & custom @javascript step definitions

Today, I had the opportunity to dive into using @javascript tags with cucumber and capybara for a project. (See JavaScript Testing with Cucumber and Capybara for a good starting point). For my needs, I simply dropped the @javascript tag in front of the scenario and i was off and running.

And then I hit my particular snag. In this scenario/form, we are using a nested model wherein a "Contact" can have multiple phone numbers. For the functionality, we're using an adapted jQuery version of the excellent video RailsCast by Ryan Bates: Nested Model Form Part 2.

So here's the snag, after clicking on the "Add a Phone Number" link, the new nested fieldset appears perfectly, but how on earth do I fill in the "Phone number" field in the second, generated fieldset? For those of you in the know, you're probably saying "just call it 'within' the selector for that fieldset." But wait, young padiwan. The id for the fieldset and the fields are generated/adjusted on the fly by the javascript, thereby creating an unknown id.

After playing with some xpath and css for a while, I settled on this:

  1. I added a "phone-fields" class to the fieldset for the Phone fields
  2. Then I added a step to my scenario like so:
    And I fill in "Phone number" with "604 555 6415" within the 2nd ".phone-fields" fieldset
  3. lastly, I added step definitions like so:
    When /^(?:|I )fill in "([^"]*)" with "([^"]*)" within the (\d)(?:st|nd|rd|th) "([^"]*)" fieldset$/ do |field, value, index, selector|
      matcher = "fieldset#{selector}"
      path = Capybara::XPath.from_css(matcher).paths.first + "[#{index}]"
      within(:xpath, path) do
        fill_in(field, :with => value)
      end
    end
    
    When /^(?:|I )select "([^"]*)" from "([^"]*)" within the (\d)(?:st|nd|rd|th) "([^"]*)" fieldset$/ do |value, field, index, selector|
      matcher = "fieldset#{selector}"
      path = Capybara::XPath.from_css(matcher).paths.first + "[#{index}]"
      within(:xpath, path) do
        select(value, :from => field)
      end
    end

This gives me a new reusable step definitions to select any fieldset with pretty much any selector along with an index. Pretty cool!

Bonus points: When you are within a @javascript scenario, put a debugger call with your step definition (with the ruby-debug gem installed of course). Play around with the "fill_in", etc calls that are available within any step definition and the browser being driven by selenium will actually do the steps that you specify. I have to admit, my jaw kind of dropped when I saw that. Very cool

Update: My initial step definitions worked great when you only had one nested model in a form, but not so much with more than one. I've updated them above to be a little more friendly. The issue seemed to be in the way Nokogiri via Capybara was interpreting the CSS into XPath. I used simpler XPath index notation instead

About

Web guy, programmer, husband & dad, pretend chef. I love solving problems, especially on the web.

Delicious