Friday, December 21, 2012

Thoughts on programming AdStaq's culture

We just posted the Careers page for my new startup, AdStaq.com. We're looking for smart developers of all backgrounds, junior and senior, who want to be part of the founding team. We're primarily looking for people in the MD/DC/PA/VA or NY regions because at this stage we need to get together frequently to compare notes. Later on we'll become a more global/virtual company.

Hopefully it's obvious from reading that page that I've been thinking very deeply about the kind of programming culture we want to build into the company from day one, influenced by all of the reading I've done over the past several years and all of my work experiences as a Navy officer, tech company employee, and founding CTO. I want to create an ultra-professional, stimulating environment that provides fun and meaningful opportunities for programmers who also have a life outside of coding and want to get home and see their families every night.

My favorite line of that page is "no weekly status updates", which someone asked me to clarify. I'm not saying "programmers get to work in isolation without communicating what they're doing". I'm saying we're never going to make people do that kind of awful busywork just to make management happy. Instead we'll keep track of our progress using other tools, like reviewing commit logs and good old-fashioned one-on-one meetings.

Ben Horowitz just wrote a good post about creating the right culture for a startup. It's early days for AdStaq but I think our cultural motto might end up being something like, "We remove all software defects immediately and fix whatever allowed the defect to occur" (we need to come up with something snappier like "don't just fix the bug, fix the process"). For example, right now, James just emailed me a bug in a secondary screen in our app. He said it's not a big deal to fix immediately, so I could blow it off for a few weeks, especially since I'm building a really cool new feature I can't wait to release. But I know better than to allow a bug like this to hang around and get stale. I also know that a small investment of time to improve our test harness to prevent this bug from recurring will act like compounding interest, saving me a lot of time later. Most importantly, since we're a company that makes other software easier to use, we really can't afford to have low quality. We have to set the standard for ad tech company software quality.

We can't do it alone though - we need your help! If this sounds interesting, email me! Instead of a resume, send us some links to stuff you've worked on!

Thursday, November 1, 2012

Ruby Dependencies, Notifications, and Adjustments

Note: I originally submitted this article as a draft to the Practicing Ruby online journal. Gregory liked my concept but ultimately ask if I would mind if he wrote his own version. He did an awesome job and if you're interested in this subject I recommend you definitely read his article.

Introduction

Object-oriented programming helps organize your code in a resilient, easy-to-change way. This article aims to explore one of the concepts that trips up beginner and more experienced object-oriented programmers: how to sensibly connect a set of objects together to perform a complex task. How do you put instances of your information-hiding, single-responsibility-discharging, message-passing classes in touch with one another?

I became confused about the smartest ways to do this when I started building  Ruby apps that involved fetch large amounts of data from external services. In these projects, a Rails or Sinatra web application acted as a facade for workers querying a large set of APIs. Each API was different from the last, requiring different approaches and different dependencies. Some APIs involved five or six different steps, and in some cases each step needed to be handled by a different object.

I felt I understand object-oriented programming pretty well, yet I struggled with specifying the relationships between objects so that each object knew just enough about its peers to get the job done. My style was inconsistent. Sometimes I would inject a dependency using the constructor, and sometimes I would use a setter method. At other times it seemed more natural to have an object directly instantiate new instances of whatever objects it needed, on the fly.

All of the code examples referenced below can be found in this gist.


Object Peer Stereotypes

All of this changed when someone turned me onto the book Growing Object Oriented Software, Guided by Tests by Steve Freeman and Nat Pryce. The book has a chapter on object-oriented design styles, and includes a description of “Object Peer Stereotypes” that addressed my conundrum perfectly.

The authors divide an object’s peers into three categories: Dependencies, Notifications, and Adjustments (DNA). These are rough categories, because an object peer could fit into more than one category, but I found it to be a useful distinction. We’ll explore each of these categories as they pertain to Ruby code using an example from my real production code: a wrapper for Typhoeus I wrote called HttpRequest.

By the way, Gregory wrote about a related topic (what types of arguments to pass into a method) back in Issue 2.14. As your objects become more sophisticated you’ll find you end up passing fewer basic object types like strings, symbols, or numbers, and more of the Argument, Selector, or Curried objects that Gregory describes.

Dependencies

“Services that the object requires from its peers so it can perform its responsibilities. The object cannot function without these services. It should not be possible to create the object without them.”


“...we insist on dependencies being passed in to the constructor, but notifications and adjustment can be set to defaults and reconfigured later.”

I wrote the HttpRequest class so that I could set on_success and on_failure callbacks (where Typhoeus only provides an on_complete callback) and to encapsulate my dependency on the Typhoeus gem, in case I want to switch to another HTTP library later.

HttpRequest objects have two Dependencies: the URL of the request and a set of options for telling Typhoeus how to make the request. Here's a link to an example of HttpRequest code.


Note that I’m supplying a default for the options argument, since it’s just a hash that gets passed onto Typhoeus::Request, and it’s something you’ll have available at the same type you have the URL. Because there is a sensible default (an empty hash), you could argue that this argument is more of an Adjustment, described below.

If options was a more complex object, something that might have peers of its own, I would probably treat it as an Adjustment. I find test-driven development really helpful in cases like this because often the tests can help you feel out which approach is more appropriate (which is the whole premise of the Growing Object Oriented Software book).

Notifications



“Peers that need to be kept up to date with the object’s activity. The object will notify interested peers whenever it changes state or performs a significant action. Notifications are ‘fire and forget’; the object neither knows nor cares which peers are listening.”

In the HttpRequest example, success_callbacks and failure_callbacks are the notifications. Another object can register for success notifications like this.

Logging is another canonical notification example. Here’s a pattern I use a lot for logging.

Notifications can also be sent as arguments to a method call. I often pass a block for error handling. I find this usually involves fewer lines of code than returning a status object that must be tested for success or failure. Here's an example.


Adjustments


“Peers that adjust the object’s behavior to the wider needs of the system. This includes policy objects that make decisions on the object’s behalf...and component parts of the object if it’s a composite.”

Most of my Adjustments involve component parts of a composite object. For the API-intense project where I’m using HttpRequest, I always have one class that has overall responsibility for getting all of the data we need for each API. That “master” class just does one thing: it coordinates the activities of a set of Adjustment peers, are of which are set to sensible defaults.
This also enables simple unit testing because you can so easily set the adjustments to mock objects provided by the tests.

If you use the strategy pattern, where peer objects make decisions for your object, your Adjustment might look like this.

It could be that AdminChecker is more of a Dependency than an Adjustment, depending on how many different kinds of AdminCheckers there are and how central admin-checking is to your code. If there’s no normal default for the admin_checker value, and if you really can’t make a DataFetcher without knowing what kind of checking policies it’ll be working with, you should probably inject your admin_checker in the constructor, marking it as an important Dependency.

HttpRequestService

There’s one other facet to my HttpRequest object that I thought Practicing Ruby readers might find interesting. Because Typhoeus is concurrent, you have to queue up requests onto a shared Typhoeus::Hydra object. The requests don’t run until you invoke the hydra’s #run method. I experimented with storing the Hydra object in various places and ended up creating a factory for HttpRequest objects called HttpRequestService, below. Can you spot the dependencies and adjustments? It doesn’t have notifications, but I could see adding some instrumentation to measure HttpRequest times.

Instances of the HttpRequestService end up as Adjustment peers for the objects responsible for fetching data.

Dependency Injection Containers

Rubyists generally eschew dependency injection containers but they complement the DNA style quite well. I use dependency injection containers as the single place where my code can pull in dependencies from different sources. These dependencies sometimes involve extra setup steps or massaging, depending on whether the code is running in production mode or not, and the container is a convenient place to consolidate that kind of housekeeping code.  It often provides the sensible default for notifications and adjustments, and it’s an important part of the boot process for most of my Ruby code.

I’ve created a simple gem for this purpose called dim based on Jim Weirich’s article. If you’re interested in the topic, I highly recommend that article. Here’s a snippet of one of my container definitions.

Conslusion

Don’t hold too rigidly to these classifications; they’re more like heuristics. As Steve Freeman and Nat Pryce wrote:

“What matters most is the context in which the collaborating objects are used. For example, in one application an auditing log could be a dependency, because auditing is a legal requirement for the business and no object should be created without an audit trail. Elsewhere, it could be a notification, because auditing is a user choice and objects will function perfectly well without it.”

When considering how to organize object peers I recommend you favor what’s most understandable and flexible, even if it means deviating from the DNA pattern.

Wednesday, October 31, 2012

Setting up Puma & Rails on Heroku

I just moved Adstaq over to Puma this weekend because I want to experiment with a multithreaded server as a way to keep our web serving costs down and our efficiency high. We're already doing this with Sidekiq for our worker code, to great effect, and philosophically I much prefer plain old Ruby threads over other Ruby concurrency solutions. Dave Copeland gave a GREAT talk at RubyConf last year called Don't Fear the Threads which I highly recommend for further inspiration.

It took some trial and error to get Rails talking to Puma and to get everything running on Heroku, so I put the needed code into a gist, embedded below.

I'm monitoring the change on New Relic but so far have not noticed any memory savings vs. Unicorn. But we're also not drowning in traffic right now. Nonetheless I'm glad we're getting some Rails multithreading experience before that happens.

Update: Watsi posted some great instructions for adjusting ActiveRecord's connection pool size.

Monday, October 22, 2012

Family calendar setup with Google Apps

A friend was recently admiring the calendaring setup my wife and I use to keep track of childcare and our professional schedules (so each of knows not to schedule something at a time when there's no childcare and the other parent is unavailable). The killer feature is that we each have access to the same calendar with the latest schedule data available to us at all times.

It took a while (and a few different iOS releases) to get it right, but here's what we do:

  • We both have personal online calendars where we track appointments that occur during the work day; these are things the other parent doesn't need to know about. We both have iPhones (though I'm switching to Android soon) but we don't use the iPhone calendar for this purpose. Instead, our phones are synced to our personal Google Calendars via Gmail Exchange. I found Apple's calendaring products very subpar, especially with syncing between the desktop and mobile devices. Also, GCal's integration with Gmail is pretty awesome.
  • I setup a Google Apps account at a custom domain that hosts two shared calendars: "Family" and "Childcare". These also use Gmail Exchange. We put stuff that we're both doing (like "Take kids to the zoo") or stuff that impacts the other parent (like "Ignite Baltimore #11") on the Family calendar. We also put stuff like "Grandma visiting" on the Family calendar. We track the ever-shifting babysitter and nursery-schools schedules on the Childcare calendar.
  • We both subscribe to my TripIt account, which automatically generates a nice travel calendar. That saves me having to manually key-in travel itineraries, which if you travel a lot is pretty awesome.
One thing that makes all of the above harder than it ideally needs to be is getting Google mobile sync working properly. But I just checked out the documentation and it looks much-improved from the time I first set all of this up.

Having shared calendars has been a huge stress-reducer for our family, cutting down on many boring logistics and scheduling conversations. Someday soon I'm sure we will be adding individual kid calendars to our setup.

If you have questions about how to do something similar, hit me up in the comments!

Monday, October 15, 2012

Ruby Dependencies, Notifications, and Adjustments

Here are the slides for the Ruby Dependencies, Notifications, and Adjustments talk I've recently given at DCRUG and Bmore On Rails:

https://github.com/subelsky/tkn/blob/master/examples/ruby_dna.rb

The talk discusses the object peer stereotype concept introduced in the book Growing Object Oriented Software, Guided by Tests. I also mention Jim Weirich's post about Ruby Dependency Injection.

I used the experimental terminal keynote software to make the slides. It was pretty fun writing my slides in Ruby, and I'd definitely recommend using it for code-heavy talks like this one. But if you need diagrams or something more visually-stimulating I'd recommend sticking with GUI-based software.

Wednesday, October 10, 2012

Developing a software education industry in Baltimore

I recorded a video for Technically Baltimore's new series "One Big Idea". My big idea is about creating a new software education industry in Baltimore:


The ideas here build on an earlier post of mine, Towards a New Paradigm for Software Education. They also dovetail nicely with something Anil Dash wrote, The Blue Collar Coder.

Friday, September 28, 2012

Scorecard for Baltimore's startup community

Update: Killer Events went from B- to B

I used Mark Suster's awesome post about building startup communities outside of Silicon Valley to make a scorecard for Baltimore's startup community. I'm writing this off-the-cuff based on my perspective and would be happy to change any of these grades if readers can provide more data:
  • A strong pool of tech founders: A. Just go to any meetup or tech event around town, and you'll meet lots of smart technically-minded, entrepreneurial engineers and business people. There are many tech people in and around Baltimore with national and international reputations, and there are many compelling startups around town (too many to name, I'm afraid to leave someone out).
  • Local capital: C. There's a lot of capital available in Baltimore but it does feel disorganized, which Mark addressed. We have several incubators and early-stage investment programs now, and things feel a little too diffused. As a step forward, check out this post Dave Troy wrote about what could be achieved if these smaller, individual efforts were combined into something larger
  • Killer Events: B. We have tons of awesome events (just check out Baltimore Innovation Week's packed calendar) but I don't see them growing enough to attract people from outside of the region without more investment and support from the city's business, municipal, and NGO sectors. For example, Betascape could become "the SXSWi of the east" if the organizers had more funding (kudos to MICA for being such a great host). In general it's hard to find space for compelling events in the city - what if the city started a program to make the convention center available at low cost to innovation community events? Update: I forgot about Baltimore TechBreakfast which is expanding to Columbia and beyond!
  • Access to Great Universities: I'll give us an A- because there are a lot of great universities and thus there is a pool of raw talent and ideas. But I don't have a sense that they're teaching much of value to startup companies. Here's what I think they should be teaching
  • Motivated Champions: B. This is the role I've chosen for myself and there are many other people who have done so as well. But we need more people of stature/fame to get involved, not just grass-roots people like me.
  • Local Press: B. This would have been an D a few months ago but now we have Technically Baltimore and Baltimore Weekly and those guys have been killing it. Special thanks to Gus Sentementes, the Sun reporter whose coverage of the tech scene is what moved us from F- to D!
  • Alumni Outreach: F. I'm not aware of any particular attempts to do this, though we make an effort to snag people when they are in town.
  • Wins: B. Doing pretty good here: Ad.com, Millennial Media, BillMeLater, and more.
  • Recycled Capital: B-. Greg Cangialosi and Sean Lane are setting a great example in this regard. Both are using their success to foster a broad range of awesome new enterprises in the city.
  • Second-time entrepreneurs: A. Several interesting companies emerged from ad.com including Millennial. I'm starting a business with someone who was early at ad.com and is using the lessons learned there to help us kick ass. Ron Schmelzer is working on an exciting company after several other wins.
  • Ability to Attract a Pool of Engineers: B-. The city has a lot to offer young people but we're competing with all of the other cities that have similar assets, where The Wire wasn't filmed. I'd love to see the city launch an initiative like the ones Mark suggested specifically geared toward recruiting innovators to move and build companies here.
  • Tent-pole tech companies: Incomplete. We don't have anything on the scale that Mark describes. The closest we have is Advertising.com but it's now a division of AOL and not on the scale of the companies he mentions. They have really accelerated their leadership in the past 12 months by hosting and sponsoring a lot of events, so I'm holding them up as an model of what a tent-pole company could do for us. 
Was I too harsh? Too gentle? Let me know your thoughts.

Friday, September 21, 2012

Intro to Arduino Workshop at Betascape This Weekend

I'm leading a workshop/hackathon at Betascape this weekend called Intro to Arduinos. Below are the links you'll need.

The workshop is BYOA aka "Bring Your Own Arduino", but the physical computing lab should have all of the other parts and consumables we'll need (LEDs, resistors, etc.).

Beginner Level
I will be on hand to help you through the tutorials. 

Intermediate Level

I'm also bringing some gadgets in case more experienced Arduino hands would like more of a challenge. Here are the projects I'm suggesting:
Other Links

Wednesday, September 12, 2012

Some great software design and architecture books


A friend and fellow self-taught programmer asked me to recommend some good books he and his team could read to buttress their Ruby design and architecture knowledge. I definitely recognized my friend's situation: after you spend years consuming short-form content like blog posts, tech talks, and screencasts, it becomes hard to organize your store of knowledge. You need labels for concepts, you need semantic layers of knowing. You need to think more deeply and comprehensively, with longer examples. You need books!

So here are some of my favorite software design/architecture books, not all of which are Ruby specific:

Design Patterns in Ruby
Ruby Best Practices
Objects on Rails
The RSpec Book
Code Complete

Clean Code

I haven't read these yet but they're on my list:

Clean Ruby
Practical Object-Oriented Design in Ruby


Also, Building Hypermedia APIs with HTML5 and Node is very relevant to web developers in any language. AdStaq is going to have a hypermedia API; in fact we're making it a central part of our sales pitch.

Thursday, August 30, 2012

Intro to CasperJS: screencast & exercises

Last night I gave a short talk on using PhantomJS and CasperJS for webscraping at the Baltimore JavaScript User's Group. The talk is embedded below, and the exercises are posted to my Github account.

 

Wednesday, August 29, 2012

Use a long passphrase for your wi-fi network

I was really chilled by this article on how easy it is to crack even seemingly-unguessable wi-fi passwords. I haven't kept up with the state of the art, and didn't realize how convenient the password cracking tools have become, nor did I know about the "deauth" trick the author describes.

The bottom line is, your basic Internet security hygiene now needs to include using uncrackable wi-fi passwords, particularly if you live or work in a wi-fi dense area that presents a "target-rich" environment to an attacker (such as the one where the author's office is located).

But what are you supposed to do, tell every house or business guest who wants to get on your wi-fi that the password is "Heyw00Dj@buZZoffe!!!69ass353q1"? That's lame. Instead I recommend choosing a random, distinctive passphrase of easy-to-spell unrelated words, separated by spaces.

For a business, I would also recommend changing the password on a regular basis. Many routers also have a "guest network" function that provides an isolated network to guests. That way you don't have to give guests access to your internal network in order for them to hop on the Internet.

Friday, August 24, 2012

My Fall 2012 technical speaking schedule

I'm excited about the chance to present a bunch of tech talks this fall about things I've been hacking on this year. Hope to see you there!
And if you're looking for a speaker on Ruby, startups, or programming, get in touch.

Wednesday, August 22, 2012

Security tip: don't send passwords over email or IM

I always insist that people not email passwords or other sensitive data to me, or use instant messaging. Chances are good that your email or my email will someday get hacked, and one of the first things an attacker will do is search your mailboxes for words like "password", "account ID",  and "credit card number".  It's not a wise risk to take.

Here's what I do instead:

KEYVAULT

I usually ask people to use Keyvault which lets you send encrypted, short-lived, self-destructing messages accessible only by a unique key. The recipient receives a message form Keyvault with a link to the message referencing the unique key.

Of course this requires you to trust the people who make Keyvault to not be a bad actor. I'm not so worried about this because the service was recommended to me by a friend, Scott Paley.

You also have to trust Keyvault to handle their security properly, to really delete the messages after the self-destruct time limit expires, and so forth. So for the most sensitive data, I recommend sending the most sensitive data out-of-band, using one of the below methods.

This is a tradeoff of course; there's still a risk in trusting Keyvault, but it's a lot less risky than trusting your email provider.

I've thought about building an open-source version of Keyvault that comes with instructions for deploying it to your own personal Heroku installation, so that you don't have to trust anyone else.

SMS

This isn't as secure of an option as it once was, now that people can back up their smartphones to the cloud or to a computer, but if you don't identify what the password is in the text message I feel it's fairly secure. The way to do this is send an email that says "my account ID is ####. I'll text the password to you shortly." Then you just sent a text with your password, by itself.

SNAIL MAIL

For really sensitive stuff, like the passphrase to unlock your company's PGP keys, I write the sensitive data on a piece of paper, stuff it in an envelope, and mail it to the recipient, making sure they know to keep the envelope in a safe place.

Monday, August 20, 2012

Some useful ImageMagick snippets

I try and stay out of Photoshop as much as possible. For most non-design image manipulation tasks I've found ImageMagick to be very useful, though it can be hard to sort through the documentation to find the transformation you need. Here are the ImageMagick commands I find most useful:

# Flatten a transparent image with a white background:
convert -flatten img1.png img1-white.png

# Make an image transparent
convert -transparent '#FFFFFF' nontransparent.gif transparent.png

# convert an image into tiles
convert -size 3200x3200 tile:single_tile.png final.png

# making a montage from a collection of images
montage -geometry +0+0 -background transparent *png montage.png

# inverting colors
convert before.png -negate after.png

# generating a favicon
convert large_image.png -resize 16x16! favicon.ico

I also once needed to add numbers to a individual parts of a tiled image. I found it easier to script this with Ruby rather than use the shell's looping constructs:

# adding numbers to a tiled image
cmd = (0..324).to_a.inject([]) do |cmd,n| 
  y=(n/25*32)+15; x=((n%25)*32)+15
  cmd << "-draw 'fill red text #{x},#{y} \"#{n}\"'"
end

`convert img.png #{cmd.join(' ')} annotated_img.png`

Monday, August 13, 2012

How to create OmniAuth provider aliases

I'm working on a project that uses OmniAuth to authenticate with many third-party services, including a few different Google products. There's an omniauth-google-oauth2 strategy that makes this easy, but I wanted to make an alias for this strategy so I could treat access to a user's AdWords account separately from their Analytics or Profile data. Some users will only be connecting our service to one of these products, and I didn't want to request access to everything at once.

My solution was to make aliases for the google_oauth2 strategy. I didn't see a built-in way to do this, nor did web searches reveal other solutions, so here's what I came up with:
# lib/omniauth-adwords-oauth2.rb
require "omniauth-google-oauth2"

class AdwordsOauth2 < OmniAuth::Strategies::GoogleOauth2
  option :name, 'adwords_oauth2'
end

# config/initializers/omniauth.rb
require "omniauth-adwords-oauth2"

Rails.application.config.middleware.use OmniAuth::Builder do
  provider :adwords_oauth2, ENV['GOOGLE_API_CLIENT_ID'], ENV['GOOGLE_API_CLIENT_SECRET'], {
    scope: "https://adwords.google.com/api/adwords/" # could also be adwords-sandbox.google.com
  }
end

OmniAuth.config.logger = Rails.logger

Thursday, August 9, 2012

Webscraping with CasperJS and PhantomJS

Update: check out this short CasperJS screencast with accompanying exercises

I needed to scrape some data from a website without an API for my latest project. The target website used JavaScript for all of its navigation, working hard against the grain of HTML and other standards. This was anti-hypermedia: there were absolutely no regular HTML anchor tags that I could use to navigate the interface (all of them were hooked to onclick JavaScript events which computed the next URL to open dynamically) and there were barely any CSS selectors I could target. To make this work, I needed my webscraper to execute real JavaScript code to simulate a real user navigating with a real browser.

I thought for awhile I was going to have to use Selenium for this task. Because the project runs on Heroku, I thought this was going to add some very heavyweight dependencies to the project, or force me to use dedicated hosting. I know you can run Selenium in a headless mode via Xvfb, but I'd still have to get a GUI-based browser compiled for Heroku - if that sounds like what you need to do check out the Vulcan build server.

PhantomJS to the Rescue

Happily, I found another way: PhantomJS, a truely headless Webkit browser that runs JavaScript code, and has no dependencies. I downloaded the binaries from the website and dumped 'em right into my app's vendor directory.

I loved how easy it was to get started with PhantomJS but I found it to be cumbersome for a multi-step webscraping project. You have to code via a series of callbacks that can get hard to manage: for example when you ask for a new page to be fetched, you have to register a callback to be notified when and if that page load succeeds. The best feature of PhantomJS, besides being able to execute JavaScript, is its screen capture mode - very helpful for debugging.

The Missing Piece: CasperJS 

In my googling for a solution to this pain I found another awesome project built on top of PhantomJS: CasperJS. Casper gives you a nice DSL to control PhantomJS and hide the callback spaghetti code - it reminds me how EM-Synchrony wraps up EventMachine's callbacks so you can write asynchronous code in a synchronous style.

Once I got the hang of Casper my code basically wrote itself. Below is a sanitized and minimally-formatted version of the production code, also posted as a GitHub gist. Hope it helps you get started with these powerful tools.

var system = require('system');

if (system.args.length < 5) {
  console.info("You need to pass in account name, username, password, and path to casperJS as arguments to this code.");
  phantom.exit();
}

var account = system.args[1];
var username = system.args[2];
var password = system.args[3];
var base_uri = "https://example.com/" + account;
phantom.casperPath = system.args[4];

phantom.injectJs(phantom.casperPath + '/bin/bootstrap.js');

var utils = require('utils');

var casper = require('casper').create({
  verbose: true,
  logLevel: 'debug'
});

casper.on('error', function(msg,backtrace) {
  this.echo("=========================");
  this.echo("ERROR:");
  this.echo(msg);
  this.echo(backtrace);
  this.echo("=========================");
});

casper.on("page.error", function(msg, backtrace) {
  this.echo("=========================");
  this.echo("PAGE.ERROR:");
  this.echo(msg);
  this.echo(backtrace);
  this.echo("=========================");
});

casper.start(base_uri + "/login", function () {
  this.fill("form[name='login_form']", { username: username, password: password },true);
});

// can't click the reports button as that causes a weird file:// link problem
casper.thenOpen(base_uri + "reports");

casper.then(function() {
  var url = this.evaluate(function() {
    return __utils__.getElementByXPath("//a[contains(@href,'Account') and contains(@href,'Report')]").href;
  });

  // winOpenTransform is a function provided by the page; it's brittle for us to invoke it 
  // this way instead of clicking a button, but when you click the button, it pops up a new
  // window, and PhantomJS doesn't currently support popup windows. Thus I have to call
  // this function directly to avoid a popup.
  url = winOpenTransform(url.match(/http:.+?(?=')/)[0]);
  this.open(url);
});

casper.then(function() {
  casper.page.injectJs('jquery.min.js'); // so we can pick an option with the select item below
});

casper.thenEvaluate(function() {
  document.report.runtimeCondition.value = "ExampleField IS NOT NULL";
  document.report.condition.value = "'','','examplename IS NOT NULL','21'";
  document.report.target = "report";
  document.report.submit();
});

casper.thenOpen("https://example.com/" + account + "/Report/reports");

casper.then(function() {
  var url = this.evaluate(function() {
    return __utils__.getElementByXPath("//a[./text()='CSV']")["href"];
  });

  this.echo("GETTING " + url);
  this.download(url,"data.csv","GET");
});

casper.run();

Wednesday, August 8, 2012

Giving Away $4500 In Ignition Grants at Ignite Baltimore #11

Just a quick note to alert everyone to the fact that we're giving away $4500 in Ignition Grants at the next Ignite Baltimore. Kate Bladow, Scott Burkholder, and Andrea Snyder have taken over leadership of this project, along with our new fiscal sponsor gb.tc.

If you know someone that's got an idea for a new product, service, or project that would make Baltimore a better place to live and work, please encourage them to apply. More details here.

Also, I recently appeared on gb.tc's weekly podcast discussing the call for proposals to speak at Ignite. In case you're wondering what kinds of talks we're looking for, or if you just want to know what's up with Baltimore tech in general, check out the video of the show:

Monday, August 6, 2012

Sidekiq, Ruby's non-atomic require, and multithreading

I just moved the workers for my newest project from Resque to Sidekiq, and it's working beautifully. I'm saving memory and enjoying a performance boost. This is part of my overall goal to use multi-threading in Ruby as much as possible (I'm also moving the web component of this project from Unicorn to Puma). I've never liked EventMachine and I've been great influenced to favor threads over processes and over EM by David Bryant Copeland, who gave this excellent talk about multithreaded Ruby at RubyNation 2012.

But today I stumbled onto an interesting, tricky bug, which exemplifies one of the downsides of multithreaded programming.

Background

I had created a new worker that used the mechanize gem for webscraping. The worker was complicated and used several different classes to get the work done. I had to require "mechanize" in a few different files, mainly so I could reference Mechanize::Error in a couple of exception handlers. This was super well-tested code that worked great on my dev machine, but things went to hell in production.

The Bug

This worker would just get stuck with zero information in the log files - the whole thread would just deadlock. Sidekiq has a TTIN signal handler that helps you figure out where your code is stuck, but unfortunately the workers run on Heroku, and Heroku does not let you send arbitrary signals to your processes, so I couldn't use it. Instead I had to insert a bunch of logging probes in my code to see exactly what line of code was causing things to freeze.

It turns out my code was freezing on a require statement, where I required the first class which required the mechanize gem. I remembered that in Ruby require is not atomic, so I was able to zero in on the problem.

The Solution

Once I moved the require "mechanize" statement into an initialization step, before my workers were loaded, everything performed beautifully.

Lesson Learned

Quoting this Stack Overflow answer, because of the potential for require to cause deadlocks like this:
"require everything you need before starting a thread if there's any potential for deadlock in your app."


Friday, July 27, 2012

New ways to help accelerate Baltimore's renaissance

I got a nice email today from one of my favorite Baltimore groups, gb.tc, announcing a new initiative:

...we are adding a new emphasis on bringing the power of technology and entrepreneurship to building a better Baltimore...Our goal is to help connect the innovators and the new ideas with the “powers-that-be” and the resources that could help accelerate Baltimore’s renaissance.
This project is near and dear to my heart. There's been a disconnect between the powers-that-be and the independent hustlers here in town, and gb.tc has cooked up three interesting new projects to change that, excerpted below:
Groundwork - August 10–11 - Over the course of 24 hours (from Friday evening to Saturday), help collect and analyze publicly-available data about Baltimore from a wide variety of sources. We are inviting a diverse mix of technologists, public health researchers, community leaders, and non-profit representatives. Our goal is to identify points of strength and to find opportunities for action and collaboration in neighborhoods, with existing programs, and among talented people from different sectors of Baltimore innovation.
Baltimore UnWIREd - August 24–25 - An unconference to be held on the campus of Johns Hopkins University, UnWIREd will build on findings and tools developed at Groundwork. We will convene innovators and power-brokers from across the region for serious discussion and concrete action. We will identify specific problems, resources, and neighborhoods as focal points.
Start Something - Fall 2012 through Summer 2013 - We will take what we have learned from Groundwork and UnWIREd and tap into the energy and creativity of Baltimore area college students. We will connect talented young people with our innovation community and the mentorship, resources, and tools they need to build sustainable businesses that serve the goals of a greater Baltimore.
I'm particularly excited about the last one. We have a lot of smart people around here and tons of opportunities to solve real-world problems, while making lots of money. I'm looking forward to seeing what a group of these smart people can do when given a little support and mentorship while exploring useful business ideas.

Tuesday, July 24, 2012

Processes should make things easier for workers, not managers

I came across The Rands Test written late last year. This paragraph really resonated with me:
Are handwritten status reports delivered weekly via email? (-1) 
If so, you lose a point. This checklist is partly about evaluating how information moves around the company and this item is the second one that can actually remove points from your score. Why do I hate status so much? I don’t hate status; I hate status reports.
My belief is that email-based status reports are one of the clearest and best signs of managerial incompetence and laziness. There are always compelling reasons why you need to generate these weekly emails. We’re big enough that we need to cross-pollinate. It’s just 15 minutes of your time. 
Bullshit. The presence of rigid, email-based status reports comes down to control, a lack of imagination, and a lack of trust in the organization.
I couldn't agree more. When I was a Navy officer I was constantly having to write stuff like that, including writing my own fitness reports and end-of-tour awards (it was considered standard procedure to submit yourself for awards, which definitely took a lot of the specialness out of the occasion).

I've been thinking about how most managerial processes are about making things easier and more controllable for the managers. As I work to build new software organizations here in Baltimore I'm committed to flipping that on its head - what if we focus on building processes that make the people doing the work happier and more productive, instead of making the manager feel safe and in control?

It's easier said than done, I realize, but I have a feeling that such an organization would vastly outperform the more traditional form, more than enough to compensate for any errors that might occur due to a lack of all-pervasive oversight.

This Just Say No post by Angela Baldonero over at AVC definitely reenforces this opinion, that most companies are too focused on making managers feel good and not helping workers do good work:
A new world of work is being born around us. Most traditional HR practices are ineffective and irrelevant. The courage to say no to the status quo has given us the freedom to blaze a new path of freedom, flexibility and creativity.  And it’s a competitive advantage for us. Our turnover is lower than nearly any other company – in our industry or any other industry. Most of our new employees come in as referrals from existing employees. And our application to hire percentage is about 1.5% -- meaning Return Path is harder to get into than Princeton.  
My advice to you is to set your people free to focus on important, high impact work and solve challenging business problems. That’s how companies will win now.
I'm starting to lay the groundwork to recruit programmers for a new startup. If you're working somewhere that fails the Rands test, please get in touch!

Tuesday, July 17, 2012

Video of Coding for Uncertainty at Ruby Nation

Here's the video from my Coding for Uncertainty talk at Ruby Nation earlier this year, where I talk about techniques I use to build durable, changeable Ruby code:


Tuesday, July 3, 2012

Testing Rails controller security with RSpec shared examples

Like most developers I'm pretty paranoid about security. For Rails apps, although I don't normally write many a lot of controller tests (because my controllers are always very thin, and I'm usually able to cover their behavior using the style of integration testing I favor), I always make sure to test security functions. I always write tests to ensure no user should be able to view or alter another user's data. Controller tests are the only way to directly test the update, create, and delete actions.

Recently I extracted this type of test into an RSpec shared example and placed it into my power tools gem so I could DRY these tests up. It's been working awesomely. Here's an example:



The code exercises all seven of the standard Rails resource actions if your controller implements them. To see the shared example, check out the power tools gem.

Thursday, June 21, 2012

dependency injection minimal (dim) gem v1.2 released

I just released v1.2 of the dependency injection minimal gem (dim). Originally this project was just a gemification of Jim Weirich's example code, but v1.2 marks my first meaningful feature addition.

dim aims to provide a simple, Ruby-esque way to handle dependency injection. I find myself using it in all of my projects as a way to consolidate into one file all of the configuration that my apps need.

I noticed a common pattern, though. I had started to use dim to encapsulate ENV variables, so that my code would not need to know the source of a configuration variable (usually an API key or a URI for accessing a third-party service); in the test environment, the source might be a hard-coded literal string, but in production it might come from an actual ENV variable.


So I added a register_envmethod to complement the register method that Jim originally added. Below is an example of how I'm using it.


# attempts to read ENV["API_PASSWORD"], otherwise makes sure that the parent container has
# a service named api_password registered
ServerContainer.register_env(:api_password)
The above code will fail if you don't have ENV["API_PASSWORD"] defined, or if ServerContainer doesn't have a parent container with :api_password set. Typically I'm using a YAML file to populate ServerContainer's parent with sensitive values that I want to have in my development environment (and then I make sure to ignore that file in source control).

See the docs or the source code for more details.

Wednesday, June 20, 2012

Personal creative process talk with some important books


I recently had a chance to speak at a new event in Baltimore called Midmorning Social where I was asked to speak about how I work and where I find inspiration. It ended up being one of the most personal and introspective things I've ever done. The video is embedded below, or you can watch here.

I thought a lot about all of the books that had influenced me on my current path or that just resonated with me and shaped me. I mentioned a bunch of these in the talk but left out others due to time. Since I was asked over Twitter to provide links to the books, I ended up making the following reading list. Hope you find it interesting as I really enjoyed compiling it!
  • The 4 Hour Work Week / The 4 Hour Body: very trendy amongst the Internet set, I know, but full of provocative and inspiring ideas about how to design the way you live instead of just following a pre-defined path
  • Organizing from the Inside Out: very useful technique for getting organized and staying that way
  • The Primal Blueprint: helped me plan how I exercise for maximum benefit with minimal, regular investment of energy/time
  • Why We Get Fat and What To Do About It or the more intense version Good Calories, Bad Calories: helped me figure out a healthier way to eat and lose weight; also a great example of debunking widely-accepted conventional wisdom. Good to contrast with another favorite book about eating, Omnivore's Dilemma.
  • The Cybernetic Brain: still grappling with what this book means, but my favorite part is the dissection of the ontology of unknowability as applied to the brain
  • The Song of the Dodo: the first really good nonfiction book I can remember reading, really turned me into a nonfiction fan
  • Collapse: I think about what happened to the European settlements on Greenland, and how that applies to the fate of our society, almost every day
  • Wizard and Glass: probably the best novel I've ever read, an incredible coming-of-age story. There's a powerful battle scene in the end that I recall so vividly it's like I lived it.
  • Godel, Escher, Bach and I Am a Strange Loop: awesome meditations on the nature of conciousness; the first book is also just an awesome work of art, stretching the notion of what a book can be or do far beyond anything else I've read
  • Imperial Hubris: Extremely prophetic book written in the early years of the "war on terror"; greatly influences how I think about the conflicts we're embroiled in and explains why "war on terror" belongs in quotes
  • Code: The Hidden Language of Computer Hardware and Software: being a self-taught programmer, this book really helped me understand lower levels of computational abstraction that I don't usually spend much time thinking about
  • Getting Things Done: also very trendy, but definitely changed the way I work and made me much more productive
  • Daemon: great near-future novel exploring the implications of current technology developments
  • The Warrior Elite: about Navy SEAL class 228; I washed out of class 230 and this book helped me decide to move on and not try to go back
  • Man's Search for Meaning: helped me clarify the truly important sources of happiness in life (the "pillars" that I mention in the talk
  • Hackers & Painters helped me decide to leave the Navy and become a programmer
  • The Lean Startup: really great manual for how to build things with less wasted effort in the 21st century. I reference this book in business conversations many times.
  • Rapid Development and Software Estimation: introduced me to the notion that in software you want your schedule to be very predictable, not necessarily super fast
  • Code Complete: introduced me to the notions of software quality and how to achieve it
  • Full Catastrophe Living: I ran out of time to discuss meditation, but this book helped me learn how and why to meditate, and helped me cultivate a mindfulness practice
Here's the video of the talk, about 20 minutes long:

Thursday, June 7, 2012

Ruby Study Hall In Session at the Baltimore Hackathon

My project for this weekend's Baltimore Hackathon is a new screencasting series called Ruby Study Hall.  I've been working informally with a small group of people who are new to programming or new to the Ruby language, and RSH is an experiment to see if I can scale myself to help a wider group of people in public. It's been really fun explaining how to get things done in Ruby by giving the students small projects to work on and providing feedback.

The home-made Ruby Study Hall logo
Ruby Study Hall will be in session on Saturday from 2 to 4 pm at the Hackathon. Due to space restrictions you must register for the hackathon to attend (which you should do anyway, it's gonna be awesome). The registration fee includes lunch at 1 pm, so why not make an afternoon of it? If you can't attend, I'll be screencasting the whole thing for posterity and posting the video to Youtube and Vimeo.

WHAT WILL WE STUDY?

This is not a class per se. I will not be showing you how to code Ruby from scratch. The first 60 to 90 minutes is meant to be a study session for beginners, functioning like a reverse classroom. I'll be  answering beginner-level questions about Ruby based on the homework assignments people have been doing.  

The last 30-60 minutes will be aimed at intermediate and advanced-level coders. I've invited Nick Gauthier to sit-in and critique some work I've done with his Domino gem. Beginners will still like this part because it'll be a glimpse of how the smaller exercises will lead you to building something in the real world.

HOW SHOULD WE PREPARE?

To get the most of out Ruby Study Hall you should:
  • Work on some Ruby code using the tutorials listed below
  • Get stuck on something
  • Post where you're stuck somewhere online where I can easily read it (preferably at https://gist.github.com/)
  • Think of questions about programming or Ruby concepts you don't yet understand
  • Email your questions and/or the link to your code to me at mike@subelsky.com
  • Attend the live event on Saturday at 2 pm or watch the video later
Here's some homework to get you started, in no particular order:
PHILOSOPHY

So far I am seeing that it's really hard, but definitely possible to learn programming even if you've never done it before. Every programmer I know is largely self-taught, and to quote Viola Spolin, "We learn through experience and experiencing, and no one teaches anyone anything..."

Monday, May 14, 2012

Midmorning Social and Geeks on a Train

Update: fixed the date for Mid-Morning Social. Thanks Rob Wray!

I'll be speaking at the inaugural Mid-Morning Social on May 31st in Baltimore, about something very personal: how I find inspiration and the way I work. This will be a nontechnical talk and I'm very excited about it. My rough outline is:
I plan to talk in concrete, specific terms about the deeply personal vision that guides my work as a programmer, technology advocate, and entrepreneur. I'm pretty obsessed with process and making gradual improvements in process, combined with big experiments, to help me succeed in my professional and family roles. Time permitting I'll touch on some or all of these topics: GTD, blogging, Ruby, test-driven development, Beeminder, physical fitness, inbox zero, meditation, psychotherapy, how to make yourself more interested and interesting, questing, the book Godel, Escher, Bach, leadership, what I learned from being in the Navy, and more!
I'm also going to be riding all along the east coast on May 24th as part of Geeks on a Train, visiting New York and Boston. If you're anywhere along the Amtrak corridor you should totally jump on board! There are some interesting meetups planned.

Friday, April 27, 2012

Looking for an assistant, apprentice, or intern programmer

I have the good fortune of having three awesome software business projects in the pipeline. My idea garden has never been more luscious!  Our goals for these three projects are ambitious and I'd love to get some help with them.

If you've got basic programming ability and are looking for a way to get started as a professional programmer, or you want to get some experience working on early-stage products, or you think I'm an interesting person, I'd love to work with someone who wants to learn the ropes. I would give you lots of mentoring and lots of responsibility for executing different parts of these ideas. We could work out equity compensation if that's interesting to you, but the main benefit would be experiential. By the time we're done you would know a lot about how to launch your own products.

All three of these involve working with successful, super interesting, super smart non-technical entrepreneurs. So that's an additional benefit.

I don't even know if such a person exists, but I think when I was getting started I would have loved to do something like this.

Sunday, April 8, 2012

Three more important, straightforward computer security precautions

I had many non-tech friends tell me they appreciated my article about two important computer security precautions everyone should take. So here are three more I recommend:
  1. Start using different passwords for everything. I recommend either LastPass or 1Password to help you track them all. These tools take care of auto-filling the password also help you generate super strong passwords.  If you only change ONE password from the default you use everywhere, it should be your email password. If you lose control of your email you could lose control of many online services. (Note: LastPass is better if you use multiple machines, as it seamlessly syncs passwords across browsers in a secure way)
  2. Make sure the browser you regularly use has locked-down Java and Flash settings. Mac users are no longer invulnerable to these attack vectors. That article explains what Windows, Mac, and Linux users should do to avoid the whole class of attacks represented by the new Flashback malware.
  3. For laptops, store your data on an encrypted disk. Ideally you would encrypt your whole hard drive; OS X has a nice feature called File Vault that will do this for you easily, and doesn't seem to affect the computer's performance.

Tuesday, March 27, 2012

Slides from my Coding for Uncertainty talk at RubyNation

Update: here's video of the talk
I had a great time at RubyNation - definitely one of the best tech conferences I've been to! I gave a talk called Coding for Uncertainty where I spoke about some of the tips and techniques I've been using to speed up my coding process (mostly by eliminating waste and making my code easier to maintain, not by cutting corners).

Important links from the talk:
The slides are below:

Sunday, March 18, 2012

Putting shorter-form content on Tumblr

Since I aspire to the "Fred Wilson School of Blogging", I've been experimenting with blogging informal, shorter-form content on Tumblr at http://short.subelsky.com/. So far it's been pretty fun! Check me out over there if you like.

Friday, March 16, 2012

My new email signature

I've been inspired by Scott Burkholder and Matt Porterfield to change my email signature:
SENT FROM BALTIMORE
subelsky.com
@subelsky // (443) ###-####
Even as we're all more globally connected, I think it's very helpful to brand yourself as being rooted in a place and part of a community. I'm also just really proud of Baltimore and I love living here, so this is just a small way to communicate that to my correspondents.

Sunday, March 4, 2012

How to help tech entrepreneurs in your city

I've attended a few meetings lately with groups in Baltimore who want to help technology entrepreneurs. Here's what I've been thinking and saying in these meetings.

First, make your city more livable

You could do the most good by focusing on quality-of-life issues that affect everyone. People who want to start tech businesses are likely to be highly mobile with options and resources. Any city that takes itself seriously as a safe, tolerant place offering diverse choices of lifestyle, housing, and fun things to do, should automatically become a technology hub.

Fortunately, there are already many people working on improving quality of life. I asked Scott Burkholder for some examples of civic and cultural groups that are doing good work with whom we in the business community could partner. Some of his suggestions are below:
(of course Scott was too modest to mention his own public art endeavor, Baltimore Love Project)

Entrepreneurs don't actually need much direct help

By definition entrepreneurs are "relentlessly resourceful", so on some level they don't need any help - they need the government to stay out of their way (I'm looking at you, Tech Tax 2). I always think of my friend Scott Messinger and his company Common Curriculum, which I advise. That dude is not waiting for anyone to give him anything; he taught himself to code, he's overcoming all kinds of obstacles, and he's making a great product.

So if you want more tech businesses to form in your city, what can you do recruit more Scott Messingers and how do you retain the ones you already have? What can you do to make your entrepreneur corps more efficient (in the sense that they either succeed or fail-and-learn more quickly)?

Create a center of excellence

Most of the organizations I've talked to are internally-focused. They have members or clients and are primarily devoted to servicing them, because that's where their revenue comes from. What we need is a "center of excellence for technology entrepreneurship" funded by entities that care about improving Baltimore's tech industry competitiveness. This center would be externally-focused, dedicated to educating citizens about the science of entrepreneurship while helping them practice it more efficiently. This could include:
  • Hosting entrepreneurs-in-residence who offer regular office hours to local startups (perhaps this would be a good way for cashed-out entrepreneurs to give back, a place for them to hang their hats while looking for the next opportunity)
  • Publishing blogs and podcasts documenting new technology endeavors (sort of like what gb.tc is now doing) and disseminating lessons learned
  • Organizing workshops, bringing in guest speakers, hosting courses in its own classrooms, etc.
  • Coordinating tech education efforts (which might look like DC's new Hungry Academy or NYC's Academy for Software Engineering)
  • Acting as a trusted connector, brokering introductions for startups and investors/mentors/customers/service providers
  • Pooling risk and providing access to shared resources like office space (perhaps by guaranteeing leases)
There are a couple of places where that center could reside. I'm hopeful that one of the organizations I've been meeting with will take on this role. There are also two exciting projects developing this year that might house such a center or take on some of these missions, one of which is opening its doors in a few weeks. The other one, led by the Innovation Alliance, is holding a town hall meeting next week to discuss all of these issues.

Monday, February 20, 2012

A video game almost made me cry

I recently finished playing an excellent video game, Mass Effect 2 (just before Mass Effect 3 comes out), on the advice of one of my favorite writers, Tom Bissell. His video game writing on Grantland is extraordinary and his book Extra Lives is a great exploration of video games as an art form. In the book he describes how storytelling in video games has become "formally compelling" (even if the stories being told are overly baroque or poorly written) and uses Mass Effect as an example.

I totally agree with Bissell. There's a pivotal scene halfway through the game where virtually your entire crew gets captured. You're given a choice: do you want to go on a high-risk rescue mission, for which the team you lead is unprepared, or do you want to continue to prepare so you're ready for the mission? If you go on the rescue mission at that moment you're also potentially leaving a bunch of side missions undone.

While some characters were beseeching me to move quickly "while there's still time to save our crew", I had other characters cautioning me to wait, telling me that proceeding would be suicidal. I thought this was the standard sort of fake-dramatic choice offered up by video games. Why would I want to rush and  get creamed by the Collectors when I had more fun stuff to do?

So I prudently put off the rescue mission, but had an eerie feeling walking through my ship. Once, it had been populated with chattering NPCs, but now was silent. I went about completing all of the side missions and got my rescue team fully dialed-in: plussed-up attributes, awesome weapons, useful upgrades, and so on. Only then did I order the rescue attempt.

My team prevailed, and the mission turned out to be relatively easy given how prepared we were (I should say how prepared "we" were, since we're talking about virtual characters - yet they felt real enough to me). But here's the thing: when we discovered where our crew was being held, there was only one survivor left. And I saw something horrible happen to the second-to-last survivor just as we showed up. The sole survivor then lashed out at me (at my character), protesting the length of time it had taken us to arrive. She said stuff like, "I'm sorry, it was so hard watching them all die." (All this hit home because the voice acting in Mass Effect is superb, something Tom Bissell also wrote about)

It was then that I realized: had I chosen to immediately go on the rescue mission, Mass Effect 2 was programmed to let more crew members survive. That choice I made unconsciously really mattered! Maybe I could have saved all of them! A glitch in the rendering underlined this for me, somehow more poignant for being erroneously disclosed. In the background of the frames with the surviving, distraught crewmember castigating me, I could see another crew member, whom I had already been told I did not save. So obviously there was code in there to control how many survivors I got to rescue based on how long I took to get there, yet this small bug caused one of the dead crew members to show up anyway.

The scene gave me chills. It made me feel horror and sadness and regret. I can't think of any other storytelling medium that could create a similar effect, because the game implicated me in these events. I made a careless choice, even if it was the right choice, and pretend people suffered horribly. I wish I could go back and start the game over again, knowing that my decisions in this game, unlike so many others, would bear such weight. I'm also really curious to see how hard the rescue mission would have been had I listened to my gung-ho virtual colleagues, and how many more crew members I could have saved.

This is what Bissell means when he says these games have become formally compelling: a good story-driven video game can grab hold of you; can involve you; can entertain you in a deep, rich way that no other medium can. I predict that just as we are seeing with recent television, some of the best writers will start to gravitate towards this medium because it offers such rich narrative possibilities.

Friday, February 3, 2012

Speaking at RubyNation and Moderating Are There Angels Among Us?

I'll be giving a talk at RubyNation in Reston, VA on March 23rd or 24th, tentatively titled "Coding for Uncertainty: How to Design Maintainable, Flexible Code for a Startup Application". I plan to discuss lessons learned from building OtherInbox and subsequent projects, and how I try to hit my maximum sustainable development speed.

I will also be moderating a Think Big Baltimore event called Are There Angels Among Us? on 2/16 here in Baltimore, all about angel investment in the mid-Atlantic region. I have a couple of free tickets to share if anyone reading this blog would like to check it out. Email me if interested.

Hope to see you there!

Thursday, February 2, 2012

The one best way I know of to write software tests

Early in 2011 I had a prophetic conversation with fellow Baltimore hacker Nick Gauthier that radically changed the way I think about testing web applications. He described a methodology where you almost exclusively write high-level acceptance or integration tests that exercise several parts of your code at once (vs. the approach I had previously used, writing unit tests for every component backed up by a few integration tests). For a Ruby app this means using something like Capybara (depicted below), Cucumber, or Selenium to test the entire stack, the way a user would interact with your site.

These tests aren't meant to be exhaustive - you don't test every possible corner case of every codepath. Instead you use them to design and verify the overall behavior of the system. For example, you might write a test to make sure your system can cope with invalid user input:

describe "Adding cues" do
  let(:user) { Factory(:user) }
    before { login_as_user(user) }

    it "handles invalid data" do
      visit "/cues/new"
      select "Generic", from: "Type"
      expect { click_button "Create Cue" }.not_to change(Cue,:count)
      should_load "/cues"
    end
  end
end

Usually with this technique you would not write a separate test for each type of invalid data since these tests like these are fairly expensive. Instead, you combine the test above with a series of unit tests which examine the components involved in the above behavior in an isolated fashion. Typically these tests will run much more quickly because they don't involve the overhead of setting up a request, hitting the database, etc.

In the above example we could cover all of the invalid cases with a model unit test that looks like this:

describe Cue do
  it { should validate_presence_of :name }
  it { should validate_presence_of :zip_code }
end

What you end up with is a small number of integration tests which thoroughly exercise the behavior of your code combined with a small number of extremely granular tests that run quickly and cover the edge cases.

One Criticism of This Approach

This idea has been working wonderfully for me. I feel like it gives me excellent code coverage without creating a massively-long running test suite. But I did notice Nick Evans critiquing this style of testing awhile ago on Twitter:
lots of integration tests + very few unit tests => a system that mostly works, but probably has ill-defined domain models and internal APIs.
The fact that it got retweeted and favorited a number of times makes me think he's onto something, though I haven't run into this problem yet, and I'm rigorous about keeping domain models and APIs clean. I have no problems refactoring in order to keep my average pace of development high. In my experience adhering to a strict behavior-driven development approach has kept me from running into the problem he describes, but that might not hold if I was part of a team. Time will tell.