Hello, I’m Jim Van Fleet

My friends call me @bigfleet.

about me

I make computers do what I want, more or less.

I am growing my freelancing business, it’s bspoke.

I cofounded TechBreakfast CLT with Vic Howie.

I am launching a Charlotte software school this fall.

I’ve published a newsletter for Charlotte startups for over two years.

I’ve attended or co-organized every Charlotte Startup Weekend.

recent public projects

Status updating…

found on

contact at

jim@jimvanfleet.com

Deferred Work Using Sidekiq

- - posted in lpca

As we’ve discussed at certain points in the past, user experience is extremely important, and back-end developers have a lot to do with that as well. Many users can deal with ‘ugly’ if the interface is clear, but no one on Earth likes slow! We’ll look at how to take needed work out of the request/response cycle in this exercise.

Step 0

We’ll be revisiting the house project with this exercise. I’ve merged the work that we’ve accomplished into master, so that you’ll be able to either update your forks, or pull the changes down locally.

What’s that, you weren’t working on a branch when you made your changes, and you can’t apply my changes quickly?

If you have made changes on master that are now irrelevant, try issuing these commands:

Terminal
1
2
3
4
git commit -a -m "Saving my work, just in case"
git checkout -b save-my-work
git branch -D master
git checkout -b master -t origin/master

That should get you ready to work again. But create branches when you start working! It’s easy! Here’s the branch I’d start here:

Terminal
1
git checkout -b friend-graph-sidekiq

Step 1

Add these files to your Gemfile:

Gemfile
1
2
3
4
5
gem "koala", "~> 1.8.0rc1"
gem 'sidekiq'

# add this in the test group
gem 'mocha', :require => 'mocha/api'

Install them. You should know how by now! Ask a neighbor if you don’t.

Step 2

Put these contents in spec/models/social_connection_spec.rb

spec/models/social_connection_spec.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
require 'spec_helper'

describe SocialConnection do

  describe "validation" do
    subject{ build(:social_connection) }
    it{ should be_valid }
    it "should require a user" do
      build(:social_connection, user: nil).should_not be_valid
    end
    it "should require a provider" do
      build(:social_connection, provider: nil).should_not be_valid
    end
    it "should require a uid" do
      build(:social_connection, uid: nil).should_not be_valid
    end
  end

  describe "associations" do
    it "should be present on user" do
      build(:user).respond_to?(:social_connections).should == true
    end
  end

  describe "Facebook" do
    let(:user){ create(:user) }

    describe "interface" do
      subject{ FacebookInterface.for(user) }
      it {should_not be_nil}
      it {should be_a(FacebookInterface::StubInterface)}
    end

    describe "usage" do
      let(:fbi){ FacebookInterface.for(user) }
    end

  end
end

This will give you a spec to pass! Run your specs with either:

Terminal
1
bundle exec guard start -i

or

Terminal
1
bundle exec rake spec

if you know that guard isn’t working for you.

To pass this test, you’ll need to:

  • create a model with the right fields and types
  • add the proper associations throughout the domain
  • add validations to the class you create

If you’d like a hint, download this file into spec/factories/social_connections.rb, or simply refer to it inline.

Our goal with this step is to create a record that allows us to keep track of some basic information for social connections on the part of our users. When you have this spec passing, you have the domain layer ready! Now let’s proceed to the integration.

Step 3

I’ve braved the wilds of koala to bring you this super simple usage for the Facebook API. Place this file in app/interfaces/facebook_interface.rb.

app/interfaces/facebook_interface.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class FacebookInterface
  def self.for(user)
    auth = user.authentications.where(provider: "facebook").first
    return if auth.nil?
    return if auth.oauth_token.nil?
    FacebookInterface.new(Koala::Facebook::API.new(auth.oauth_token))
  end

  def initialize(api)
    @api = api
  end

  def friends
    @api.get_connections("me", "friends")
  end

  def friend_detail(id)
    @api.get_object(id)
  end


end

We don’t want to hit the API as we’re testing, so let’s bring in this standin.

spec/support/facebook_interface.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
class FacebookInterface

  class StubInterface

    def friends
      [
        {
          "name" => "James Schaffer",
          "id" => "11670"
        },
        {
          "name" => "Brian O'Malley",
          "id" => "615125"
        },
        {
          "name" => "Greg Staff",
          "id" => "1507686"
        },
        {
          "name" => "Katherine McNerney",
          "id" => "1530325"
        },
        {
          "name" => "Joel Bonasera",
          "id" => "1905046"
        },
        {
          "name" => "Denny Abraham",
          "id" => "1911249"
        }
      ]
    end

    def friend_detail(id)
      {
        "id" => id.to_s,
        "name" => "James Schaffer",
        "first_name" => "James",
        "last_name" => "Schaffer",
        "link" => "https://www.facebook.com/jas.schaffer",
        "username" => "jas.schaffer",
        "gender" => "male",
        "locale" => "en_US",
        "updated_time" => "2013-09-23T02:08:44+0000"
      }
    end
  end
end

FacebookInterface.stubs(:for).returns(FacebookInterface::StubInterface.new)

Place this file in spec/support/sidekiq.rb

spec/support/sidekiq.rb
1
2
require 'sidekiq/testing'
Sidekiq::Testing.fake!

Finally, place this spec in place in spec/models/facebook_friend_worker_spec.rb:

spec/models/facebook_friend_worker_spec.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
require 'spec_helper'

describe FacebookFriendWorker do

  subject{ FacebookFriendWorker.new }

  it "should include the line 'include Sidekiq::Worker'" do
    subject.respond_to?(:jid).should == true
  end

  context "when processing friends" do

    before(:each) do
      @user = create(:user)
    end

    it "should save all friends" do
      lambda{ subject.perform(@user.id) }.should change(SocialConnection, :count).by(6)
    end

    context  "attribute saving" do
      before(:each) do
        subject.perform(@user.id)
        @friend = SocialConnection.where(uid: "1905046").first
      end

      it "should store uid" do
        @friend.should_not be_nil
      end

      it "should save provider" do
        @friend.provider.should == "facebook"
      end

      it "should store name" do
        @friend.name.should == "Joel Bonasera"
      end

      it "should be bidirectional" do
        @friend.follower.should == true
        @friend.follows.should == true
      end

    end
  end

end

This will give you the next spec to run. This will test that you can progress through the Facebook API response, and save the results to the DB in the appropriate manner.

It’s customary to create an app/workers directory to place your FacebookFriendWorker, as well as any other background workers that you create. So the code that you write to pass this test should go in app/workers/facebook_friend_worker.rb.

When your specs are passing here, we’ve added the ability to defer work outside of the request/response cycle. We’re most of the way to seeing this work!

Step 4

Add this spec to your spec/models/authentication_spec.rb file:

spec/models/authentication_spec.rb
1
2
3
4
5
6
 context "saving Facebook auths" do
   subject{ build(:authentication) }
   it "should enqueue a Facebook friend saver when saved" do
     expect { subject.save }.to change(FacebookFriendWorker.jobs, :size).by(1)
   end
 end

Write a lifecycle method on Authentication that will enqueue the worker. We’re definitely getting close now!

Step 5: Putting it all together

Code wise, you are ready to go! We have a few more things to put in place before we can actually run the code and have everything work.

First, sidekiq requires redis, so let’s install that.

Terminal
1
brew install redis

We don’t want redis to run all the time— it’s not as cool as postgres. It does need some configuration to run, so let’s save this file at config/redis.conf

Finally, add these two lines to your Procfile:

Procfile
1
2
redis: redis-server config/redis.conf
worker: bundle exec sidekiq

Step 6:

Terminal
1
bundle exec foreman start

And try it in your web browser!

You should see something in your server window like:

Terminal
1
11:15:52 worker.1 | 2013-11-03T16:15:52Z 60093 TID-ovijid2f0 FacebookFriendWorker JID-afefbf22f98c6c4f37a82132 INFO: done: 4.197 sec

if it worked. You can then use the data in there to print out various things in the rest of your app. Try current_user.social_connections.count in your console, or in your view!

Facebook OAuth Using OmniAuth and Rails 4

- - posted in facebook,, oauth,, omniauth

Allowing Facebook logins in Rails 4

I had to copy and paste in information from a variety of sources to end up with something I liked at the time of this writing. Since I want to walk my students in Launchpad Code Academy through this process, I figured I’d make this walkthrough public. It may help newcomers for quite some time to come!

About this solution

We are going to be using a server-side OAuth authorization. The mechanism uses some JavaScript checks and interfaces with the JS Facebook API, but ultimately the connection is made on the server-side.

You don’t necessarily have to be using Devise, but if you’re not, our tips about how to leverage this approach for Facebook login may not be helpful.

With a little extra work, you can allow users that have attached their Facebook account to log in with Facebook. You might even be able to adapt this approach to allowing users to create accounts with a single click. But you won’t like that as much when you want to get Twitter involved, since Twitter doesn’t send an email address in its OAuth callback. It’s best to have existing users affiliate their accounts and then providing login as a convenience.

Getting started

Step 1: Installing gems

Include these gems in your Gemfile:

Gemfile
1
2
gem "omniauth"
gem 'omniauth-facebook', '1.4.0'

Install them in your terminal with the bundle command:

Terminal
1
bundle install

Step 2

Per the usage instructions for omniauth-facebook, create a new file in config/initializers named omniauth.rb:

config/initializers/omniauth.rb
1
2
3
4
5
OmniAuth.config.logger = Rails.logger

Rails.application.config.middleware.use OmniAuth::Builder do
  provider :facebook, ENV['FACEBOOK_KEY'], ENV['FACEBOOK_SECRET']
end

The config/initializers directory is designed for use on Rails startup to configure how libraries are intended to operate. In this case, we want our Rails application to know that we are using Omniauth, and are configuring the Facebook provider to reference environment variables to run.

To set these environment variables properly, we’ll need to go get some info from Facebook.

Creating and configuring a Facbook App

Step 1: An app

I honestly don’t remember what it’s like to register for a Facebook developer account, other than it should be free, and it should happen at the Facebook Developers site.

When you’ve registered properly, there should be an “Apps” tab in your navigation. Click on that to travel to your list of apps.

Click “Create New App”. You should pick a name that indicates you are doing testing. You can place it in a namespace, if you like, but that’s optional.

Mine looked like this

Click “Continue”, and you should be brought to an application screen that contains your App ID (or API Key) and your App Secret. Note those, but we’ll need to fill in some information here.

In the “App Domains” box, put ‘localhost’

Click the green check on “Website with Facebook Login”, and fill that in with http://localhost:5000/. My students (or anyone who uses my Rails templates) will be able to use this. This value may be different for you— make sure that it matches whatever you use in development. localhost:3000 would be common if you are using rails s and appname.dev would be likely if you were using Pow.

Mine looked like this

Step 2: Installing application details

Students in my class use foreman to run their development environment. If you won’t, perhaps you can consider dotenv, to load env variables from files for you? It’s important not to commit sensitive information like this Facebook App Secret to your repository. Note the difficulties and caveats, should you ever need to remove sensitive data. Usage of foreman or dotenv can help with that.

If you are using foreman, you can add these files to your .env file (which is not in version control). Instead of the values below, they should match your own app’s key and secret that you obtained previously. You cannot just copy and paste this file. I totally made up these numbers, and they will not work.

.env
1
2
FACEBOOK_KEY=686338067928534
FACEBOOK_SECRET=60b9fe21ab431897eabc0743b39a5406

Facebook Powers: Activate!

Step 1: Create a model to store the authentications

We don’t want to tie authentications to a user in a 1-1 way, since we’d love to allow connecting with other social networks by default. We want a user to have many social networks attached, potentially, so we’ll create a model that appropriately attaches to users.

Create an Authentication model using this command:

Terminal
1
bundle exec rails g model Authentication user_id:integer provider:string uid:string name:string oauth_token:string oauth_expires_at:datetime

This will create a migration for you similar to this:

db/migrate/20131015222934_create_authentications.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class CreateAuthentications < ActiveRecord::Migration
  def change
    create_table :authentications do |t|
      t.integer :user_id
      t.string :provider
      t.string :uid
      t.string :name
      t.string :oauth_token
      t.datetime :oauth_expires_at

      t.timestamps
    end
  end
end

You’ll also need to provide a mechanism for Omniauth to save the data it can provide to your DB for your use. After you issue the above command, you should have an app/models/authentications.rb file. Replace that file with these contents:

app/models/authentication.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Authentication < ActiveRecord::Base

  belongs_to :user

  def self.from_omniauth(user, auth)
    where(auth.slice(:provider, :uid)).first_or_initialize.tap do |authentication|
      authentication.user = user
      authentication.provider = auth.provider
      authentication.uid = auth.uid
      authentication.name = auth.info.name
      authentication.oauth_token = auth.credentials.token
      authentication.oauth_expires_at = Time.at(auth.credentials.expires_at)
      authentication.save!
    end
  end

end

Be sure to also add has_many :authentications to your app/models/user.rb file. And don’t forget to run your database migrations here!

Step 2: Create the authentication user interface

Terminal
1
bundle exec rails g controller authentications index

This will create an authentications controller, and a view file for you. We don’t quite want any of what we get out of the package. Copy these file contents into your authentications controller:

app/controllers/authentications_controller.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class AuthenticationsController < ApplicationController

  def index
    @authentications = current_user.authentications if current_user
  end

  def create
    auth = Authentication.from_omniauth(current_user, env["omniauth.auth"])
    flash[:notice] = "Authentication successful."
    redirect_to authentications_url
  end

  def destroy
    @authentication = current_user.authentications.find(params[:id])
    @authentication.destroy
    flash[:notice] = "Successfully destroyed authentication."
    redirect_to authentications_url
  end

end

Place this file into your JavaScript directory. Note that this one won’t work either by just copying and pasting! You need to include your non-sensitive App ID :

app/assets/javascripts/facebook.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// Additional JS functions here
window.fbAsyncInit = function() {
  FB.init({
    appId      : 686338067928534, // App ID
    status     : true, // check login status
    cookie     : true, // enable cookies to allow the server to access the session
    xfbml      : true  // parse XFBML
  });
};

// Load the SDK Asynchronously
(function(d){
   var js, id = 'facebook-jssdk', ref = d.getElementsByTagName('script')[0];
   if (d.getElementById(id)) {return;}
   js = d.createElement('script'); js.id = id; js.async = true;
   js.src = "//connect.facebook.net/en_US/all.js";
   ref.parentNode.insertBefore(js, ref);
}(document));

function fblogin() {
  FB.getLoginStatus(function(response) {
    if(response.status == "connected") {
      location.href =
        '/auth/facebook/callback?' +
        $.param({ signed_request: response.authResponse.signedRequest })
    } else {
     FB.login(function(response) {
      if (response.authResponse) {
          '/auth/facebook/callback?' +
          $.param({ signed_request: response.authResponse.signedRequest })
      }
     })
    }
  })
};

Copy this view file into place, as the bulk of our tutorial actions will happen there. There are HTML comment blocks below— my blog assumes I want a hyphen, when I really do want two dashes. Be sure the file matches this gist.

app/views/authentications/index.html.erb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<% if @authentications %>
  <% unless @authentications.empty? %>
    <p><strong>You can sign in to this account using:</strong></p>
    <div class="authentications">
      <% for authentication in @authentications %>
        <div class="authentication">
          <%= image_tag "#{authentication.provider}_32.png", :size => "32x32" %>
          <div class="provider"><%= authentication.provider.titleize %></div>
          <div class="uid"><%= authentication.uid %></div>
          <%= link_to "X", authentication, :confirm => 'Are you sure you want to remove this authentication option?', :method => :delete, :class => "remove" %>
        </div>
      <% end %>
      <div class="clear"></div>
    </div>
  <% end %>
  <p><strong>Add another service to sign in with:</strong></p>
<% else %>
  <p><strong>Sign in through one of these services:</strong></p>
<% end %>

<!—
<a href="/auth/twitter" class="auth_provider">
  <%= image_tag "twitter_64.png", :size => "64x64", :alt => "Twitter" %>
  Twitter
</a>
—>
<% unless @authentications.select{ |a| a.provider == "facebook" }.any? %>
  <%= link_to_function image_tag("facebook_64.png", :size => "64x64", :alt => "Facebook"), 'fblogin()' %>
<% end %>
<!—
<a href="/auth/google_apps" class="auth_provider">
  <%= image_tag "google_64.png", :size => "64x64", :alt => "Google" %>
  Google
</a>
—>

<div class="clear"></div>

Let’s pretty this up a little with some CSS:

app/stylesheets/authentications.css.scss
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
.authentications {
  margin-bottom: 30px;
}

.authentication {
  width: 130px;
  float: left;
  background-color: #EEE;
  border: solid 1px #999;
  padding: 5px 10px;
  -moz-border-radius: 8px;
  -webkit-border-radius: 8px;
  position: relative;
  margin-right: 10px;
}

.authentication .remove {
  text-decoration: none;
  position: absolute;
  top: 3px;
  right: 3px;
  color: #333;
  padding: 2px 4px;
  font-size: 10px;
}

.authentication .remove:hover {
  color: #CCC;
  background-color: #777;
  -moz-border-radius: 6px;
  -webkit-border-radius: 6px;
}

.authentication img {
  float: left;
  margin-right: 10px;
}

.authentication .provider {
  font-weight: bold;
}

.authentication .uid {
  color: #666;
  font-size: 11px;
}

.auth_provider img {
  display: block;
}

.auth_provider {
  float: left;
  text-decoration: none;
  margin-right: 20px;
  text-align: center;
  margin-bottom: 10px;
}

Step 3: Putting it all together

First, the above step created some cruft in your routes that will make you unhappy later. Remove the line that says get “authentications#index” from your routing file. Your route file should contain a trace of the authentications you plan on dealing with. Use this snippet:

config/routes.rb
1
2
3
4
  resources :authentications

  match 'auth/:provider/callback', to: 'authentications#create', via: [:get, :post]
  match 'auth/failure', to: redirect('/'), via: [:get, :post]

Ensure that your Facebook JavaScript is loaded into the asset pipeline:

app/assets/javascripts/application.js
1
//= require facebook

Ensure that your authentications CSS is loaded into the asset pipeline:

app/assets/stylesheets/application.css.scss
1
@import "authentications";

Include a link to social logins to your already logged in accounts:

app/views/layouts/application.html.erb
1
<%= link_to "Social Accounts", authentications_path %>

Download some Facebook icons:

Terminal
1
2
curl -o app/assets/images/facebook_32.png https://www.evernote.com/shard/s1/sh/c3303305-ff8f-4829-a315-9ee91709f479/49b3985624af8fb0cae8e3223333c61a/deep/0/facebook_32.png
cp app/assets/images/facebook_32.png app/assets/images/facebook_64.png

You can use Facebook to let people create new accounts, but that’s left as an exercise to the reader!

Step 4: Boot it up

Issue a command to start your server:

Terminal
1
bundle exec foreman start

Since setting environment variables is important to the application running properly, rails s probably won’t work any longer! Foreman will put us in good position to manage environment variables (and pull user social graphs via Sidekiq later!)

You should be able to click through to the

Acknowledgements:

Many of the file contents are avialable in this gist.

The amazing RailsCasts series provided not one but two pieces of this finished puzzle. Thanks, Ryan!

This StackOverflow post on invalid_credentials in Omniauth-facebook pointed out the need to use a particular omniauth-facebook release. Another StackOverflow post pointed out the need to send a signed_request parameter with the GET to the Facebook SDK. That’s incorporated into the above JavaScript.

Charlotte Startup Weekend 3

- -

I haven’t blogged since the last Startup Weekend in Charlotte! Must mean it’s time for another one, as the next Startup Weekend approaches.

First is Charlotte Startup Weekend 3, where I am a co-organizer. You can read our kickoff blog for CSW3 on our site. We also have testimonials from technologists and business people. This is a great event for working on a project for the fun of it, and making friends and connections in the Charlotte startup community at the same time.

It’s November 4-6, so it’s in a few weeks. We have a lot of sponsors, judges, advisors and volunteers to introduce, but we need attendees! If you cannot afford the registration fees, please contact me, as there may be some scholarship possibilities.

If you’re not sure whether Startup Weekend is right for you, there’s an event from Collaborate CLT and CLT Launch hosted by Packard Place to help you evaluate that on Tuesday, October 25.

Finally, if you are interested in the Charlotte startup community, I publish a newsletter that attempts to circulate great information about what’s happening and who is involved here in the city. You can view the archives or sign up!

Thanks for your time and attention.

Jim Van Fleet

Charlotte Startup Weekend 2

- -

For those of you who are learning of my existence for the first time, welcome! I’m writing today about my involvement with Charlotte Startup Weekend 2, but I have to start with some of my own background to help you understand why you should be involved as well.

I came to Charlotte in January of 2008 to pursue my professional passion of working with Ruby on Rails. I selected a Charlotte startup over one in the Bay Area because I believed in the business. During our time here, my wife and I have come to love Charlotte deeply, and have made it our home. I am an advocate for Charlotte, and I’m also an admirer and exhibitor of its entreprenurial spirit. After moving here for one Charlotte startup, I’ve founded or co-founded two others, and joined a fourth as its CTO.

I am co-organizing Charlotte Startup Weekend 2. I am donating my time because I believe in the format, and that it’s exactly what Charlotte’s maturing entrepreneurial environment needs to take the next step. During my time as a freelance consultant doing networking in Charlotte, I came to be familiar with a great deal of this city’s talent in design, software development, marketing, and entrepreneurship. I believe it’s time for this claim that I know to be true to become widely believed: this city has an incredible talent base and tremendous potential. By participating in Charlotte Startup Weekend, you’ll be teaming with some of Charlotte’s best and brightest for an inspiring weekend of networking, friendship, and working together.

The agenda is available on the CSW2 website, but here is a summary. On Friday night, after opening remarks, those who have an idea they’d like to put before the group to create will pitch their concept. A small number of those concepts will be selected, and teams will self-organize based on what and who they’d like to work with. Work will begin. Food and drink will be provided. Advisors will review and offer commentary on your progress. At the end of the weekend, a panel of judges will decide who has won. Depending on the organizers meeting their sponsorship goals, there may be prizes awarded the winners. Perhaps our winner will have an opportunity to become tenants at our host sponsor, Packard Place!

The primary sponsor of the Startup Weekend brand is the Kauffman Foundation, whose mission is promoting entrepreneurship. A study from that group in 2010 begins When it comes to U.S. job growth, startup companies aren’t everything. They’re the only thing.. The study reveals that, both on average and for all but seven years between 1977 and 2005, existing firms are net job destroyers, losing 1 million jobs net combined per year. By contrast, in their first year, new firms add an average of 3 million jobs.

I’d exhort us all to build new companies together here in Charlotte. Practicing will make us better, and you could meet your next business partner at this event. You’ll have a chance to know what everyone on your team is capable of, and you’ll be comparing results with your peers for weeks to come. You’ll look at what has been accomplished by a group of strangers in one weekend, and you’ll wonder what’s possible in your own business with your own teams in the next two weeks.

So, go register!. And if you are interested in sponsorship, please contact me at jim at jimvanfleet.com and reference CSW in your subject line.

DevOps Culture Hacks | DevOps.com

- -

DevOps Culture Hacks | DevOps.com: “A turning point for Jesse in terms of moving from an obstacle in the way of change to someone that really knew how to add value with ops practice stemmed from a battle he got into with the ‘VP of Awesome’ at Amazon. This was the nickname of this particular VP because it seemed that pretty much any highly interesting project at Amazon was under this man’s purview. What happened was that Jesse did not want to let out a piece of software because he knew, for sure, that it would bring the site down. The VP overrode him by saying that the site may go down, but the stock price will go up. So, the software went out, and it brought the site down. Two days of firefighting and the site came back up, and so did the stock price, and so did the volume of orders. The dev team went on and had a party, they were rewarded for job well done, new and profitable functionality released. At the end of the year, Ops got penalized for the outage! Amazon rewarded development for releasing software and providing value and operations was not a part of that. They were in fact penalized for something that was out of their control.”

This is a great post, go read the rest.

336 Hours

- -

In the next two weeks, I expect the following events:
  • I will speak at Ignite! Charlotte for a second time, this time in front of a sold-out Neighborhood Theater.
  • My wife Megan and I will have a pre-natal visit and our last ultrasound before the birth of our first child, a son, in April.
  • My wife’s parents will make their first visit to Charlotte, bringing their dogs with them. We will have ten living creatures in the house.
  • I will turn 32.
  • My wife will have a baby shower.
  • My parents will visit with the intention of selecting a new home for themselves, here in Charlotte.  After that selection, I expect the logistics of their move to be made in a short amount of time.
  • I will attend a meeting of CRTEC which promises to become the home of Charlotte’s technology leadership, followed by a meeting with another CRTEC member to discuss our vision of Charlotte’s software development community.
  • I will attend an all-day workshop for entrepreneurs focused on preparing for investment and attracting investors to small businesses, put on by the BIG council in conjunction with the SBTDC.
  • I will submit a talk for RailsConf 2011.
  • Megan and I will attend a Punch Brothers show at the Neighborhood Theater. Chris Eldridge is a dear friend of Megan’s.
  • I will celebrate the one year anniversary of going freelance with it’s bspoke.
  • Adam Howell and I will observe the one year anniversary of Work Montage and our product Mocksup.
  • And finally, although a more formal announcement will be forthcoming, I’ve altered bspoke’s charter to accept a full-time CTO position at Otherscreen, a web and mobile startup here in Charlotte, NC. It is a true privilege to be working with this team already, and you should expect big things.
That’s in addition to client work and the particulars of every day life. If I am overly quiet or missing for a good portion of February, now you know why. If I owe you something, please keep reminding me. Except for you, Raquel, I’m almost done with your recommendation.

Unqualified Reservations: What’s Wrong With CS Research

- -

Unqualified Reservations: What’s wrong with CS research: “So here’s the first thing that’s wrong with CS research: there’s no such thing as CS research. First, there is no such thing as ‘computer science.’ Except for a few performance tests and the occasional usability study, nothing any CS researcher does has anything to do with the Scientific Method. Second, there is no such thing as ‘research.’ Any activity which is not obviously productive can be described as ‘research.’ The word is entirely meaningless. All just semantics, of course, but it’s hardly a good sign that even the name is fraudulent. When we look at what ‘CS researchers’ actually do, we see three kinds of people. We can describe them roughly as creative programmers, mathematicians, and bureaucrats.”


To excerpt from this post does it a great disservice, and, like most other things I post to my blog, is highly recommended reading.

From my time in undergraduate CS studies at a prestigious university (attached to the programming languages team, for good measure!), I can both accept and amend the author’s central claim: CS research sucks.

I worked on a team working on an optimizing compiler for the Java language that could detect when known transforms could be applied yielding a semantically equivalent, but faster, set of bytecodes. The platform gets marginally faster for everyone, should the research yield meaningful fruit and get adopted upstream. A noble goal, undertaken by earnest and intelligent men and women, but ultimately doomed.

One note the author does not strike is of the commercial nature of programming languages. Over and over, we see the pattern: evangelism, adoption, glut of choice, everything starts to suck and get vendor dependent, death. After its acquisition by Oracle, to the author’s “creative programmers”, Java is now in its final stage, destined to live as a zombie whose musculature (the JVM) is kept alive only by newer languages (e.g. Scala, Clojure, JRuby, Groovy, etc.) that target the platform. This fact should not be lost on the judgement of quality of CS research.

On the other side of the equation, programming an IDE that supported an alternative implementation of the generics which became part of the Java language in JDK 1.5 introduced me to basically all of the concepts I use still today as a successful programmer. It wasn’t because of the work I did faked on writing the grammar for this extended language, it was because of the techniques we used as a team in writing the IDE. Pair programming, test driven development, The Pragmatic Programmer, etc. It’s hard for me to think of that being a failure. I love programming, and it’s because of my time with the PLT team at Rice University. Thanks, Dr. Cartwright!

(Original via @puredanger.)

National Anthem

- -

This was my favorite rendition I can remember.

Hacker News | That Was One of the Things That Really Surprised Me About the Real World: That B…

- -

Hacker News | That was one of the things that really surprised me about the real world: that b…:

Nostrademons writes:

“That was one of the things that really surprised me about the real world: that big advancement only comes from big lateral jumps. Different companies, different projects, different markets, or different customers. There’s this model of the world we’re taught as schoolkids - at least where I grew up - where you work hard at something, do as your told, and slowly but surely you rise up. And maybe at one level it’s true, but it’s very slow, and you’ll never become the sort of success you read about in the paper that way.

Instead, I’ve found that what usually happens is that you join an organization because you meet some minimum skill baseline that they’re looking for. And then as you practice and learn from the people around you, you end up picking up a bunch of other skills and getting better at your job. But the people around you generally won’t notice. First impressions usually pigeonhole you into a general category, and then people are blind to gradual changes.

So to reap the rewards of everything you’ve learned, you have to expose yourself to new people. Jump ship, and suddenly you seem really valuable to them, because all those skills you’ve picked up which your current organization takes for granted are new and useful.

There’s a leverage effect as well: people try to work with others of roughly the same level. If you’re diligent about practicing, you’ll go from being (hopefully) near the bottom of your team to the top of it. If you then repeat the process, your new teammates better be higher skilled still, and so your team as a whole can tackle more ambitious problems.”


Unless you work very hard at your communications within the organization, this is a very likely outcome. It may even be inevitable. Embrace it.

(Via @peteforde.)