Writing a Domain-Specific Language in Ruby

Posted 4 months back at GIANT ROBOTS SMASHING INTO OTHER GIANT ROBOTS - Home

A Domain-Specific Language, or DSL, is “a programming language of limited expressiveness focused on a particular domain”. It makes tasks in its domain easier by removing extraneous code for a particular task and allowing you to focus on the specific task at hand. It also helps other people read the code, because the purpose of the code is so clear.

Here’s a little Internal DSL in Ruby:

Smokestack.define do
  factory User do
    name "Gabe BW"
    pet_name "Toto"
  end
end

user = Smokestack.build(User)
puts user.name == 'Gabe BW'  # true
puts user.pet_name == 'Toto' # true

other_user = Smokestack.build(User, name: "Bob")
puts other_user.name == 'Bob'      # true
puts other_user.pet_name == 'Toto' # true

Let’s go over each part and how it works.

Set up

First, let’s define User and Post classes that we’ll be using in our factory:

class User
  attr_accessor :name, :pet_name
end

class Post
end

We’ll be referring to these throughout the post.

Identifying method calls

When I first looked at code like Smokestack.define above, I had a hard time identifying where methods were being called. Let’s add parentheses:

Smokestack.define do
  factory(User) do
    name("Gabe B-W")
    pet_name("Toto")
  end
end

That’s better. Now we can see that Smokestack.define takes a block, and the factory method takes a class, like User, and a block. But where is the factory method coming from?

instance_eval

To find out, we need to look at the instance_eval instance method, available on every class. According to the docs:

Evaluates a string containing Ruby source code, or the given block, within the
context of the receiver (obj). In order to set the context, the variable self is
set to obj while the code is executing, giving the code access to obj’s instance
variables.

Here’s an example:

class DefinitionProxy
  def factory(factory_class)
    puts "OK, defining a #{factory_class} factory."
  end
end

definition_proxy = DefinitionProxy.new
definition_proxy.instance_eval do
  factory User
  factory Post
end

That code prints out this:

OK, defining a User factory.
OK, defining a Post factory.

The factory User and factory Post are evaluated in the context of the definition_proxy instance. That means that factory User in the definition_proxy.instance_eval block is actually calling definition_proxy.factory(User).

Now let’s add it to Smokestack:

module Smokestack
  def self.define(&block)
    definition_proxy = DefinitionProxy.new
    definition_proxy.instance_eval(&block)
  end
end

Smokestack.define is now the entry point for our DSL. It takes a block, then evaluates that block in the context of a DefinitionProxy instance.

Registering Factories

Now that our code sort of works, let’s register factories. Factories aren’t helpful unless we can refer to them, and to do that we need a central registry. The simplest registry is a hash that maps factory classes to factories.

The following code gives us Smokestack.registry:

module Smokestack
  @registry = {}

  def self.registry
    @registry
  end
end

Let’s change the factory method to register factories when they’re declared:

class DefinitionProxy
  def factory(factory_class)
    factory = lambda { puts "OK, creating a #{factory_class}." }
    Smokestack.registry[factory_class] = factory
  end
end

Instead of printing out a message immediately, we wrap it in a lambda. This means that we can store that lambda in the registry, and call factories whenever we like after registering them:

Smokestack.define do
  factory User
end

Smokestack.registry[User].call # => "OK, creating a User."
Smokestack.registry[User].call # => "OK, creating a User."

Diving Deeper

Now we can declare that a factory exists, but it’s not really a factory yet. It doesn’t actually initialize objects. Let’s look at the original code again:

factory User do
  name "Gabe BW"
  pet_name "Toto"
end

We want that code to declare a factory that does the following:

user = User.new
user.name = "Gabe BW"
user.pet_name = "Toto"
return user

Like Factory Girl, we’ll assume that:

  • factory User refers to the User class
  • The User class has setter methods for every attribute in the factory (e.g. name=)

Each factory might have different setter methods (e.g. pet_name=), so we’ll use method_missing to handle every case.

Let’s take a stab at it:

class Factory < BasicObject
  def initialize
    @attributes = {}
  end

  attr_reader :attributes

  def method_missing(name, *args, &block)
    attributes[name] = args[0]
  end
end

class DefinitionProxy
  def factory(factory_class, &block)
    factory = Factory.new
    if block_given?
      factory.instance_eval(&block)
    end
    Smokestack.registry[factory_class] = factory
  end
end

DefinitionProxy#factory now passes its block to a Factory instance, then stores the Factory instance in the registry. If there’s no block (i.e. if block_given? evaluates to false), then the factory does not evaluate the block, but is still put in the registry. Here’s a case where we have no block, because Post has no attributes:

Smokestack.define do
  factory Post
end

Factory inherits from BasicObject, which is a class with very few methods defined. It’s great for use in metaprogramming like this, where you want every instance method call to trigger method_missing.

We now have all of the Smokestack.define DSL working, with factories and a registry to map factory names to stored factories. Let’s add Smokestack.build.

Smokestack.build

Smokestack.build(User) needs to do the following:

  • Grab the user factory
  • Set attributes on the user, with optional overrides
  • Return the user

To get the attributes, we can grab factory.attributes from the user factory in the registry. Let’s have Smokestack.build take an optional second parameter, overrides, which allows people to pass custom values.

Here’s the code:

module Smokestack
  def self.build(factory_class, overrides = {})
    instance = factory_class.new

    # Set attributes on the user
    factory = registry[factory_class]
    attributes = factory.attributes.merge(overrides)
    attributes.each do |attribute_name, value|
      instance.send("#{attribute_name}=", value)
    end

    # Return the user
    instance
  end
end

Putting it all together

Here’s what we ended up with:

module Smokestack
  @registry = {}

  def self.registry
    @registry
  end

  def self.define(&block)
    definition_proxy = DefinitionProxy.new
    definition_proxy.instance_eval(&block)
  end

  def self.build(factory_class, overrides = {})
    instance = factory_class.new
    factory = registry[factory_class]
    attributes = factory.attributes.merge(overrides)
    attributes.each do |attribute_name, value|
      instance.send("#{attribute_name}=", value)
    end
    instance
  end
end

class DefinitionProxy
  def factory(factory_class, &block)
    factory = Factory.new
    factory.instance_eval(&block)
    Smokestack.registry[factory_class] = factory
  end
end

class Factory < BasicObject
  def initialize
    @attributes = {}
  end

  attr_reader :attributes

  def method_missing(name, *args, &block)
    @attributes[name] = args[0]
  end
end

Let’s run it through its paces:

Smokestack.define do
  factory User do
    name "Gabe BW"
    pet_name "Toto"
  end
end

user = Smokestack.build(User)
puts user.name
#=> "Gabe BW"
puts user.pet_name
#=> "Toto"

other_user = Smokestack.build(User, name: 'Bob')
puts other_user.name
#=> "Bob"
puts other_user.pet_name
#=> "Toto"

Neat.

How could this be made better?

The use of a class directly (factory User) looks out-of-place if you’re familiar with Rails idioms or Factory Girl. To make this more Rails-y, we’d use a symbol like factory :user. To make this work, we can use plain Ruby or ActiveSupport:

# Plain Ruby
Object.const_get(:user.capitalize) #=> User

# ActiveSupport
:user.capitalize.constantize #=> User

Further Reading

For more examples of DSLs, check out factory_girl or the Rails routes.

Finding the perfect house using open data

Posted 4 months back at Encytemedia - Home

1283d6a2014211e3a98422000aa80fc9_7

My childhood backyard.

Growing up in rural Mississippi had its perks. Most days my brother and I would come home from school, grab a snack from the fridge, and head outside to fish in the pond tucked behind the tree line or play basketball with the neighborhood kids. It was very much a community where everyone knew everyone. I had known many of the kids from my graduating class since second grade and my parents knew their parents since highschool and earlier.

As beautiful as my hometown was, it was, like many small towns, economically depressed and void of all but the necessities. As I grew older, I became frustrated by this. We had one small grocery store, one stop light, two movie rental places and not a single fast food restaurant. We had no book stores, no electronic stores, no big-box stores and only a couple of places to grab a bite to eat.

Truth be told, the gas station (one of those big ones, forever known as “The BP” long after a name change) was where we picked up most of our take out. When highway 72 was expanded to four lanes, a nearby gas station was converted to a “super” station. It was packed with a pizza place, fresh sub sandwiches, and the best chicken strips that have ever graced the space below a heat lamp. It was the community watering hole.

The lack of access eventually wore on me. As I started to grow my design skills (my Hail Mary escape from factory work), I would hear of my peers in larger cities going out to eat, to the movies, or just having a beer at a nearby bar. Beer, by the way, was illegal where I grew up. Not just the consumption of it, the mere possession of it.

6307658831_df66e3f10d_b

Portland - Oregon by Patrick M. License CC BY-NC-SA 2.0

By 2007, after a couple of years on the outskirts of Memphis, TN, I had finally had enough and convinced my wife to move to Portland, OR. We knew very little about Portland at the time. In fact, we knew so little about the Pacific Northwest, we moved in the dead of winter, in a sports car, driving through the Cascade mountain range. It’s not exactly something I’m proud of; a hilariously ill-conceived cross-country trip.

When we moved to Portland we decided we wanted to be in the center of it all. There was so much life around us; so much happening relative to our rural upbringing. I wanted to be as close to Downtown as I could be so I could go as often as I liked.

We eventually settled on the Pearl District. A relatively new residential development that was previously occupied by a rail yard. Finally, I would have the access that I once craved. Almost anything I wanted was a short walk or streetcar ride away. All that I wished for growing up, I would have.

8bb23018889a11e18cf91231380fd29b_7

Fast forward 7 years and we’re still in the Pearl District. We’ve added a member to our family who now desires access to the things I had while growing up. He wants a yard to play in, a basketball goal and a proper house where he can get excited without disturbing our neighbors.

It’s an interesting scenario. The Pearl District and Downtown aren’t exactly teaming with affordable single family homes and the further you move out of the city center, generally the less access you have to the many things a dense urban area has to offer. But, in reality, I only wished for a couple of things out of a new location.

The journey begins

After thinking about the problem, I decided to list out a set of criteria for a location I would want to live. Other factors will eventually come into play, but I wanted to narrow down the city into “target zones”—that is, zones that meet a set of defined criteria.

  • Walking distance to a grocery store: Living across the street from a grocery store has spoiled me.
  • Walking distance to a rail stop: This will allow me to get to other locations in the city without a car relatively quickly. One could argue the bus system is just as good, but I would argue that it isn’t and I much prefer rail.

I defined walking distance as ~5 blocks, but ~10 blocks is still a pretty sane distance. I want to be close to a grocery store and close to a MAX or Streetcar stop. Unfortunately, none of the real estate applications I tried had a feature like this so I decided to create what I needed using open data that I had already been working with for some time now.

Gathering the data

This section makes heavy use of GDAL and PostGIS. Both of which can be installed using homebrew on OSX.

We’ll need 3 open datasets.

After downloading the data, we’ll want to reproject the building dataset to EPSG:4326 so that all of the data shared the same projection. EPSG:4326 (WGS84) is a common projection and the projection of the other two datasets so I went with that.

ogr2ogr -t_srs EPSG:4326 -f "ESRI Shapefile" building-footprints.shp  Building_Footprints_pdx.shp

Note: EPSG:2913, the original projection of the building dataset, is probably the more accurate choice if we were concerned with a high level of precision.

Now we need to create a PostGIS-enabeld Postgres database

createdb portland
psql -c "create extension postgis" -d portland

Finally, we need to import the datasets to our freshly created Postgres database. See the shp2pqsql docs for an explanation of the flags used. Essentially we want to import as latin1 (there are some encoding errors in the building dataset), force 2d geometry and create an index on the geometry column.

shp2pgsql -W "latin1" -t 2D -I -D -d -s 4326 building-footprints.shp building_footprints | psql -d portland
shp2pgsql -W "latin1" -t 2D -I -D -d -s 4326 osm-polygons.shp osm_polygons | psql -d portland
shp2pgsql -W "latin1" -t 2D -I -D -d -s 4326 trimet-rail-stops.shp trimet_rail_stops | psql -d portland

After we have the data imported into Posgtres, we can begin to find target geometries (buildings) that meet the criteria we set. The first thing we want to do is find the zones around all supermarkets using st_expand. Our units are decimal degrees and 0.0045 is about the desired distance of ~5 blocks. We’re not too worried about being a little off here.

select st_expand(geom, 0.0045) as zone, 5 as score from osm_polygons where osm_polygons.shop='supermarket'

zones

At this point, we have large rectangle geometries. As you can tell from the image above, some buildings lie in overlapping zones. We want to score those buildings for every zone they intersect with. In similar fashion, we want to find the zones around rail stops and public parks.

The next thing we want to target individual buildings instead of merely drawing a large box around a zone. We can find all buildings that intersect a zone using st_intersects.

select * from supermarket_zones inner join buildings on st_intersects(supermarket_zones.zone, buildings.geom) where buildings.subarea='City of Portland'

screen shot 2014-05-24 at 11 42 14 am

Finally, we want to group identical geometries, sum the score and stuff the target buildings into a new table. We don’t necessarily need to add the target buildings to a new table, but continuously running these queries across the entire building set can be slow.

select sum(score) as rank, gid, geom into target_homes from target_buildings group by 2, 3;

Here’s what everything looks like combined which can be run using psql -f score-buildings.sql -d portland.

<script src="https://gist.github.com/Caged/d9b988485b813b14c69b.js"> </script>

Styling the results

Mapbox has a great crash course on TileMill. I highly recommend you check it out if you’re unfamiliar with it.

The last major thing we need to do is to visualize the results on a map. For this, I’ll use the open source editor Tilemill by Mapbox. This step is pretty straight forward since we’ve already done the hard work of extracting and scoring the buildings we’re interested in. We only need to supply Tilemill with the name of the table we stored our target homes in.

screen shot 2014-05-24 at 11 54 05 am

Finally, let’s fill each building with a color based on its score using CartoCSS.

#homes {
  [rank >= 5] {
    polygon-fill: #ea97ca;
  }

  [rank >= 10] {
    polygon-fill: #3581ac;  
  }

  [rank >= 15] {
    polygon-fill: #4dac26;
  }

   [rank >= 20] {
    polygon-fill: #a9bb29;
  }
}

We can add more layers to help give some context to our results. Here’s what I ended up with after adding layers for rail lines, rail stops and supermarkets.

screen shot 2014-05-24 at 12 04 49 pm

And that’s it. Now I have a good idea of locations I can check out in my quest to find a house nearby a supermarket and rail line. Nothing like quickly grabbing a beer for a backyard barbecue and a little game of basketball. And hey, when the Trail Blazers play? I’ll just walk a few blocks and hop on the MAX.

Episode #467 - May 23rd, 2014

Posted 4 months back at Ruby5

Some new stuff(Rspec3 rc1, ActiveJob), some cool stuff(Devise-two-factor, Camcorder), and some educational stuff (Teaching kids of Pis, Weirich on Exceptions) in this RubyLoco-powered edition of Ruby5!

Listen to this episode on Ruby5

This episode is sponsored by New Relic

Brought to you by NewRelic
This episode is sponsored by New Relic

ActiveJob

Active Job is a framework for declaring jobs and making them run on a variety of queueing backends. In just a few days, it has gone from a neat idea to a functional job abstraction on top of 8 Ruby Job queue libraries.
ActiveJob

devise-two-factor

Devise-two-factor is a minimalist extension to Devise which offers support for two-factor authentication
devise-two-factor

inch pages

If you are a gem developer or maintain a library you probably already use badges in your README to show that your tests are passing and your code isn't a horrible mess in need of refactoring. Now you can also show that you documented your project properly.
inch pages

camcorder

Need to have VCR-like functionality for more than just http? Wait no more. This gem allows you to record arbitrary method invocations from arbitrary objects.
camcorder

Kids and Pis

Last fall I volunteered at my kids school and taught over 200 kids the ‘hour of code curriculum’. I’m trying to get together a summer program for about 15 kids around 5th grade, giving them raspberry pis, support, and ideas on fun stuff to do. I’m using Ruby5 as a soapbox to find others doing similar things. If you’re interested in collaborating as teachers and doing something in your area, reach out on twitter (@bokmann)
 Kids and Pis

Active Record Soup

Once upon a time there was a small but prosperous village...
Active Record Soup

Weirich on Exceptions

Writes Avdi Grim, "Back in 2011 I was doing research for the talk that became Exceptional Ruby, and Jim Weirich was nice enough to let me pick his brain on the topic. I was reminded of this email today, and thought I’d share it."
Weirich on Exceptions

Working Effectively with Unit Tests

Posted 4 months back at Jay Fields Thoughts

Unit Testing has moved from fringe to mainstream, which is a great thing. Unfortunately, as a side effect developers are creating mountains of unmaintainable tests. I've been fighting the maintenance battle pretty aggressively for years, and I've decided to write a book that captures what I believe is the most effective way to test.

From the Preface

Over a dozen years ago I read Refactoring for the first time; it immediately became my bible. While Refactoring isn’t about testing, it explicitly states: If you want to refactor, the essential precondition is having solid tests. At that time, if Refactoring deemed it necessary, I unquestionably complied. That was the beginning of my quest to create productive unit tests.

Throughout the 12+ years that followed reading Refactoring I made many mistakes, learned countless lessons, and developed a set of guidelines that I believe make unit testing a productive use of programmer time. This book provides a single place to examine those mistakes, pass on the lessons learned, and provide direction for those that want to test in a way that I’ve found to be the most productive.
The book does touch on some theory and definition, but the main purpose is to show you how to take tests that are causing you pain and turn them into tests that you're happy to work with.

For example, the book demonstrates how to go from...

looping test with many (built elsewhere) collaborators
.. to individual tests that expect literals, limit scope, explicitly define collaborators, and focus on readability
.. to fine-grained tests that focus on testing a single responsibility, are resistant to cascading failures, and provide no friction for those practicing ruthless Refactoring.
As of right now, you can read the first 2 chapters for free at https://leanpub.com/wewut/read

I'm currently ~25% done with the book, and it's available now for $14.99. My plan is to raise the price to $19.99 when I'm 50% done, and $24.99 when I'm 75% done. Leanpub offers my book with 100% Happiness Guarantee: Within 45 days of purchase you can get a 100% refund on any Leanpub purchase, in two clicks. Therefore, if you find the above or the free sample interesting, you might want to buy it now and save a few bucks.

Buy Now here: https://leanpub.com/wewut

SSL for Rails with Heroku and DNSimple

Posted 4 months back at GIANT ROBOTS SMASHING INTO OTHER GIANT ROBOTS - Home

SSL certificates can be intimidating but Heroku and DNSimple make the process easy. The following steps should take us less than 15 minutes.

Buy the SSL certification from DNSimple

Buy a wildcard certificate from DNSimple. The wildcard (*) lets us use the same certificate on staging, production, and any other future subdomains (api, etc.).

Prepare the SSL certificate

Follow the wildcard certificate instructions to get .pem, .crt, and .key files prepared.

Follow these instructions to complete .key preparation, provision the SSL addon from Heroku, and add the certificate to Heroku:

heroku certs:add server.crt server.key

Replace it with:

heroku certs:add *.{pem,crt,key}

Otherwise, we might see an error like:

Updating SSL Endpoint myapp.herokussl.com for [heroku-app]... failed
 !    Internal server error.

Get SSL endpoint from Heroku

Run:

heroku certs

This provides us the correct end point for the SSL enabled domain. This is a domain that looks like tokyo-2121.herokussl.com.

Add Heroku SSL endpoint to DNSimple

Next, go to our DNSimple dashboard and update/add the CNAME record for the SSL enabled domain to point to (e.g.) tokyo-2121.herokussl.com.

Prepare Rails app

Make a one-line configuration change in our staging and production environment config files within our Rails app:

# config/environments/{staging,production}.rb
config.force_ssl = true

Deploy that change.

Now, if users type “ourdomain.com”, they should be redirected to “https://www.ourdomain.com” and our browser’s URL bar should display its appropriate indicator (perhaps a green lock) declaring the SSL certificate is valid.

What’s next?

Read our production checklist to see a full list of things, including SSL, that should be done before an application goes live.

Episode #466 - May 20th, 2014

Posted 4 months back at Ruby5

Unexpected new Ruby, plenty of SMTP, Discovery Tests and their mocks, heroes building ROM, Windows longing for ExecJS, Napybaras, and dangerous :nodocs: this week on Ruby5.

Listen to this episode on Ruby5

Sponsored by RailsLTS

With the release of Rails 4, support for Rails 2.3 and Rails 3.0 has ended. Security vulnerabilities are no longer patched for these versions. Rails LTS offers a solution for mission critical applications by providing security patches for old versions of Rails.
This episode is sponsored by RailsLTS

Ruby 1.9.3-p547 released

Last week, Ruby 1.9.3­p547 was released. As the release announcement explains, there is one exception to the security ­only maintenance phase that 1.9.3 is currently in, and that’s critical regressions. Apparently some Ruby users on Ubuntu 10.04 LTS noticed that when their system had an old version of OpenSSL, a segfault was possible when using the get method on Net::HTTP, and this release fixes that prevents the segfault. Only affected users are invited to upgrade. ���
Ruby 1.9.3-p547 released

Email failover with MultiSMTP

Harlow Ward wrote in to let us know about a small library from Michael Choi and his blog post on the HotelTonight engineering blog covering Rails email failover with multi­SMTP support. Using the Mail gem, MultiSMTP gives your app multiple SMTP server configuration support with failover. With multiple SMTP servers configured ­like SendGrid, Mandrill, or Google ­you get multiple host redundancy and very likely geographical and service redundancy.
Email failover with MultiSMTP

Mock Objects in Discovery Tests

The virtue and value of mocks has been under siege for the past few weeks as DHH and others attacked the construct for enabling bad behavior when testing. Justin Searls, who I discovered with his great Breaking Up With Your Test Suite talk at Ancient City Ruby this year, created a great screencast in which he shows how useful mocks can be in what he calls Discovery Tests. He describes only using mocks to the extent he needs them in order to specify the contract between a subject's dependencies. The screencast is quite thorough and provides a lot of concrete examples. I think whether you agree with him or not, it’s rare enough to be able to witness another developer’s design habits at play, that you should take the time to watch this. He also mentions Gary Bernhardt’s Test Isolation Is About Avoiding Mocks post which is long, but quite worth the read, as well.
Mock Objects in Discovery Tests

Help Us Build ROM

Piotr Solnica, maintainer of ROM — the Ruby Object Mapper library — put together a post where he describes the current state of ROM, the purpose, the foundation, where it’s been, the current ecosystem, and most importantly, instructions on how to get started contributing to the project. Because the project has been going on for so long, there is a lot of history and experimentation. There’s also a large number of libraries and concepts floating around. Things like mutant for mutation testing, memoizable for method return value memoization and adamantium to create immutable objects. So, rather than have to re­-explain all of this knowledge for each developer who wants to get started, he distilled it into one page.
Help Us Build ROM

ExecJS is looking for a new Windows-friendly maintainer

Josh Peek, the current maintainer of the ExecJS gem (which the Asset Pipeline depends on) announced on Twitter yesterday that he’s looking for a more active maintainer for the project, especially someone who cares about Windows support.
ExecJS is looking for a new Windows-friendly maintainer

Napybara

George Mendoza wrote in to let us know about a Capybara extension library that he’s created and released, called Napybara. It's a Capybara extension which adds a lightweight DSL for defining Capybara helpers that are easy to abstract, compose, and introspect. An example of this are for nested reference support for selecting your page inputs and elements. Basically, rather than just working with element names or whatever, with Napybara, you can "dot-­reference" page objects by tag name or class to get all the way down to what you’re after. Rather than maybe doing within scopes or something, you can now just reference elements more directly with something like "testpage.form.row­1.text_field". You can find by Ruby objects or selectors, you can easily determine element existence, it works with RSpec and it is extensible. Check it out on GitHub.
Napybara

:nodoc: means tread lightly

Zachary Scott wrote an interesting piece of documentation for Rails last week, covering method visibility. While the Ruby core team marks methods that people shouldn’t use directly as private, on the Rails core team some internal methods are indeed public but they’re marked with a :nodoc: comment. A lot of people do ingenious stuff with internal methods like arel_table and end up getting bit whenever they are changed, renamed or removed without notice from the Rails core team because that’s exactly what people should expect.
:nodoc: means tread lightly

Project Retrospective: Reserve A Game

Posted 4 months back at GIANT ROBOTS SMASHING INTO OTHER GIANT ROBOTS - Home

Reserve A Game

Earlier this year, Boston startup Reserve a Game came to thoughtbot to design their product: a way for people to reserve time at local public tennis courts. Many in our office are familiar with the disappointment of showing up to the Boston Common courts after work, only to find a long line to play. For frequent tennis players, this becomes less of a slight annoyance and more of daily problem. At a time when most everything can be reserved (tables at a restaurant, seats for a movie), it seemed like a great idea, but first we needed to test our assumptions.

Here’s a look at our process, from design sprint to launch:

The Problem

The experience of playing tennis on public courts is frustrating. The challenge of finding an open court, uncertainty about court availability, and the potential of having to wait, get in the way of playing the game.

The Product

What does it need to be? What does it need to provide? Who is it for? We had to eliminate a lot of feature ideas, even good ones, to settle on searching and reserving as the main jobs to be done in the application. Our biggest challenge was to meet the needs of both tennis players who would reserve courts, and cities that would adopt this service. For an early-stage startup, it can be a challenge to balance user needs with sales. In this case, it was clear that the founders valued user experience above all, so we charged ahead, hoping that if tennis players would use the product, cities would want to adopt it.

The design sprint wasn’t easy, but it was worth it. We had a done a lot of work before we came to thoughtbot, but this process helped us to put a framework to our concepts and whittle our options down to the best user flow possible for players. We also discovered what we all felt was the best design to ensure a great experience on both mobile and desktop.

Brent Colson, Founder, Reserve a Game

The Critical Path

What tasks does a person need to be able to do with this product? After diverging for a day to sketch the user flow individually, we came together to draw the critical path as a group. This drawing served as the basis for our prototype.

Testing and Learning

We interviewed tennis players and watched them click through the prototype. These conversations validated our assumption that avid tennis players would, in fact, pay for the convenience of a reservation. However, using this app needed to be easier than just showing up and waiting in line.

Some of our assumptions turned out to be false. For example, we assumed people wouldn’t care about the specific court they reserved in a facility. We were wrong. While some people didn’t care, the most avid players (our target users) noted that they often had a preference, and would appreciate the option to choose. Our prototype had focused on selecting any available court in a facility, rather than choosing a specific court. We now knew we needed to add court selection back to the top of our feature list.

User testing did two main things for us. First, our assumptions went through the ringer and some proved to be false, allowing us to pivot in minor ways to save us big money down the road. Second, it proved to be another validation of just how much need there is for our product. Most testers were surprised by how easy the process was and told us they would definitely use the service. It was music to our ears…

Brent Colson, Founder, Reserve a Game

The Development Process

Over the course of 200+ git commits, we built the MVP in time for the spring season in Boston. The design sprint helped us to understand our assumptions and risks up front and gave us a clear direction. With many potential problems having already been addressed, we moved quickly through development. Daily standups, weekly retrospectives and constant communication kept our team focused on delivering the right product.

I thought I knew agile development before we started working with thoughtbot, but their expertise and process helped me grow tremendously in my own ability to manage these types of projects. They helped me to constantly challenge assumptions and find better, or simpler ways to build our product. In the end, we built the right product, which wasn’t necessarily how we envisioned it before we started with thoughtbot.

Brent Colson, Founder, Reserve a Game

If you want to learn more about our process, take a look at our design sprint methodology.

Reserve a Game has now launched their service in the Boston area. They are looking for creative people, including designers and developers, to join their team to help create the future of community sporting services. If you are interested, please get in touch with Brent Colson.

Weighing in on Long Live Testing

Posted 4 months back at Jay Fields Thoughts

DHH recently wrote a provocative piece that gave some views into how he does and doesn't test these days. While I don't think I agree with him completely, I applaud his willingness to speak out against TDD dogma. I've written publicly about not buying the pair-programming dogma, but I hadn't previously been brave enough to admit that I no longer TDD the vast majority of the time.

The truth is, I haven't been dogmatic about TDD in quite some time. Over 6 years ago I was on a ThoughtWorks project where I couldn't think of a single good reason to TDD the code I was working on. To be honest, there weren't really any reasons that motivated me to write tests at all. We were working on a fairly simple, internal application. They wanted software as fast as they could possibly get it, and didn't care if it crashed fairly often. We kept everything simple, manually tested new features through the UI, and kept our customer's very happy.

There were plenty of reasons that we could have written tests. Reasons that I expect people will want to yell at me right now. To me, that's actually the interesting, and missing part, of the latest debate on TDD. I don't see people asking: Why are we writing this test? Is TDD good or bad? That depends; TDD is just a tool, and often the individual is the determining factor when it comes to how effective a tool is. If we start asking "Why?", it's possible to see how TDD could be good for some people, and bad for DHH.

I've been quietly writing a book on Working Effectively with Unit Tests, and I'll have to admit that it was really, really hard not to jump into the conversation with some of the content I've recently written. Specifically, I think this paragraph from the Preface could go a long way to helping people understand an opposing argument.

Why Test?

The answer was easy for me: Refactoring told me to. Unfortunately, doing something strictly because someone or something told you to is possibly the worst approach you could take. The more time I invested in testing, the more I found myself returning to the question: Why am I writing this test?

There are many motivators for creating a test or several tests:
  • validating the system
    • immediate feedback that things work as expected
    • prevent future regressions
  • increase code-coverage
  • enable refactoring of legacy codebase
  • document the behavior of the system
  • your manager told you to
  • Test Driven Development
    • improved design
    • breaking a problem up into smaller pieces
    • defining the "simplest thing that could possibly work"
  • customer approval
  • ping pong pair-programming
Some of the above motivators are healthy in the right context, others are indicators of larger problems. Before writing any test, I would recommend deciding which of the above are motivating you to write a test. If you first understand why you're writing a test, you'll have a much better chance of writing a test that is maintainable and will make you more productive in the long run.

Once you start looking at tests while considering the motivator, you may find you have tests that aren't actually making you more productive. For example, you may have a test that increases code-coverage, but provides no other value. If your team requires 100% code-coverage, then the test provides value. However, if you team has abandoned the (in my opinion harmful) goal of 100% code-coverage, then you're in a position to perform my favorite refactoring: delete.
I don't actually know what motivates DHH to test, but if we assumed he cares about validating the system, preventing future regressions, and enabling refactoring (exclusively) then there truly is no reason to TDD. That doesn't mean you shouldn't; it just means, given what he values and how he works, TDD isn't valuable to him. Of course, conversely, if you value immediate feedback, problems in small pieces, and tests as clients that shape design, TDD is probably invaluable to you.

I find myself doing both. Different development activities often require different tools; i.e. Depending on what I'm doing, different motivators apply, and what tests I write change (hopefully) appropriately.

To be honest, if you look at your tests in the context of the motivators above, that's probably all you need to help you determine whether or not your tests are making you more or less effective. However, if you want more info on what I'm describing, you can pick up the earliest version of my upcoming book. (cheaply, with a full refund guarantee)

Rails Is Not Dead

Posted 4 months back at Luca Guidi - Home

A few years ago, my lead develop of the time, told me: “Beware of the coupling that you’re introducing in your models”. My answer was: “Hey, you don’t know what you’re talking about, this is ActiveRecord”.

I was an unexperienced developer fascinated by the innovation that Rails introduced. After all, my technology was able to get rid of all that configurations, and all that boring stuff from the past.

- Patterns?
- I don't need them. I have the Holy Grail: MVC.
- Interfaces?
- Are you kidding me? This isn't Java, it's Ruby!

We all have been there. We were recovering from the consequences of the New Economy economy bubble burst. A new wave of technologies was raising: AJAX, Rails, and the Web 2.0. All was exciting, we felt like we’d learned from the past mistakes. We were creating a new way to sell software, we needed to be agile, fast and pragmatic.

All that thinking about the architecture looked like an unnecessary aftermath of the enterprise legacy.

Fast forwarding to today, after years spent on several projects, countless hours staring at a monitor, helping startups, banks, broadcasting and highway companies, non-profit organizations, large and small Open Source projects, I can confess one thing: I was wrong.

Rails has the undeniable credit to have changed the way we do web development. It has lowered the entry level so much, that even people without a background as programmers have been able to create a successful business. But this had a cost: technical debt.

I don’t blame Rails for this, as we shouldn’t blame TDD for writing damaged code. We write it, we generate legacy while writing it. We take merits when it’s good, we’re to blame when it isn’t.

But honestly, I don’t get one thing: why half of the Ruby community is so scared to talk about better code?

I have my own opinions about software, that now are diverging from Rails. I’m creating a web framework to introduce new ideas and rethink architectures. I hope to remove the pain points that have been a problem for my direct experience as a programmer.

And you know what? I might be wrong, but don’t be afraid to talk with me. Don’t you recognize this is diversity too? I don’t claim to be right like the leaders of this community think they are. I don’t think that the ideas that I had ten years ago are still valid, like they do.

The current leaders are behaving like those old politicians who say that global warming is a scam: they get defensive because their world is criticized. They keep saying to not worry about, that the problem doesn’t exist, but it does.

Rails is not dead. Debating about things such as the hexagonal architecture isn’t an assault to the framework, but a way to evolve as a community. If they feel under attack, we have a problem.

Please speak up.

Refactoring with an apprentice

Posted 4 months back at GIANT ROBOTS SMASHING INTO OTHER GIANT ROBOTS - Home

When I was part of thoughtbot’s apprentice.io program, I spent my days learning to code in a functional, maintainable and scalable way. In my first two weeks, refactoring with my mentor Anthony became one of my favorite exercises.

In my third week as an apprentice, we sat down to refactor a test I wrote for my breakable toy application. This is the process we followed:

# spec/features/teacher/add_an_assignment_spec.rb

require 'spec_helper'

feature 'teacher adding an assignment' do
  scenario 'can create an assignment with valid attributes' do
    teacher = create(:teacher)
    course1 = create(:course, name: 'Math', teacher: teacher)
    course2 = create(:course, name: 'Science', teacher: teacher)
    course3 = create(:course, name: 'History', teacher: teacher)
    course4 = create(:course, name: 'Quantum Physics', teacher: teacher)

    visit new_teacher_assignment_path(as: teacher)

    select 'Science', from: :assignment_course_id
    fill_in :assignment_name, with: 'Pop Quiz'
    fill_in :assignment_description, with: 'I hope you studied!'
    select '2014', from: :assignment_date_assigned_1i
    select 'January', from: :assignment_date_assigned_2i
    select '15', from: :assignment_date_assigned_3i
    select '2014', from: :assignment_date_due_1i
    select 'January', from: :assignment_date_due_2i
    select '17', from: :assignment_date_due_3i
    fill_in :assignment_points_possible, with: 100
    click_button I18n.t('helpers.submit.create', model: 'Assignment')

    expect(current_path).to eq(teacher_assignments_path)
    expect(page).to have_content('Course: Science')
    expect(page).to have_content('Name: Pop Quiz')
    expect(page).to have_content('Description: I hope you studied!')
    expect(page).to have_content('Date assigned: January 15, 2014')
    expect(page).to have_content('Date due: January 17, 2014')
    expect(page).to have_content('Points possible: 100')
  end
end

Check out this repo to follow along.

Key areas to improve on:

  • The section of code for filling out the form is not very legible especially the date fields.
  • The date_assigned and date_due fields are not named using Rails idioms.
  • There is a lot of repetition.
  • The code is not reusable.
  • It is important to abstract as many strings from your code as possible to make future changes less painful.

Where to begin?

Idiomatic date attributes

First we looked at some low hanging fruit. Anthony asked me, “when we use t.timestamps in a migration, what are the attribute names?” I knew immediately where he was going with this. Timestamps are named created_at and updated_at. The reason they are named with _at is because it gives developers context that says, “this is a DateTime.” Similarly, when naming Date attributes, the proper Rails idiom is _on.

This may seem like a small thing, but following conventions makes it much easier for other developers (including my future self) to read and derive context about my attributes without having to dig.

So, we changed date_assigned and date_due to assigned_on and due_on respectively:

select '2014', from: :assignment_assigned_on_1i
select 'January', from: :assignment_assigned_on_2i
select '15', from: :assignment_assigned_on_3i
select '2014', from: :assignment_due_on_1i
select 'January', from: :assignment_due_on_2i
select '17', from: :assignment_due_on_3i

Updated assertions to follow the same convention:

expect(page).to have_content('Assigned on: January 15, 2014')
expect(page).to have_content('Due on: January 17, 2014')

We check to make sure our test passes and make a commit.

Create what you need, and nothing more

This test creates 4 courses, so that a teacher must select which course the assignment belongs to. This could be done much more efficiently by using some simple Ruby. However, upon further consideration, having more than 1 course is not only unnecessary, but detrimental to our test because it writes unnecessary data to the database and increases run time.

teacher = create(:teacher)
course1 = create(:course, name: 'Math', teacher: teacher)
course2 = create(:course, name: 'Science', teacher: teacher)
course3 = create(:course, name: 'History', teacher: teacher)
course4 = create(:course, name: 'Quantum Physics', teacher: teacher)

becomes

teacher = create(:teacher)
create(:course, name: 'Science', teacher: teacher)

Again, we check to make sure the test still passes and commit.

Abstract clunky code to methods to increase readability

Anthony is always pushing me to write code so that it performs like it reads. Doing so ensures readability for myself and other developers, and forces us to make sure our objects and methods execute the intentions indicated by their name.

When Anthony isn’t around for conversations, I find pseudocoding helps organize my intentions:

# I want a method that:
#  fills out all attributes within my assignment form
#  selects a course from a dropdown list
#  fills in text fields with the appropriate attributes
#  selects dates for the appropriate attributes
#  submits my form
#  is readable and intention-revealing

The ugliest part of this test (in my opinion) is the way the date fields are selected. It takes 3 lines of code for each date because the form has a separate select for each Month, Day and Year. We can DRY (Don’t Repeat Yourself) this up by creating a method that will make these selections for us.

First, we write the method call:

select_date(:assignment, :assigned_on, 'January 15, 2014')
select_date(:assignment, :due_on, 'January 17, 2014')

When using form_for, form fields are all prefixed with the object they belong to (in this case, :assignment), so we pass that first. Second, we pass the form field we want to select. Third, we pass the date in a string.

Now we write the method:

def select_date(prefix, field, date)
  parsed_date = Date.parse(date)
  select parsed_date.year, from: :"#{ prefix }_#{ field }_1i"
  select parsed_date.strftime('%B'), from: :"#{ prefix }_#{ field }_2i"
  select parsed_date.day, from: :"#{ prefix }_#{ field }_3i"
end

To make extracting the Month, Day and Year from our string much easier, we convert them to a Date object and interpolate the form attributes using the prefix and field arguments.

The test is green, so we commit.

Extract parsing of Dates

We don’t love the local variable for parsing our date and there is an argument order dependency as well. So we extract the parsing of dates to local variables at the top of the test. We aren’t exactly sure what to do about the argument order dependency at this point, and assume this may be an issue with the next form field as well, so we put off that refactor for now.

assigned_on = Date.parse('January 15, 2014')
due_on = Date.parse('January 17, 2014')
...

select_date(:assignment, :assigned_on, assigned_on)
select_date(:assignment, :due_on, due_on)
...

def select_date(prefix, field, date)
  select date.year, from: :"#{ prefix }_#{ field }_1i"
  select date.strftime('%B'), from: :"#{ prefix }_#{ field }_2i"
  select date.day, from: :"#{ prefix }_#{ field }_3i"
end

We feel good about this refactor. Our code is still readable and introduction of the Date object will allow us to put the date in whatever format we like and still achieve the same result.

The test is green, so we commit.

Find similarities in your code

We have 3 text_field attributes being filled the exact same way. Following what we did with select_date, we can write a method that will fill in the text_field’s and will DRY up this duplication.

Again, we write the method call so that it reads as the code performs:

fill_in_text_field(:assignment, :name, 'Pop Quiz')
fill_in_text_field(:assignment, :description, 'I hope you studied!')
fill_in_text_field(:assignment, :points_possible, 100)

This isn’t much of an improvement. While we may have decreased a little bit of ‘noise’ and increased the legibility, we are accomplishing our task in the same number of lines and it is still repetitive. Stay tuned, we’re going somewhere with this.

def fill_in_text_field(prefix, field, value)
  fill_in "#{ prefix }_#{ field }", with: value
end

We are getting less out of this refactor than the last. We still have argument order dependencies and the code’s readability is much the same. However, notice the pattern forming between all the different form methods…

Our test is green, so we commit.

Be patient, go step-by-step

We have a lot of duplication. We are calling the methods select_date and fill_in_text_field multiple times each. We need to find a way (perhaps an object or method) to pass each form field type multiple arguments and iterate over them.

However, we need to make sure that all the form fields are essentially using the same format before we try to wrap them. We need to create a method for selecting our course. Write the method call:

select_from_dropdown(:assignment, :course_id, 'Science')

This may look a bit funny, selecting a course from a drop-down list with a field identifier of :course_id, but passing it the string 'Science' instead of an id. This is due to a little bit of form_for magic. When courses are created, each receives an id when persisted to the database. In our form, we want to be able to select courses that belong to a specific teacher. form_for allows us to display the names of the courses in the drop-down list, but once selected and submitted, the form actually sends the course_id that is required for our Assignment belongs_to :course association.

The method:

def select_from_dropdown(prefix, field, value)
  select value, from: :"#{ prefix }_#{ field }"
end

Now we can really see a pattern forming. Test is green, commit.

Abstract identical arguments using yield and wrapping method calls

The next refactor is a very small but integral step in making these other refactors worth while. What good are the select_from_dropdown, select_date and fill_in_text_field if we can’t use them every time we need to fill in another form?

In each of these method calls, we are passing a ‘prefix’ (in this case it is :assignment) which will always be present no matter what form you are filling out for a particular object. We can abstract this away by wrapping all of these method calls in another method that simply yields the prefix. We’ll call this method within_form(prefix, &block):

def within_form(prefix, &block)
  yield prefix
end

Update the method calls to fill in our form:

within_form(:assignment) do |prefix|
  select_from_dropdown(prefix, :course_id, 'Science')
  fill_in_text_field(prefix, :name, 'Pop Quiz')
  fill_in_text_field(prefix, :description, 'I hope you studied!')
  select_date(prefix, :assigned_on, assigned_on )
  select_date(prefix, :due_on, due_on )
  fill_in_text_field(prefix, :points_possible, 100)
end

All we are doing here is abstracting the object for the form into an argument, and supplying that argument to each method call with yeild.

But what if instead of yeilding our prefix, we were to yield an object back that understood the methods select_from_dropdown, select_date and fill_in_text_field? If that object understood our prefix, and these methods, we could use within_form for any object we need to fill in a form for.

Our test is green, so we commit.

When applicable, create a new object to handle a single responsibility

This next refactor has a lot of moving pieces. We want to create an object responsible for filling out all form fields. As always, write the method call and describe what you want it to perform:

within_form(:assignment) do |f|
  f.select_from_dropdown(course_id: 'Science')
  f.fill_in_text_field(name: 'Pop Quiz')
  f.fill_in_text_field(description: 'I hope you studied!')
  f.fill_in_text_field(points_possible: 100)
  f.select_date(assigned_on: assigned_on)
  f.select_date(due_on: due_on)
end

In order for within_form to perform properly we must update it to yield an object that understands each method responsible for filling out form fields.

def within_form(form_prefix, &block)
  completion_helper = FormCompletionHelper.new(form_prefix, self)
  yield completion_helper
end

By creating the FormCompletionHelper object, we have a place to put the select_from_dropdown, select_date and fill_in_text_field methods.

Each time within_form is called, a new instance of FormCompletionHelper is yielded. We call our form methods, and pass along the field and value arguments that each method requires:

class FormCompletionHelper
  delegate :select, :fill_in, to: :context

  def initialize(prefix, context)
    @prefix = prefix
    @context = context
  end

  def fill_in_text_field(field, value)
    fill_in :"#{ prefix }_#{ field }", with: value
  end

  def select_date(field, date)
    select date.year, from: :"#{ prefix }_#{ field }_1i"
    select date.strftime('%B'), from: :"#{ prefix }_#{ field }_2i"
    select date.day, from: :"#{ prefix }_#{ field }_3i"
  end

  def select_from_dropdown(field, value)
    select value, from: :"#{ prefix }_#{ field }"
  end

  private

  attr_reader :prefix, :context
end

This was a big refactor. By wrapping the methods select_from_dropdown, select_date and fill_in_text_field within the FormCompletionHelper class, their scope changes and they no longer have access to Capybara’s select and fill_in methods. In order to call these methods from FormCompletionHelper, we delegate to the test context (hence, choosing context for the name of this object). We do this by passing self as an argument to the within_form method and we delegate with the code:

delegate :select, :fill_in, to: :context

We also are able to remove prefix as an argument from each of our methods by defining a getter method for prefix:

attr_reader :prefix, :context

Our test is green, so we commit.

Remove duplication, through iteration

We are calling fill_in_text_field 3 times, select_date twice, and the click_button action that submits our form is reliant on ‘Assignment’ being passed as a string.

Let’s address the duplication:

within_form(:assignment) do |f|
  f.select_from_dropdown(course_id: 'Science')
  f.fill_in_text_fields(
    name: 'Pop Quiz',
    description: 'I hope you studied!',
    points_possible: 100
  )
  f.select_dates(
    assigned_on: assigned_on
    due_on: due_on,
  )
end
click_button I18n.t('helpers.submit.create', model: 'Assignment')

Notice that instead of passing multiple arguments, we now pass key: value pairs.

Now, we must adjust our methods to allow one or more fields:

def fill_in_text_field(options)
  options.each do |field, value|
    fill_in :"#{ prefix }_#{ field }", with: value
  end
end
alias :fill_in_text_fields :fill_in_text_field

def select_date(options)
  options.each do |field, date|
    select date.year, from: :"#{ prefix }_#{ field }_1i"
    select date.strftime('%B'), from: :"#{ prefix}_#{ field }_2i"
    select date.day, from: :"#{ prefix }_#{ field }_3i"
  end
end
alias :select_dates :select_date

def select_from_dropdown(options)
  options.each do |field, value|
    select value, from: :"#{ prefix }_#{ field }"
  end
end
alias :select_from_dropdowns :select_from_dropdown

In addition to adding iteration to each of these methods, we also create an alias for each method to allow singular or plural method calls.

alias :select_dates :select_date

The test is green, commit.

Complete abstractions

We know that in the context of a database backed object, form submit actions are only used to create or update the object. To make this submission dynamic we need to assign the model and stipulate whether the action is a create or update.

The method call as we want to see it perform:

def within_form(:assignments) do |f|
...
  f.submit(:create)
end

Implement #submit in FormCompletionHelper:

delegate :select, :fill_in, :click_button, to: :context
...
def submit(create_or_update)
  raise InvalidArgumentException unless [:create, :update].include?(create_or_update.to_sym)
  click_button I18n.t("helpers.submit.#{ create_or_update }", model: model_name)
end

private

def model_name
  prefix.to_s.capitalize
end

This refactor completes our ability to dynamically fill out forms. By abstracting the submit action to the FormCompletionHelper we are able to assign the model_name using our form_prefix. We also include an InvalidArgumentException to allow :create or :update arguments only.

Our test is green, so we commit.

Encapsulate behavior and keep code clean and organized through namespacing

Now that we’ve fully abstracted form completion, it doesn’t make much sense to leave #within_form or FormCompletionHelper in our spec/features/teacher/adding_an_assignment_spec.rb. We can move them to separate files, wrap them in a module, and include them in our RSpec configuration so that our teacher/adding_an_assignment_spec.rb will have access to them. A nice by-product of doing this is that any other feature specs that require a form to be filled out can now use the within_form method.

We move our FormCompletionHelper class to a new file called form_completion_helper.rb. The functionality that this class offers is only going to be used in feature spec files, so we place the file in the spec/support/features/ directory. We also namespace the class by wrapping it in a Features module.

# spec/support/features/form_completion_helper.rb

module Features
  class FormCompletionHelper
    delegate :select, :fill_in, :click_button, to: :context

    def initialize(prefix, context)
      @prefix = prefix
      @context = context
    end

    def fill_in_text_field(options)
      options.each do |field, value|
        fill_in :"#{ prefix }_#{ field }", with: value
      end
    end
    alias :fill_in_text_fields :fill_in_text_field

    def select_date(options)
      options.each do |field, date|
        select date.year, from: :"#{ prefix }_#{ field }_1i"
        select date.strftime('%B'), from: :"#{ prefix }_#{ field }_2i"
        select date.day, from: :"#{ prefix }_#{ field }_3i"
      end
    end
    alias :select_dates :select_date

    def select_from_dropdown(options)
      options.each do |field, value|
        select value, from: :"#{ prefix }_#{ field }"
      end
    end
    alias :select_from_dropdowns :select_from_dropdown

    def submit(create_or_update)
      raise InvalidArgumentException unless [:create, :update].include?(create_or_update.to_sym)
      click_button I18n.t("helpers.submit.#{create_or_update}", model: model_name)
    end

    private

    def model_name
      prefix.to_s.capitalize
    end

    attr_reader :prefix, :context
  end
end

We also created a form_helpers.rb file for our #within_form helper method. We also namespace this method in the Features and FormHelpers modules.

# spec/support/features/form_helpers.rb

module Features
  module FormHelpers
    def within_form(form_prefix, &block)
      completion_helper = FormCompletionHelper.new(form_prefix, self)
      yield completion_helper
    end
  end
end

The last step is to require these modules in /spec/spec_helper.rb.

RSpec.configure do |config|
  config.include Features
  config.include Features::FormHelpers
end

Our test is green, so we commit.

We’re done.

Next time, I might use the Formulaic gem. However, I find that exercises like this really help me understand the process of writing quality code.

What’s next?

If you found this post helpful, check out our refactoring screencast on Learn.

Also, check out this blog to take your test refactoring to the next level using I18n.

Our Problem with Boxen

Posted 5 months back at blah blah woof woof articles

Over a year ago, we started using Boxen at Icelab to manage our team’s development environments. It’s worked as advertised, but not well enough. I’m looking for something else.

Our problem with Boxen is that it contains hundreds of different components, all of which are changing, all the time. It needs constant tending. By the time a team is big enough to need something like Boxen, it’s paradoxically too small to look after it properly: to have someone whose job it is to be “Boxenmaster,” someone who knows how these intricate parts all interact and can run the regular clean installs needed to make sure that the experience is smooth for new people (we’ve found it typical for a functional Boxen setup to stay working over repeated updates, while clean installs end up failing). We need a tool that we can set up once for a project and then have it still work reliably 6 months later when we revisit the project for further work.

Boxen can be a trojan horse. If you don’t look after it properly, you risk creating two classes of developers within your team: those who were around to get Boxen working when you first rolled it out, now enjoying their nice functional development environments, and those who get started later, whose first experience in the team is one of frustration, non-productivity and a disheartening, unapproachable web of interconnected packages. And no one is safe: as soon as you want to upgrade that version of PHP, you could slip down there too.

So while Boxen can indeed work as manager of personal development environments, and while Puppet is a serious and capable configuration manager, my recommendation is not to commit to Boxen half-heartedly. In fact, you may not even need something so rigorous and complex if your team is still small. I’m looking into such alternatives right now. I’m not settled on anything yet, but it’ll likely involve virtual machines, and perhaps use Docker as a way to keep it lightweight while working on multiple projects at a time. Fig seems like it could be a good fit. I’ll keep you posted.

Episode #465 - May 16th, 2014

Posted 5 months back at Ruby5

A rich text editor that isn't awful, over one thousand free programming books, handle email subscriptions and track emails sent, super easy email unsubscribe, and a cheatsheet for OAuth exploits.

Listen to this episode on Ruby5

Sponsored by New Relic

New Relic is _the_ all-in-one web performance analytics product. It lets you manage and monitor web application performance, from the browser down to the line of code. With Real User Monitoring, New Relic users can see browser response times by geographical location of the user, or by browser type.
This episode is sponsored by New Relic

Quill

Quill is a modern rich text editor built for compatibility and extensibility. It was created by Jason Chen and Byron Milligan and open sourced by Salesforce.com.
Quill

Free Programming Books

A compilation of roughly 1,500 links to free programming-related resources.
Free Programming Books

OAuth Security Cheatsheet

This site describes common OAuth/Single Sign On/OpenID-related vulnerabilities.
OAuth Security Cheatsheet

Ahoy Email

Simple, powerful email tracking for Rails
Ahoy Email

Mailkick

Email subscriptions made easy
Mailkick

What to do when Stack Overflow is down?

Posted 5 months back at mir.aculo.us - Home

The Internet is awesome. Information at your fingertips and always-available help from people all over the world is one of humanity’s dreams come true. I’m not sure if the ancient philosophers included copy & pasting of code snippets in this dream, but it’s a fact of daily developer life.

It’s awesome, and it’s very convenient.

But this is not how you learn and become great at thinking for yourself, finding solutions for solving programming problems and most importantly how to be creative. Over-using sites like Stack Overflow will not make you a better developer, it will (probably) make you very good at clicking up-vote buttons and copy & pasting.

You owe it to your brain and future self that you try to find a solution first, and not give up just because something doesn’t work the first time you try it. Especially when you don’t feel comfortable or knowledgeable, because you’re working on a new project, with a new programming language or different development environment. Humans are built for exploration and understanding by doing. Your brain will reward you for discovering things. The rewards are higher as the problem is harder (for you) to solve.

That doesn’t mean to ban forums and answer sites from your bookmarks. You can and should share your discoveries and see how others solved similar problems. You’ll probably find that there’s (hope my cats won’t hear this) more than one way to skin a cat. Sharing will likely lead to new, better ways to tackle a specific problem, and this will benefit lots of people.

All because you spent 10 minutes thinking about a problem and not just copy & pasting the first answer that somewhat works.

Software Apprenticeship Podcast Episode 3 is Out

Posted 5 months back at Jake Scruggs

This week we start off by throwing Jonathan into the deep end of pool where he pairs with an experienced developer on a 10 year old Java project that is the core of our signature product: Backstop.  Of course the company is called Backstop Solutions and so, in order to avoid confusion, we gave the project a different name for internal use:  Fund Butter.  The mystery of how such a terrible thing came to pass is revealed in this very episode.

There’s no way we couldn’t discuss DHH’s Rails Conf declaration and blog post: “TDD is dead. Long live testing.” This, of course, leads to a discussion of our team’s test philosophy.

You can find it on iTunes (search for Software Apprenticeship Podcast), any podcast app’s search function, Google, this temp page: https://itunes.apple.com/us/podcast/software-apprenticeship-podcast/id868371146 or use the RSS feed directly if your into that sort of thing: http://softwareapprenticeship.libsyn.com/rss



Our panel (composed of Toby Tripp, Matt Pyra, Eric Johnson, Jonathan Howden, and I) meander through quite a few topics.  Here’s a breakdown by time of the various topics:

01:27 Backstop’s 2 day bug bash
02:00 The apprentice has to tackle a 10 year old Java program
06:22 “Everything needs to have an ID if you’re going to make it Hibernate-y” - Jake “super technical” Scruggs
08:21 Why we call Backstop “Fund Butter” within the company
10:50 The apprentice encounters Selenium
12:42 Troubles with regression/integration testing through the web browser.
13:43 “Unit Testing is Dead” - DHH 
20:00 Pairing all the time vs code review
21:51 Toby talks about the Hill Air Force Base pair programming study mentioned here: http://www.informit.com/articles/article.aspx?p=29410
26:40 The Wall of Awesome - Backstop’s way for employee’s to recognize and thank other employees
47:21 The anti-college movement
49:36 The “Expose your ignorance” apprenticeship pattern with examples/confessions from Jonathan, Jake, and Toby
51:14 The C3 project comes up with near 100% frequency when >= 2 die hard XP'ers are in the same room.

Episode #464 - May 13th, 2014

Posted 5 months back at Ruby5

In this episode we talk about new Ruby releases for versions 2.1.2 and 2.0.0-p48, Jekyll 2.0, Ruby core team disputing a CVE report, How Batched Queries work in Rails and FiniteMachine.

Listen to this episode on Ruby5

Sponsored by RailsLTS

With the release of Rails 4, support for Rails 2.3 and Rails 3.0 has ended. Security vulnerabilities are no longer patched for these versions. Rails LTS offers a solution for mission critical applications by providing security patches for old versions of Rails.
This episode is sponsored by RailsLTS

Ruby 2.1.2 and 2.0.0-p481

Late last week Ruby 2.1.2 was released alongside Ruby 2.0.0­-p481. Version 2.1.2 notably fixes a regression on the Hash#reject method.
Ruby 2.1.2 and 2.0.0-p481

Jekyll 2.0

Jekyll, the popular static site generator, released its 2.0 version last week. This new version is jam­-packed with highly­-requested features and bug fixes, thanks to the contribution of over 180 different developers.
Jekyll 2.0

Ruby CVE dispute

The Ruby core team is disputing an earlier CVE report. The CVE in question claimed that it was possible for an attacker to forge arbitrary root certificates by modifying the certificate’s signature. Apparently it’s simply a misunderstanding over the return value of the X509Certificate#verify method.
Ruby CVE dispute

How Batched Queries Work

Adam Sanderson wrote another article in his "Reading Rails" series titled 'How do Batched Queries Work', where he investigates Rails' find_each. The 'find_each' method is used to run queries when you don't want all the records instantiated at once.
How Batched Queries Work

FiniteMachine

FiniteMachine is a gem by Piotr Murach that provides a minimal finite state machine with a straightforward and intuitive syntax. The machine is event driven, with a focus on passing synchronous and asynchronous messages to trigger state transitions. It supports a natural DSL for declaring events, exceptions and callbacks.
FiniteMachine