Rails App Template Alternative

We are making lots of new apps at TaskRabbit and have many shared components. All of this stuff (gems, best practices, test setup, etc) needs to get into the new project quickly so the team can focus on the business of providing the intended functionality. My first attempt to solve this problem was to create a Rails app template with all that stuff, but switched to a new way that involves a true template application.

Conventional app templates seem to work for a lot of people and Rails Composer looks to be a good option in this space. This method works by running Ruby code that puts down files. This level of indirection is likely a positive thing when projects vary (rspec one time, test-unit the next). However, we’re trying as hard as we can to be consistent across apps, so when I found that this indirection made working with the templates more difficult, I decided that it was not worth it.

The alternative method is pretty simple. I made a Rails app called Warren) that was exactly what I wanted to see new projects use. It contained all our our gems for authentication, shared styles, inter-app communication, and developer tools. You could basically log in, log out, and go to a page where you saw who was logged in. It had its own test suite to test these things along with all the normal stuff: yml files, initializers, .rvmrc, .gitigore, ApplicationController, favicon, etc. It was simply a working Rails app.

The only addition is the app.rake file that I put in the /lib/tasks directory. That provides this functionality:

% rake app:create[new_name]

This will create a new app called NewName in a peer folder to Warren. The full process looks something like this:

localhost:warren brian$ rake app:create[new_name]

localhost:warren brian$ cd ../new_name
=== RVM Message ===
Do you wish to trust this .rvmrc file? (/Users/brian/taskrabbit/new_name/.rvmrc)
y[es], n[o], v[iew], c[ancel]> yes
Using /Users/brian/.rvm/gems/ruby-1.9.3-p194 with gemset new_name

localhost:new_name brian$ bundle install
Fetching gem metadata from http://rubygems.org/......
Installing all-the-things (3.9.2) 
Your bundle is complete!

localhost:new_name brian$ rake db:create db:migrate db:test:prepare

localhost:new_name brian$ rails s
>> Listening on 0.0.0.0:3000, CTRL+C to stop

And http://localhost:3000 works.

Read on →

Singletons, Threads, and Flexibility

In Ruby, we often like very simple APIs, but this often comes at the price of thread safety and code flexibility. I’ve found that if you use a few tricks from the start, you can get the best of it all.

I recently did a project where I tried to use the VCR gem, but it went awry when working in multiple threads. This is a great gem that, like many of my own, falls into the trap of module/class level singleton configuration/execution.

This is approach is characterized by things like extend self in the top-level module and then having instance variables at that level. This is not to call out VCR specifically. it’s just my most recent example of hundreds of gems that take this overall approach.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
module VCR
  extend self

  def current_cassette
    cassetes.last
  end

  def configure
    yield configuration
  end

  def configuration
    @configuration ||= Configuration.new
  end

  private

  def cassettes
    @cassettes ||= []
  end
end

When operating on multiple threads, things get wacky because of this because they are sharing this current_cassette and writing to the associated file. You end up with recordings on top of each other.

I am inclined (and some say over-inclined) to use singletons to do something like this:

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
class VCR::Client
  def current_cassette
    cassetes.last
  end

  def configure
    yield configuration
  end

  def configuration
    @configuration ||= Configuration.new
  end

  private

  def cassettes
    @cassettes ||= []
  end
end

module VCR
  extend self

  delegate :current_cassette, :configure, :configuration, :to => :default_client

  def default_client
    @default_client ||= Client.new
  end
end
Read on →

Hubtime

I got pretty sidetracked during my 2012 Review and ended up making a new tool called Hubtime. It lets you graph your activity in a variety aways across Github repositories.

The inspiration came from Github’s own reports, but I made Hubtime because those reports are only at a repository level. I was looking to see patterns across the many repositories that I worked on over the year. It seems that Github agrees to some degree because they have since launched metric overviews on user profile pages.

A 42 day streak! Hubtime has the data to make Hubtime do the same graph, but right now focuses more on reproducing the Github experience that is only now per repository.

$ ./hubtime.rb graph commits --months 3

Graphing commits, additions, deletions, or impact can also be done showing the magnitude by repository.

$ ./hubtime.rb graph commits --months 3 --stacked

This was the first purely command line Ruby project that I have done. In addition to that, I learned several new things and tried some new approaches during development.

Read on →

Playing Work

We didn’t go anywhere over the holidays and had a nice Christmas at home. It’s possible that I’m incapable of taking a vacation at all, but this is particularly true when on a stay-cation. Other than Christmas day itself, I was coding on a normal schedule for most of the week.

My daughter (4.5) was around most of the week too, often with the normal babysitter that comes for my younger son. So all week, our house had me coding, my wife editing, and her hanging out with the babysitter. She even brought us lunch like it was restaurant including a fork wrapped up in a napkin.

On January 1st, I also took the day completely off and asked her what she wanted to play. “Not now, I’m working,” she said. She was “playing work,” which involved writing out a dense set of letters on white sheets of paper.

“There is a lot to do and I have to work, even on family days.”

And she went back to scribbling like crazy. This all says something about me as a person and a parent. I’m not sure exactly what, but it’s probably not good.

It hurts because I actually think I’m going a pretty good job. I leave early (by engineer-at-startup standards) to have dinner and hang out with her and only work again after she is asleep. I’m not sure I could have more “balance” anyway. To me, the term suggests a healthy ratio between what you are forced to do because of work and the things of “normal life.” I might be intrinsically unbalanced, but I feel lucky that my normal life has a lot of things that I love doing which centers mostly around building things for people. For better or worse, I’m thinking about this stuff all the time, anyway.

It likely comes with my being so visibly inaccessible all week. Regardless, I didn’t have any profound realizations at that moment or anything. Instead, I decided to plant a behavioral seed for later.

“I understand. I’ll let you get to it. Let me know when you can play.”

Review: 2012

I honestly can’t remember anything from January or even October very specifically. It sure felt like I was busy as we doubled the TaskRabbit engineering team and scaled the site to get a lot more stuff done for real people in the real world.

I can’t even decide what the best way is to see what I did in January. I could look at my email or calendar, but I strive not to make those the center of my world. Maybe in Evernote. My git commits are probably a bit too granular, but maybe there is something in the aggregate.

Most striking is the almost non-existence of code between July and October. We were growing the team during this time and I made the conscious choice to try on more of an “engineering manager” role as opposed to a “tech lead” kind of role. Judging by the large spike in October, it’s clear the experiment got cut short. Around this time, I made the biggest change of the year: transitioning from VP of Engineering to Chief Architect.

Read on →
Copyright © 2013 Brian Leonard