Want it? Give.

April 10th, 2010 by Radar

Imagine this scenario. You’re waiting at a checkout at your supermarket. It’s a pretty long line, compared to your past experiences.

Directly in front of you there’s a 22-year-old guy with medium-length hair, listening to God-knows-what on his earphones, dressed in casual gear. Probably middle class.

In front of him there’s another guy, about mid thirties, wearing a “business suit”; black pants, white top and tie. Probably upper class.

Then in front of him there’s a woman, probably around the same age as the man, but dressed like a hippie. She’s got a shirt that says “There’s no place like 127.0.0.1″. You fondly remember giggling quietly to yourself the first time you saw this shirt.

Then of course there’s the cashier. Unusually, it’s a guy with a ponytail who looks like the kind who you’d see attending computer and anime conventions.

The lady at the front of the queue puts her goods on the belt and the cashier processes them. Status quo. Then when the lady hands over the money, the cashier’s drawer breaks and falls out. Money goes everywhere. Coins roll in every which direction.

Now what the fuck do you do? Do you sit back and let the cashier run about collecting up his coins or do you help out?

Well, in this analogy, you sit back and let the cashier do it all. All of you in the queue do. Nobody helps the poor cashier.

You useless, pathetic bastards.

Now imagine this scenario wasn’t a checkout line. Imagine the people in the checkout line are actually people in an open source project’s community. Imagine, for a moment, that you’re waiting for The Next Big Release for this open source project. Imagine instead of the cashier’s drawer dropping out and throwing coins like shrapnel from a frag grenade, it’s actually tickets for this open source project. Do you know of a project like this?

I do.

It’s called Ruby on Rails. And it’s suffering because of your ignorance. It is at the moment in a place which I will steal the term “Development Hell” for and use. At current writing it has over 900 open tickets. Let me state that again because it is such a pertinent fact: There are over 900 tickets still open. So what the fuck are you going to do about it?

One little piece

It’s great that (at least in this Western world) we have things called weekends. We also have time where we are not working. Some of us have (a lot) more of it than others and generally waste it playing video games or watching TV. I’m fine with that, but there is a limit I feel before it turns from “relaxing” into “slacking off”. You have to realise that you are part of a world-wide community. You are using something developed by people world wide and it is time that you gave back.

I am sure that many of you reading this will think “I don’t know enough about Rails to do anything with any of the tickets.”

Bullshit. Fucking bullshit.

Take this ticket for instance. Guy experiences hassles with rake doc:rails on Ruby 1.9.2 and edge Rails. How do you go about fixing something like that? Well, here’s that god-damned clue you’ve been missing:

  • Attempt to duplicate it. People make mistakes, because they are people. Can you see what they did wrong? Is the bug still occurring in the latest (at this point in time, 2.3.5 & 3.0.0, yes, test both!)
  • If something is broken, attempt to fix it. This continues onto my third point:
  • Fix it! This is the most simplest, basic, elementary thing. You know the saying “If it ain’t broke, don’t fix it?” the reverse applies. Fix the ever-loving shit of it.
  • Can’t fix it? Find somebody who can. They exist. There’s a great probability that the problem is not as unsolvable as certain other problems in this world.
  • Can’t find somebody? You’re not looking hard enough. Ask in the IRC channels on irc.freenode.net. Ask in #carlhuda. Ask in #rubyonrails. Ask in #rails-contrib. Ask your friends. Post on the core mailing list. Six-degrees of separation means that you have the power to find somebody with the power to fix this issue.
  • Is this ticket no longer valid? Assign it to somebody who can close it. I’m now one of these people. Assign it to me and I’ll look over it.

Another thing to look at is how long the ticket has been a problem for and if it still applies to the latest version of Rails. Take for example this ticket which has been a problem since the 9th of January last year, when Rails 2.2 was the latest version. It’s still a problem in Rails 3, and this means it needs to be fixed. If one guy is suffering, how many other people who have not seen that ticket are? We must go through and judge every ticket before a major release. If I was in charge of a release process, this is how I would run the show. When I release a major version of my project, I want a clean slate, well, at least no bugs. Admittedly there may be some people who miss out on feature requests, but that’s what future releases are for.

Pissing on the fire

I think the Bugmash events are freakin’ awesome. But they only “piss on the fire”. What we need is a concentrated stream (think Amazon River) to quell the beast of 900+ tickets. Donate some of your time to the Rails project. Spend a concerted amount of your spare time this week, and next week, and the week after that, going through the tickets and finding something you can help fix. Every little bit of effort helps.

The Rails core team has only so much effort it can apply in any given timeframe, how about applying some of your own to speed up the process of bringing us closer to a final Rails 3 release?

I ask you, not as a Ruby on Rails core member (clarification: I’m not, nor desire to ever be “core”), but as a fellow Rails guy: let’s keep this Rails beast alive and kicking. Take some time out of watching your porn and actually do something useful. Otherwise, you are just another leech hanging on the side and whining about “it’s been so long between releases”. Did you ever stop to think that: “maybe there’s something holding up the release?” or “maybe there’s something holding up the release that I can help with?”.

Give back to the community that has provided this wonderful framework for your benefit.

Please.

Extra Links

Dan Pickett also has similar advice on contributing back to Rails 3. He makes a good point that if you are able to demonstrate that you have contributed to Rails that it looks awesome on your CV / Resume.

Kristopher Murata writes from the point of view who hasn’t contributed all that much to Rails, but really wants to.

Greetings YCombinator people! Thanks for making this story one of your favourites (peaked at #4). I have commented on your comments left on YCombinator and I appreciate the time you have spent writing them. I look forward to keeping up the correspondence.

Greetings also to the Ruby sub-reddit crew. Thank you for making this your 3rd most popular post and your comments (no matter how critical, all comments are good)

When Rails 3 is Due

April 5th, 2010 by Radar

As a person who hangs out in #rubyonrails on Freenode a little too much of his spare time, I eventually come across repeated questions. This is why I made the channel bot which runs on Summer.

One of the hardest frequently asked question is “When is Rails 3 due?”, the next being “When is Rails 2.3.6 due?”

To be honest I don’t know, and I’m pretty sure not even Rails Core knows precisely when it’s due. Sure, they’ll have some kind of idea of when they’d like it to be released but it’s a very similar idea to mine of wanting to be rich (i.e. right now). Ideas and realities are two entirely separate worlds.

On the 1st of April, Rails 3.0.0beta2 was announced by DHH. This announcement came very nearly two whole months after first Rails 3 beta announcement.

So why so long between releases? Well, lets go time traveling.

We travel back, back through time and its murk. We land spot bang in the middle of March 28, 2006. It’s on this day that a slightly-younger version of DHH announces Rails 1.1. Oh look it has RJS. How young and foolish we all were. By we, I mean you guys of course, this was at least 3 months before I even begun getting into Rails. So Rails 1.1 was born into the world on March 28th, 2006. Right then. What about the next significant version?

The next version would be Rails 1.2, let’s jump forward to the first Rails 1.2 Release Candidate on November 23rd, 2006. This is a distance of ~20,735,982 seconds (or in more sensible terms: 7 months and 27 days) between a major release (1.1) and a the next major release’s (1.2) release candidate. Ok, so when was the next release candidate?

That would be the second Rails 1.2 release candidate. Somewhere between these two releases I joined the Rails fray. The distance between releases? ~3,715,200 (or in more sensible terms: 1 month and 13 days). They really didn’t waste much time getting this out the door, and with so many changes too! Next!

So with the release candidates out of the way DHH announces Rails 1.2. This was a mere 17 days (~1,468,800 seconds in the “old money”) between release candidate and major release. 17 days (not a pattern) later, Rails 1.2.2 is announced. On Pi day in 2007, 36 days after Rails 1.2.2 is released, Rails 1.2.3 is released. Then nothing happens for a while.

During the 30th September, 2007 A Rails 2.0.0 Preview Release is announced. Surely the 2.0 release has to be close, right?

Between the 2.0 release postings, on the 5th of October, 2007, 6 months and 19 days after Rails 1.2.3 is released, Rails 1.2.4 comes out. Then a mere week later, Rails 1.2.5 is announced and released. Rails 2 work continued through these releases, as indicated by a Rails 2 release candidate announcement in the midst of November 2007. Rails 1.2.6 was announced 1 month and 12 days after Rails 1.2.5 was. This was to be the final version 1 release before Rails 2.

On December 7th, 2007, Rails 2.0 was released much to the joy of the Rails world. 10 days later Rails 2.0.2 comes out with “some new defaults and a few fixes”. Then nothing happens for a while, again.

Then Rails 2.1 came out, on the 1st of June, 2008, 5 months and 23 days later.

Some more patch releases were made after the Rails 2.1 release. The 3rd of September is when Rails 2.0.4, the first patch release is announced, 3 months and 2 days later. On the 19th October, 2008, another patch release Rails 2.0.5 is released. This is 1 month and 16 days since the previous patch release.

Rails 2.1.1 was released 3 months and 4 days after the Rails 2.1.0 announcement with “lots of bug fixes”. It seems they didn’t quite fix all the bugs as Rails 2.1.2 was released 1 month and 18 days later. The next minor release wasn’t far off, only 28 days, and that one was Rails 2.2.

It is important to note that it is around this point in time that the Merb + Rails merger is announced on the 23rd December, 2008. This merge would grow into what we will soon know as Rails 3.

The next minor release after that was the Rails 2.3 announcement, 3 months and 24 days later on the 16th March, 2009, the first release of 2009. The next announced release occurred on the 20th July, 2009: Rails 2.3.3. Some security fixes are announced, making Rails 2.3.4 a reality 1 month and 15 days after the Rails 2.3.3 announcement.

Then we get to the most recent stable version of Rails: Rails 2.3.5. This was released a total of 2 months and 26 days after Rails 2.3.4.

Now most recently, the Rails 3 betas. The first was announced on the 5th Feburary 2010, 2 months and 5 days after Rails 2.3.5 was released, which doesn’t mean much. What’s a more relevant statistic would be that it was released 1 year, 1 month and 14 days after the Rails + Merb merge was announced. The beta was a very large and sweeping change of just about everything in Rails, afterall, this is a major release. There is going to be some major differences.

Rails 3 beta 2, announced on April fools day, 1 month and 25 days after the first beta release. DHH says that this release is “hopefully our last stop before a release candidate” but again: nobody knows.

13 days after this, Rails 3 beta 3 is released and DHH says “we’re getting close to home now!”.

Once you know the release candidate goes out you’ll know there’ll be a huge hubbub of how momentous the ocassion is. I say everyone deserves a “huge round of applause” or whatever the internet equivalent is. The amount of work put in Rails 3 over the last year and a bit is tremendous. Then people can finally start (or continue, in some cases) migrating their plugins and gems over to Rails. Personally, I look forward to the day where I can begin a new Rails application using compatible versions of Cucumber and RSpec and the latest and greatest Rails 3 code.

This post is not intended to give a solid or even a vague guess at what the Rails 3 release date is going to be. If you want my personal opinion it’s going to be another 2 to 4 weeks (from April 5th, so April 15th-May 5th) before a release candidate. Pure, utter, guesswork based on observation. The regression tickets themselves do not seem overly complex and if they are the only thing in the way of a release candidate then I cannot see there being any major delay.

May 9th update: So I was wrong about the release candidate. It happens. Things get delayed. My new guess is that they’ll release+announce the release candidate at or near the beginning RailsConf. For now, I suggest that we all start developing our applications on it now, so that we can get something strong for the community.

Not staying in Scotland

April 1st, 2010 by Radar

So I posted earlier that I got offered a job in Scotland and was staying for a couple of weeks. (Un?)fortunately this is not the case. As of this writing I’m sitting very close to Changi Airport’s C23 in the “Laptop Access” area they have here getting my internet fix after a 12-and-a-half hour flight. Sitting in a middle seat. Scotland is a fantastic country and one day I may go back to visit it but for now my home is Sydney, closely followed by Brisbane. If something comes up that is irresistible then perhaps I will move elsewhere, but there are still plenty of opportunities in Australia for me and moving is such a ginormous pain in the ass. If I did move out of the country it’s more than likely I would have to sell everything I own and start afresh, a prospect I do not look forward to. I simply have too much crap, and I’m only 22.

So in summary: Staying in Sydney, not Scotland. Catch up with you all when I get the chance :)

Staying in Scotland

March 31st, 2010 by Radar

This past week I attended the Scottish Ruby Conference and for the week prior I was experiencing the joy that is Scotland. I have made a decision to stay on a couple of weeks and I apologise for those who I haven’t yet discussed this with.

Since the conference, I have been discussions with one of the local companies who wish to hire me to teach Ruby after my contract with GetUp has expired. I’m going to their offices in Edinburgh today for a meeting to discuss this. I think they’re fantastic people and it would be almost as much joy to work with them as it has been to work with GetUp and I would name them if it wasn’t for a damn NDA. GetUp’s going to be exceptionally hard to beat.

I may return to Australia to collect some things and put my affairs in order eventually, but Scotland just feels like the right place to be at the moment. It’s much closer to a larger number of countries than Australia with greater opportunities in the Ruby & Rails sectors and I love everything here.

Later on today I will contact GetUp and let them know that I’m still willing to do work for them, albeit remotely, and I hope they will understand.

More on this later. See you then!

Starsigns & Dreams

March 7th, 2010 by Radar

Now I know that you guys expect this to be like… pure technological content since I’m a technological kind of guy, but sometimes I do break the rules. This is one of those more of a “blog” and less of a “tutorial” or “code” post. Sorry. Just something strange has been going on. Oh, and it contains profanity. Sorry.

I’m not one who believes in fortune-telling, I think it’s a complete and utter scam. These people will tell you precisely what you want to hear so they and their brethren can get precisely what they want: your money. They tell you all these good things and to pay attention to your horoscopes and star signs and so on and so forth, so you’ll go out and buy all these books about it and effectively dedicate your entire life to knowing about what’s going to happen in your future.

Fuck you.

No, really. Do you think that you’re such “a beautiful or unique snowflake” that the stars, balls of burning Helium, Hydrogen and whatever the fuck else are actually representing your fate? That they are able to correctly predict what will happen to you in terms of life (love and not), money and well-being? Jesus H. Christ you people are fucked in the head. You are not “a beautiful or unique snowflake”. Your fate is entirely dependent on your actions. If you want something positive to happen: work the fuck towards it.

Do not get me started on Numerology, either.

My (read: your) God.

Now that I’ve got that whole little blurb out of the way I can go on telling a story of two exceptionally strange coincidences that have happened within the past week. Yes, I view them as “coincidences”, not as “messages from the stars” or whatever you loonies want to call them. Although occasionally I feel that something is causing these to happen but then I have a nice hard-dose of a little thing us sane-folk like to call “Reality” and I’m right as rain.

Coincidence #1.

A girl at work asked me if my Paypal account had any money in it, I thought it didn’t but I checked anyway. There was some in there and she asked if I could use $1 for it to test some of the site’s donation functionality as it was misbehaving. I did, and it was. Then I thought that the money would be best out of the hands of Paypal and better in the hands of my bank so I “wrote” a mental note to transfer it when I got home. I didn’t.

That night I dreamed of a person or people putting money into my Paypal account. I quite often dream of things related to the previous day, almost like it’s a consequence of them being committed to my long term memory or something. So in the dream as I receive the money and go to transfer it, naturally I wake up. I always wake up from dreams when it gets to the good part.

So I get out of bed and onto my computer and as soon as I open up IRC I receive a IRC private message from Zarathu who says that he appreciates all my help that I give him and others and would like to show his respect in monetary format. He sends me $100.

Go figure.

Coincidence #2.

I have flu-like symptoms and to help me sleep through them I’m taking Codral day & night tablets. When I take the night tablets I have really, really vivid and sometimes whack(er than usual) dreams. Last night’s major consisted of myself and an unknown person really agreeing on something, we were having a discussion about something but there were no details. But we shared a common idea.

Tonight Marcelo & his girlfriend cooked dinner for us all and Marcelo’s mother came over. We talk about what I do and Marcelo’s girlfriend asks if I do iPhone development. I say that I tried to get into it but I needed an app idea in order to learn the language. She says she has an idea but she won’t tell me it because she fears I will steal it. There’s this one application I’ve been looking for (and I won’t say it because YOU will steal it :)) since the iPhone came out and I ask “Is it something to do with …?”

Silence.

“How’d you do that?”, she asks.
“Do what?”
“Read my mind.”

We spend the next hour talking about how awesome this idea is.

So, I still view these as coincidences, but for something like this to happen twice in a week is kind of freaky.

Testing Facebook

March 2nd, 2010 by Radar

We’re currently adding Facebook integration to an existing application that uses Authlogic. That means adding a button that any user can press on the login form that then takes them to Facebook, signs them in and then lets them log into our site. For this purpose and the time being “Facebook integration” means only that: letting the user login with their Facebook details. For the Facebook side of things we’re using Facebooker which is not the well-documented library we all would hope it is. Oh, and you cannot use it as a gem with Rails.

Also along with Facebooker we also use the Authlogic Facebook Connect plugin to provide us with a button we use on our login form. It also provides us with a file called xd\receiver.html in our public folder which’s use is documented here.

We created our application.html.erb using these key elements, as specified in the Authlogic Facebook Connect README:

<html>
  <head>
    <%= javascript_include_tag :defaults %>
    <%= fb_connect_javascript_tag %>
  </head>
  <body>
    <%= fb_connect_javascript_tag %>
    <%= init_fb_connect "XFBML" %>
  </body>
</html>

Our login page is nothing out of the ordinary save for this tag placed where we want the button to connect to Facebook:

<%= authlogic_facebook_login_button :length => "long" %>

As stated in the Canonical Documentation because we’ve generated the button the Javascript included into the layout will be executed when the user visits the page. This Javascript then calls the FB.init("YOUR_API_KEY_HERE", "xd_receiver.htm"); which does some Facebook/Javascript magic I am still yet to comprehend. This voodoo eventually renders a button that your user can click. When your user clicks this button it opens a popup window that asks the user to log into Facebook if they aren’t already, otherwise this will do a “seamless” login. We’ll go with the first option here and assume the user hasn’t logged in. But by the time you’ve read this, they have logged into Facebook and now the Javascript continues to execute, retrieving values from the popup window and stores them as cookies. After this is all “said and done” your form will be submitted and your app will carry on its merry way.

Here’s the beginning of our Authlogic-juiced User model:

class User < ActiveRecord::Base
  acts_as_authentic do |c|
    c.session_class = UserSession

    c.login_field = :email
    c.validate_login_field = false
    c.validate_email_field = false
    c.validate_password_field = false

    c.ignore_blank_passwords = false
  end

  # Validations for email based accounts
  with_options :unless => :facebook_uid do |u|
    u.validates_presence_of :email, :message => :missing_email

    u.validates_presence_of :password, :on => :update, :if => :require_password?, :message => "^You must enter a password."
  end

  with_options :unless => Proc.new {|u| u.email.blank? } do |u|
    u.validates_format_of :email, :with => Authlogic::Regex.email, :message => "^The email given looks invalid, please check for typos."
    u.validates_uniqueness_of :email, :message => :email_in_use
    u.validates_confirmation_of :email, :message => "^The emails given did not match."
  end
end

As you can see here if facebook_uid is present we are not validating the presence of email or password for obvious reasons.

When your form is submitted it’ll go a create action in a controller (we called ours UserSessionsController) and looks like this:

class UserSessionsController < ApplicationController
  before_filter :check_fb, :only => :create
  #...
  def create
    @user_session = UserSession.new(params[:user_session])

    if @user_session.save && !@user_session.user.suspended?
      unless @user_session.user.facebook_uid.nil?
        @user_session.user.active = true
        @user_session.user.save
      end

      flash[:notice] = t(:msg_welcome)
      if @user_session.user.login_count > 1 && @user_session.user.last_login_at?
        flash[:notice] << " " << t(:msg_last_login, @user_session.user.last_login_at.to_s(:mmddhhss))
      end
      redirect_back_or_default root_url
    else
      #...
    end
  end
  #...
  private

    def check_fb
      if params[:user_session].nil?
        ensure_authenticated_to_facebook
      end
    end
end

We have specific code here to activate a user if they log in through Facebook; we assume that if a person is logging in through Facebook that they are not an automated robot (as opposed to a manual one?) and they do not need a confirmation email sent. What’s most exciting about this code however is not the create action, but the before_filter we run… erm, before… it.

As you can see, the before_filter calls ensure_authenticated_to_facebook which is a method from Facebooker, traditionally used itself as a before_filter but because we have the ability to log in with an email & password OR a facebook login, is called conditionally. That method looks like this:

def ensure_authenticated_to_facebook
  set_facebook_session || create_new_facebook_session_and_redirect!
end

This attempts the set_facebook_session method first:

def set_facebook_session
  # first, see if we already have a session
  session_set = session_already_secured?
  # if not, see if we can load it from the environment
  unless session_set
    session_set = create_facebook_session
    session[:facebook_session] = @facebook_session if session_set
  end
  if session_set
    capture_facebook_friends_if_available! 
    Session.current = facebook_session
  end
  return session_set
end

We do not have a current session so it’ll go and call create_facebook_session:

def create_facebook_session
  secure_with_facebook_params! || secure_with_cookies! || secure_with_token!
end

So this uses three methods: secure_with_facebook_params!, secure_with_cookies! or secure_with_token. Remember what I said earlier about what happens when the user presses the button? No? Here’s a refresher: it sets cookies. Not the edible kind, sadly. So the method that’ll be used here is secure_with_cookies!.

I feel now is a good time to show you the test we wrote.

describe UserSessionsController do
  describe "create" do
    describe "facebook user" do
      it "creates account based on facebook details" do
        Facebooker.use_curl = false 
        FakeWeb.allow_net_connect = false
        FakeWeb.register_uri(:post, "http://api.facebook.com/restserver.php", :body => Rails.root + "spec/fixtures/get_users_info.xml")

        setup_fb_connect_cookies

        post :create

        response.should redirect_to(root_url)
        @assigned_user = assigns[:user_session].user
        @assigned_user.new_record?.should be_false
        @assigned_user.active.should be_true
      end
    end
  end
end

The Facebooker.use_curl = false is only neccesary if you have the curb gem installed. Hat-tip to Balvig in the comments!

We first disable internet connections using FakeWeb. We do this so we can stub out the response to Facebooker’s internal call to getUsersInfo to Facebook and always return a valid user object. The fake XML can be viewed in this gist.

After Fakeweb has done its thing we call the setup_fb_connect_cookies method which does exactly what it says on the box, it lives in the spec/support/facebook_helpers.rb file:

def setup_fb_connect_cookies
  cookie_hash_for_auth.each {|k,v| request.cookies[ENV['FACEBOOK_API_KEY']+k] = CGI::Cookie.new(ENV['FACEBOOK_API_KEY']+k,v).first}
end

def cookie_hash_for_auth
  hash = {"_ss" => "not_used", "_session_key"=> "whatever", "_user"=>"77777", "_expires"=>"#{1.day.from_now.to_i}"}
  raw_string = hash.map{ |k,v| [k.gsub(/^_/, ''), v].join('=') }.sort.join
  actual_sig = Digest::MD5.hexdigest([raw_string, Facebooker::Session.secret_key].join)
  hash.merge("" => actual_sig)
end

Why such complicated code? Well, this provides the cookies that Facebooker needs in order to log in. The final three lines in the cookie_hash_for_auth method is all about setting up a “signature” which Facebook parses in the parameters to ensure that they haven’t been tampered with. The generation of this was ripped straight from the guts of Facebooker which uses (almost) the same code to generate an MD5 to verify the signature against.

In short: We now have cookies that our post :create is going to use. So, when this is triggered secure_with_cookies! does its thing:

def secure_with_cookies!
    parsed = {}

    fb_cookie_names.each { |key| parsed[key[fb_cookie_prefix.size,key.size]] = cookies[key] }

    #returning gracefully if the cookies aren't set or have expired
    return unless parsed['session_key'] && parsed['user'] && parsed['expires'] && parsed['ss'] 
    return unless (Time.at(parsed['expires'].to_s.to_f) > Time.now) || (parsed['expires'] == "0")      
    #if we have the unexpired cookies, we'll throw an exception if the sig doesn't verify
    verify_signature(parsed,cookies[Facebooker.api_key], true)

    @facebook_session = new_facebook_session
    @facebook_session.secure_with!(parsed['session_key'],parsed['user'],parsed['expires'],parsed['ss'])
    @facebook_session
end

This has now generated a value for session[:facebook_session], a Facebooker::Session object. Great. The @user_session in our controller has a user method that returns a valid user and we ensure it’s that way in the remainder of the controller test. Great, so that part works. Now about how doing something with the logged in user?

Well for that purpose, Elad Meidar wrote a blog post covering how to do it in Cucumber. This consists of setting up your facebooker.yml to having a cucumber key share the configuration of the development key and a couple of steps:

Given /^I am logged in as a Facebook user$/ do

  # Initializer facebooker session
  @integration_session = open_session

  @current_user = User.create! :facebook_id => 1

  # User#facebook_user returns a Facebook::User instance, i decided to mock the session in here since i am not
  # sure what the behavior might be if it will be in the actual model.
  @current_user.facebook_user.session = Facebooker::MockSession.create(ENV['FACEBOOK_API_KEY'], ENV['FACEBOOK_SECRET_KEY'])
  @current_user.facebook_user.friends = [ Facebooker::User.new(:id => 2, :name => 'Bob'),
    Facebooker::User.new(:id => 3, :name => 'Sam')]
  @integration_session.default_request_params.merge!( :fb_sig_user => @current_user.facebook_id, :fb_sig_friends => @current_user.facebook_user.friends.map(&:id).join(',') )
end

This code sets the parameters on the next request and Facebooker accepts these and uses them to create a new Facebooker::Session object, which it stores in session[:facebook_session].

The open_session method comes from Facebooker by placing this line in features/support/app.rb:

require 'facebooker/rails/cucumber'

The facebook_user method on our User object comes from defining it on the User model:

Now with the steps and correct requires in place, we have our feature:

Feature: Facebook
  In order to use the site as a facebook user
  As a user
  I want to have already logged in with Facebook and be roaming the wide brown lands

  Scenario: logging into facebook
    Given I am logged in as a Facebook user
    And I am on the homepage
    Then I should be on the homepage

This is just a silly example that ensures that the user is not redirected back to the login page if they are logged in as a Facebook user. I hope you write better features than this. This feature will fail for the time being because our current_user method only queries current_user_session, so we’ll modify it to be this instead:

def current_user
  @current_user ||= (current_user_session && current_user_session.record)
  @current_user ||= User.find_by_facebook_uid(session[:facebook_session].user.uid)
end

Now we can use current_user to reference current Facebook users too, meaning our feature will now pass.

With a controller spec and feature passing, that’s lunch!

For After Lunch

So how was lunch? I hope it was good. Since this is only a one-way kind of communication I can’t accurately respond to whatever you’re going to say. Sorry!

Right then! So our application is tested well enough that we know that we can log in using faked-out Facebook cookies, but does the actual real-world side of things work? Does clicking the button actually prompt the user to log into Facebook if they haven’t already or just go through that whole section transparently and present them with an already logged in screen?

Chances are this is a big, gigantic, fat

No.

You’ll more-than-likely run across an “Invalid parameter” issue as we had when we tried to use our application. The error code for this is 100.

So what’s up?

Well, as it turns out, when you try to go to the login page for an application that hasn’t yet been activated it just warns you that it hasn’t been activated. I’m not quite clear on how Facebooker works in this particular section, but it is my understanding that the login page is supposed to take you to the application page. Let me explain in step-by-step kind of way. “application’s page” means your site in this scenario. You’ve set this up by specifying the “Connect URL” in the “Connect” section of your Application Settings page to be the root-level of your site. So this is how Facebooker does its thing:

  1. Facebooker grabs an auth_token using the facebook.Auth.createToken API method. This returns something like 72a910e1f24eb6034549d23cd2245f28
  2. This auth_token is then passed to http://facebook.com/login.php as a parameter, which is rendered in whichever fashion you wish. For all intents and purposes, our application renders it in another browser window.
  3. The login.php page detects if you are logged out or in and does either:
  4. If you’re logged out of Facebook, prompts for an email and password. If you “get this right”, Facebook sets up some cookies, links that auth_token to your Facebook user, and redirects you to the application.
  5. If you’re logged in to Facebook, Facebook sets up some cookies, links that auth_token to your Facebook user, and redirects you to the application.
  6. The cookies are then used to call facebook.Auth.getSession which, because you’re now most-definitely logged into Facebook, will return a session object. Something that looks like:

    2.5KVyRHmZWBbOun8ZwDwQxg__.3600.1243290000-608966587\n  608966587\n  1268190000
    

  7. Facebooker creates a Facebooker::Session object based on this return value which it stores in your application as session[:facebook_session]
  8. What could possibly go wrong is that if you have your application in “Sandbox Mode” (under “Advanced” in “Application Settings”), when you go to the login page you’ll be shown the “This application is under construction” and therefore Facebook will not link your user account with the auth_token so when facebook.Auth.getSession tries to do what its name implies: it’ll fail with “Invalid Parameter”. Just be careful about that! It had us caught up for a day and bit, we didn’t know about that option.

    I hope you found this as informative as I found it interesting to investigate.

Congratulations

February 13th, 2010 by Radar

Congratulations! You’ve worked so amazingly hard over the last seven-and-a-half months on this project. You met all the client’s demands as they came in. You completed the project on-time and under the $30,000 budget by $2,000. The client is pleased about that. You can tell by the dollar signs in his eyes. The client is also pleased that they’re able to put the website out to the world to grow and conquer it, it already has a couple of users from the beta invites you sent out earlier in the week. You still keep in touch with the client on an almost-daily basis. He’s saying the site’s doing great.

But.

There’s this one user who’s reporting an issue with a feature you worked on 3 months ago. The client has set up his personal email address to receive the bug reports. You receive them when he gets around to sending them. A page is showing “We’re sorry but something went wrong”.

Uh oh.

You log into the website and check for yourself. Sure enough that page is throwing a 500. But why? This feature was completed 3 months ago and worked fine then, didn’t it? You try it on your local machine and you see that perhaps it’s something simple. Perhaps a variable incorrectly spelled in the controller. Or perhaps not. Perhaps it takes you longer than a couple of seconds to identify the issue. Perhaps it takes you an hour, a day.

A week.

So how did this error come to be? You did write tests, didn’t you?

Oh I see.

Because of the impending deadline you were pressured for time and couldn’t be bothered learning any of the testing frameworks. You want to. So many people talk about it in such a positive attitude… it’s just you don’t have the time. When you bring the point up, your boss says “The client’s not paying you to write tests, he’s paying you to write features” Even though your Rails knowledge has increased during the life of this project three to four times the size of what it previously was, you still don’t know shit about testing. Maybe’s the time to start to learn you think. Ah, but The Boss doesn’t want you spending time not producing features. “Tests are a waste of the client’s money” he claims. You sigh. “I’ll do the next project better. I’ll get him to see the light. I’ll really push for testing…”, you say in your head. Ok, so you didn’t write tests.

So here’s the facts:

  • There’s a bug.
  • You worked on it in the past.
  • You must fix it. Now.

So how do you go about debugging this bug to ensure that it doesn’t happen again? Well, you fix it and you know that it won’t happen again because you fixed it, right? You’ll leave a decent comment (actually, you’ll think about leaving a decent comment) after it’s fixed, that way nobody will repeat your mistake. Right?

Wrong.

Alright, so you know it’s sometime in the past. You can view the list of branches and maybe one will trigger your memory, surely you have branches with memorable names?

“Two Strikes” you say? Shame about that. Oh yeah, branching in SVN is a pain in the ass. I agree. If only you could convince your boss to use Git too. Git’s branching is so much nicer. Maybe you’ll get him to “see the light” about that on the next project too. So all the changes are in the trunk, and going back through them is, of course, going to take a lot of time. Best of luck with that.

So let’s assume that you chance across it. You remember the revision and fix the bug. Gone. Dead. Destroyed. Defeated. Sent to the depths of Hell along with one eighteenth of your sanity. That was quite a toughy. You did write a regression test to ensure that it wouldn’t happen again, right?

Oh I see.

You commented on the Basecamp todo item saying that it was fixed. I guess it has a searchable name, right? Just in case it comes up again? It’s called “Something went wrong” or “Page is broken”?

Uh oh.

So you go home, satisfied that you kicked the ass of a bug that had been on your mind for days. You win.

Congratulations.

The next day you wake up, grab your coffee/milk/orange juice and check your emails. There’s 3 from Facebook, a couple from a few mailing lists you subscribe to and fourteen from your client. These aren’t fourteen love letters. You see the first one was sent to you 20 minutes after you went to bed. If only you had stayed up later.

You read the first one. It’s a bug report. So is the next one. And the one after that. And the one after that. And guess what? The one after that, too.

All fourteen emails your client sent to you overnight weren’t “Thanks for all your fabulous work on the site” they were the “Why the fuck is this shit broken?” kind of language. He paid good money for it he thinks. You are happy being paid whatever it is you earn. It hasn’t been long that you’ve been doing this anyway and you have to start out somewhere. People make mistakes, right?

Congratulations.

You now have bug reports to deal with when you get into work this morning. 8 hours in a day, with each bug taking you 30 minutes to do. Easy, with time to spare. “Pfft. Done by sundown”, you think. You realise that one of the bug reports that got sent in was that bug that you fixed the other day. Another developer working on your project had a conflict with the file and accidentally put back the broken code instead of the working code. Ok. That’s fine. You’ll fix that again. Maybe you never wrote that comment and you insert it now. Yeah, that’ll stop them re-introducing it.

You have a 2hr meeting with another client at the beginning of the day, leaving you with only 6 hours to fix those bugs by sundown. You spend an extra half-hour at lunch. Five-and-a-half-hours. But by lunch you’d already “killed” four of them. You were a bit groggy this morning and you think that lunch will cure that feeling. You’ll conquer the other ten this afternoon.

You don’t.

You finish four, maybe five of them leaving eight, maybe nine bugs fixed. The client is not pleased. You have only done some of the work. ALL the bugs were critical. Your company is small, and you’re the only one with the knowledge of the project, plus, the other developers are busy on their own projects. The client expects… DEMANDS… a 7-day-a-week-24-hour-all-the-freakin’-time response.

Because you’re his bitch.

Alright. So your boss gives him a large apologetic email that you will try harder in the future to meet all of his demands because you don’t want to lose this client. He’s invested $30,000 in this company already and with “Version 2″ of the site “just around the corner” he’ll probably invest a lot more.

So you’re back to fixing those remaining bugs. During the night another three have come in. Your bug count is now eight. Eight hours in a day, eight bugs in the list. Done by sundown. You complete five during work hours and two when you get home, after dinner. You’re exhausted. They took you all day to debug. You email the client and say that you’ve only fixed seven of the eight bugs. He emails you back, naturally twenty minutes after you’ve gone to sleep saying that the eighth and final bug “makes the site unusable”. Your boss brings you in in the morning and says that your work isn’t good enough. You baulk at this suggestion. You claim to have fixed thirteen of the fourteen bugs the client emailed you earlier in the week. You feel that you’ve put in some exceptionally hard work this week. Today you’ll have completed the fourteenth one, you’re so confident about that. He naturally asks why there were fourteen bugs in the first place. You don’t have an immediate answer, although you think of mentioning testing. He continues on his rant about that you should be testing the code each time you deploy it. Go through the site and make sure that it’s ok, you know, just click on the links and sure it’s working. The boss continues on his tirade for an hour. You try to counter his arguments but you view him as some sort of “higher-being” and due to your lack of experience you can’t fault him. He’s the boss man after all. He got there somehow. He’s gotta be right about everything?

Your company has accrued all this technical debt that you didn’t budget for. This carries on for a month longer and now the client has gone over his budget by $2,000. $2,000 he never wanted to spend. Instead of saving $2,000 he’s now spent an extra $2,000 out of his own personal account in order to get this going. He’s talking about leaving your company and moving to another one who could do a better job. This is probably the case. Your boss brings you in and tells you what’s what with this project. The client is leaving. The next day he fires you.

Congratulations, Freebird. You’re out of a job and very, very nearly out of money. A couple of grand is all you have left. Time to begin that hunt again.

So how do you prevent something like this from happening?

You eventually get a new job working with a new company. You sit down with your new client and you do it right. You spec out their application’s stories using something like Pivotal Tracker. You’re taught to write tests religiously for every single story in Cucumber. There isn’t a story without a test. This reduces technical debt in the long run. You won’t have as many bugs like you did when you didn’t test with the previous application. You will have bugs, though, but you won’t be spending those long nights fixing them because you have tests covering it all. The tests will show you where something went wrong because more than likely, a broken part of the site also means a broken test. See a bug that’s not covered by a story or a test? That sometimes happens, but now you have this wonderful framework for really ensuring it doesn’t happen again: Regression testing. Write the test. It breaks. Fix the bug. It passes. If you and your team stick to the Green is Good policy, then you and they will NEVER EVER reintroduce this bug. In theory, anyway. People make mistakes.

So you start off on a simple story such as “User login” and you write a cucumber feature for it with two scenarios. One for logging in. One for logging out. You’ve written all the steps for it but some of them are not implemented, others are just plain broken. That’s because you haven’t written any code for it yet. It may feel backwards at first. This is called Behaviour Driven Development. You’re going to be learning it, and you’re going to do it right from now on. You’re going to be a BDD Zealot. You implement each step one at a time and eventually your feature is all green.

Why do you do this?

So future-you doesn’t come back in 3 months, see that this feature is broken and begin working on a time machine to go back and kick your dumb ass.

Bonus points if you’re using a Continuous Integration server to ensure that this feature and its eventual test brothers stay green. A broken build means a broken application and your singular goal if that build is ever broken is to make it very, very unbroken.

Congratulations.

You can now mark that story as “Finished” in Pivotal. Then you can deploy it to a staging server and mark it as “Delivered”. The client then can log in to Pivotal and see that the story is marked as “Delivered” and then log in to the staging server, test that feature and press that lovely holy-grail “Accept” button. You want to be seeing green stories in your Pivotal list. Green is the colour you want to be seeing everywhere.

Green is Good.

So the next feature comes along and involves some rather complex controller logic that returns a JSON hash. You can write this also in Cucumber, or you could write an RSpec Controller test. This is the kind of thing that’s really great for in-team discussions. You’ll suggest Way A of doing it, and maybe the other team people will agree or suggest Way B, and that lovely dynamic of throwing ideas back and forth really produces a better result. Either way, you’ll write the test first and then the code. Behaviour Driven Development. Then the test will pass. Then you can refactor the code if it’s not quite up to scratch and it’ll still pass. Sure it will feel slow at first, but that’s because you’re learning how to do it. Don’t fight it. It will save you a lot of time in the future, where it’s most important. Focus rather on the long term gains rather than the short term.

Eventually after the next seven-and-a-half months you’ll have all these Pivotal Tracker stories all green in the “Completed” section and maybe one or two in the “Backlog” that the client wants done for next release. You’ll run all the specs on your system. They’re all green. You’ll run all the features. They’re all green. You deploy to the staging server for the last time for this release. The client loves it. You deploy it to production and send out the invites. Everyone loves it.

But.

There’s a bug. This time however you’ve installed something like Hoptoad so in your inbox you’ve got the error there, right when it happened. You are the support team for this application, NOT the client. After all, you’re still working for a small company. It contains stacktrace and you can see where it went wrong immediately. You write a test/feature to ensure that this bug would never happen again. It fails because you haven’t fixed the bug. The error is the same one as in the Hoptoad email. You fix the bug.

Congratulations. You’ve successfully regression tested a bug. This bug never happens again for the life of the project.

The client is happy. Your boss asks if he can have a chat with you. You’re doing an awesome job. The other guys were previously on a higher salary than you because you were perceived to be a junior. Not any more. You’ve come an amazingly long way. Now you’re equal. The client wants more work done on his application. He’s flying your boss to his offices next week. They’ve specifically requested you to go along too, as you seem “switched on”. You meet up with the client and discuss the terms of the next iteration, a major one. This deal goes through and your company needs to grow. Massively. The application explodes, in the positive meaning. You run into scaling issues (of course). You bring on another ten guys over the next year just to work on this application. You and a couple of the other “Originals” teach them all you know about your application and the process you’ve helped develop. They then go on to teach the other twenty people you hire in the six months following.

Congratulations. Now you’re doing it right.

The Initialization Guide

February 8th, 2010 by Radar

For a couple of weeks now I’ve been writing a guide on how the initialization process in Rails 3 works. As of writing, the guide and its accompanying “notes” totals over 10,000 words. I admit that this is currently nowhere near completion, but I am working on it and I need your help. I need people to go over it for me and point out anything that they don’t quite understand or I have stated incorrectly and file an issue on the repository for it. Originally I was going to accept pull requests but they aren’t “public knowledge” and I don’t want two or more people submitting pull requests to fix the same chunk of code. With issues, people can see that “oh, there’s already a typo here.” and move on to finding more errors and punching more holes through it.

So yeah, if you guys could read my guide and file any issues you find with it, that’d be swell!

Computer Woes

February 1st, 2010 by Radar

Today I had to deal with two Windows-based computers’ problems for Mark and Marlene. Here’s what happened.

Mark

Mark has a 4 year old Compaq Presario f500 which occasionally when you switch it on it’ll keep rebooting itself without showing anything on the screen. The fix for this was to turn it off, leave it off for a couple of seconds and then turn it back on. Then the problem went away until you turned it off and on again, in which it would resume. I couldn’t figure this one out. The other problem Mark had with his computer is that when he left it alone the screen would go strange. We figured out this was his screensaver, and changing away from the “Pictures Slideshow” option fixed it. I suspect there’s something in there that isn’t quite right.

Marlene

Marlene’s daughter has a recently bought no-name-brand case with a no-name-brand motherboard in it. Marlene had the computer at her house because she told me about the issue last night and I couldn’t fix it over the phone and her house is easier to get to than her daughter’s. The issue was that the computer wasn’t getting past the first POST screen, the one with the CPU & Memory information. I opened up the case when I got to Marlene’s house and saw that the cable for the CPU fan had a tiny cable tie clip on it that was stopping the CPU fan from spinning. Apparently this stops the computer from getting past that point! I moved it out of the way and tucked it around some other cords to make sure it wouldn’t get in the way again, sealed the case and tested it, it worked and so I thought that was that.

Until 5:30 tonight.

Marlene phones me up. The computer’s making a beeping noise. I can hear it in the background, “BEEEEEEEEEEEEEEEEEEEEEEEEEP”, pause, rinse, repeat. One long beep. It wasn’t doing that earlier. So I trek as far north in Brisbane as I have ever gone to play around with this box. I needed to fix this problem as I felt it was something I did. I get there and sure enough it’s making the “BEEEEEEEEEEEEEEEEEEEEEEEEEP” noise. I take the side off the case and the cord for the CPU is where I put it and that fan’s spinning alright.

I looked it up on Wikipedia and it said that it could have been a memory issue, so I took that out. No change. I took out the graphics card. No change. I took out the sound card. No change. I unplugged the power and data cables to the harddrives and DVD drives. No change.

What the hell?

I was on the verge of giving up so I just put everything back in the case one thing at a time, starting with the graphics card.

CHANGE!

The computer emitted a singular quick beep indicating successful POST and a choir of angels was heard in the distance.

Pieced it all back together and it booted fine. Did the ol’ go-through-and-remove-all-the-spyware-shit-that-builds-up routine and another happy customer!

tl;dr:

  1. Wacky screen after a period of non-use? Try changing your screensaver.
  2. Long singular beep? Ensure the PCI cards are seated correctly.

Why Mocra Is Awesome

January 21st, 2010 by Radar

Mocra is awesome because their employees are some of the brightest and most “switched on” people I know. They come up with fantastic ideas and execute them brilliantly. They even sometimes allow their employees to work on open source during work hours. Putting that much brainpower into a company that small is a genius idea. Yes, they’ve struggled. But what small business doesn’t? It’s still in its early phase and they’ve refined their process down to a tee and are really getting their stuff together. I fully support the company and will remain friends with them all. If you’re looking to hire a Rails company for your new/existing Rails application, hire Mocra.

Now to being completely honest with everyone.

I’ve decided that I want a change. As of today, I am no longer employed by them. I’m not sure how to phrase what went down. I got angry, and left. This had happened before. Later Nic called and asked me to come in to have a chat the next morning. This is entirely my fault. I wanted to leave for a while, to explore what else is out there. With freelancing, I got that power to travel and work with different people. I know the whole “grass is greener” cliche, and I’m aware of that. I need something different, perhaps to only focus on one project instead of multiple at a time? I’m not quite sure. Freelancing was fun, but it’s also very, very lonely. I’ve had a couple of leads but I think it’s too soon to be jumping into another job. I need to realise that, attitude wise, I need to change it. I’ve changed it since NetFox quite a lot with some of that due to a little book called “How to Win Friends and Influence People” by Dale Carnegie. The suggestion to read this book came from no other than Dr. Nic himself. I read it and realised there were some things in there that I wasn’t doing and that would not only improve my life, but the life of the people around me. It did exactly that.

One thing the book does not have a chapter for is anger. When we went to the Ski Trip at Thredbo I got angry with a waitress because I wasn’t served a steak. Everybody else’s order came out, and mine was simply lost in the process. They made a mistake, and I got angry for no real reason. The waitress apologised but the mistake was done! How dare she stuff up my order! She’s supposed to be a professional. I could put this down to the fact that I was tired, but that should not be used as an excuse. As long as I have the ability to breathe I should have the ability to be polite and analyse a situation before showing my emotional response. This is what I need to continue to refine. There’s no showing you how much I’ve improved since the school days, since Netfox, I can only state that I have.

And only yesterday did I lash out at Bo. I had just received an email for my car damage. I had scraped the side of it and destroyed the right mirror by reversing along side a pole at a shopping center. I was angry at myself then, and that level of anger I believe was acceptable for that situation. I made a mistake, and it was going to cost me money. The email said the repair and the service was going to cost $1,500! I tried to bottle it up and shrug it off, but it ate away at me inside. $1,500! GONE! For what? Shortly after I was writing a bash script to change the keymappings for a plugin Mocra uses called Telefrag. This plugin works with Teleport and allows me to type in QWERTY when Bo or Chendo is typing in Colemak or Dvorak respectively, dismissing the need to switch keyboard layouts with a shortcut. The script wasn’t working as I wanted it and Bo suggested something whilst I was trying something else, and I said something angrily at him. This is an unacceptable case of showing my anger, and therefore I failed, again. I was not angry with Bo and he’s not the one who cost me $1,500. It was me. Getting angry like that cost me my job and I fear could cost me future employment opportunities and eventually leave me in a worse state than where I am at now. I need to stop getting angry so easy and over such trivial things. I need to learn how to.

Mocra is awesome, I failed them and am now unemployed again due to my, and only my, actions. I will fix this, I promise you. This post needs to exist so that people can show it to me, remind me of it, snap me out of it. I will always remember how bad I felt writing it, but also how much of a relief it was to get it off my chest. Yeah, future employers may see this. At this specific point in time I am still human, and therefore still have emotions. This is me describing my journey of controlling them for self-betterment.

Thanks to those who have offered their support over the past 24 hours (friends & family), you have all been brilliant and without such a group I would have probably done something drastic. If you guys ever need anything, I am always available for a chat, as you have been for me. I don’t care if it’s 4am. Call me if we need to talk. I’m there.

Seriously, hire Mocra. They have been fantastic, and I know that they have, can and will succeed.