Pivotal Labs

Main menu

Skip to primary content
Skip to secondary content
  • About
  • Case Studies
  • Team
    • Executives
    • Locations
      • San Francisco (HQ)
      • Boston
      • Boulder
      • Denver
      • London
      • Los Angeles
      • New York
  • Community
    • Blogs
    • Tech Talks
    • Events
  • Careers
    • Lifestyle
    • Principles & Practices
    • Benefits
    • FAQ
    • Apply
  • Contact
    • Press Room
    • Press Releases
    • In The News
    • Press Kit
  • All
  • Labs
  • Standup
  • Tracker
Jonathan Berger

How to write Well-Formed User Stories

Jonathan Berger
Sunday, October 7, 2012

Writing Well-Formed User Stories

Convention Over Configuration is one of core principles of the Rails approach to software development, and delivers enormous value.

Convention Over Configuration – means that Rails makes assumptions about what you want to do and how you’re going to do it, rather than requiring you to specify every little thing…

Oddly, we tend not to apply the same perspective to project planning: on almost every project, the team re-invents the wheel of “how should we write and format our stories?”. I’ve worked closely with the Product team on about a dozen projects in the past few years, and rigorous story-writing is one of the most common areas for low-cost, high-gain improvement. I encourage every team to adopt (or at least consider) these techniques.

  1. Write every story in Gherkin. I don’t care whether or not you use cucumber: use Gherkin. Which is to say, every story should be in “Given / When / Then” form. This is the cheapest and easiest way to apply Convention Over Configuration to your user stories, and can have a HUGE benefit for your team.
    Scenario: User adds item to cart
      Given I'm a logged-in User
      When I go to the Item page
      And I click "Add item to cart"
      Then the quantity of items in my cart should go up
      And my subtotal should increment
      And the warehouse inventory should decrement
    
  2. Every feature story should include an “As a / I want to / Because…” block, which illustrates the motivation behind a story. Compelling the product team to specify the motivation behind a story help illuminate what exactly the requirement is, as well as providing guidance to the developers. Some people prefer “So That…” instead of “Because“, but in most cases “Because” helps drive out motivation—the Final Cause—whereas “So that” may only drive out the Effective Cause, which is less useful for understanding the story. (Thanks to Sam Coward for this insight.)
    Feature: Shopping Cart
      As a Shopper
      I want to put items in my shopping cart
      Because I want to manage items before I check out
    
  3. Every story title should include the word “should”. NEVER use the word “can”, which camouflages desired behavior. E.g. It’s unclear whether the story “User can delete comment” is a feature or a bug. “User should be able to delete comment” or “User should not be able to delete comment” are much clearer: the former is a feature, the latter a bug. Don’t make me guess.

When a story feels a little fishy, check that these bases are covered. If any are missing, fix then before you do anything else. The answer will often be driven out in the process of working the story into Well Formed shape.

Benefits

Well Formed stories truly drive out the feature from the user’s perspective; this catches 80% of weird edge cases while the whole team is together, in context, and in planning mode, instead of having to interrupt-drive the PM. Well Formed stories make it impossible to camouflage large stories as small stories by elision. Because the story has to be written out step-by-step, all the complexity might otherwise be hidden is forced out into the open. And when you find yourself with conditionals or switches? That’s a new scenario! Now all stories are forced into roughly the same size. Another side-effect is that once one story ~= one scenario, the amount of work to be done can be roughly gauged spatially, by looking at how much of your wall is covered by index cards. For bonus points, use the story title as your git commit, e.g. the story “User should be able to recommend a product” becomes the git commit “User is able to recommend a product”, and your git log tells the narrative of your project.

How did this start?

Once apon a time, J (the anchor) made N (a very bright, technical Product Manager) write stories in Gherkin. Most stories weren’t 100% ready to be pasted into cucumber, but it usually didn’t take too much work to get them there. The team would discuss in IPM, and then devs could copy-and-paste stories right into Cucumber. This doesn’t work for every PM, but even in the worst case, teams with less than tech-savvy PMs see real benefits from writing their stories at the right level of granularity. Once I was exposed to a team where we wrote Gherkin all the time, anything else felt like broken process.

UPDATE: To be clear, the opinions in this article are my own, and do not reflect anything close to consensus or standard practice on the part of Pivotal. Some Pivots will agree with this position, while many others will not.

UPDATE 3/17: Added a brief introduction elaborating on how Well-Formed Stories help bring principles of Convention Over Configuration to story-writing.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Ken Mayer

From customer requirements to releasable gem

Ken Mayer
Sunday, May 13, 2012

One of the many pleasures of working at Pivotal Labs is that we are encouraged to release some of our work as open source. Often during the course of our engagements, we write code that might have wide-spread use. Due to the nature of our contracts, we can not unilaterally release such code. Those rights belong to the client. And rightly so. So, it is an even greater pleasure when one of our clients believes in “giving back” to the community, as well.

One such example is this modest gem, attribute_access_controllable which allows you to set read-only access at the attribute level, on a per-instance basis. For example, let’s say that you have a model Person with an attribute birthday, which, for security purposes, cannot be changed once this attribute is set (except, perhaps, by an administrator with extraordinary privileges). Any future attempts to change this attribute will result in a validation error.

e.g.

> alice = Person.new(:birthday => '12/12/12')
=> #<Person id: nil, attr1: nil, created_at: nil, updated_at: nil, read_only_attributes: nil, birthday: "0012-12-12">
> alice.attr_read_only(:birthday)
=> #<Set: {"birthday"}>
> alice.save!
=> true
> alice.birthday = "2012-12-12"
=> "2012-12-12"
> alice.save!
ActiveRecord::RecordInvalid: Validation failed: Birthday is invalid, Birthday is read_only
> alice.save!(:skip_read_only => true)
=> true

Setting this up is trivial, thanks to a Rails generator which does most of the heavy lifting for you.

rails generate attribute_access Person

After that, you need only know about one new method added to your class:

#attr_read_only(*attributes) # Marks attributes as read-only

There are a few others, but this one, plus the new functionality added to #save and #save! will get you quite far.

And if that’s all that you were looking for when you stumbled across this article, then there’s no need to read any further. Go install the gem and have fun (and may your tests be green when you expect them to be).

From customer requirements to releasable gem

On the other hand, if you are interested in how we got from the original customer story to a releasable open sourced gem, read on. The source code for the module is a mere 34 lines long. It implements 2 new methods, a validator and (gently) overrides #save and #save!. Being good Test Driven Developers, we wrote our specs first, and since we wanted this behavior to be included in several models, we wrote our specs as a shared behavior as well. The spec clocks in at 44 lines, slightly longer than our implementation. All in all, tiny. The whole commit was less than 100 lines of code.

AttributeAccessControllable
  it should behave like it has AttributeAccessControllable
    #attr_read_only(:attribute, ...) marks an attribute as read-only
    #read_only_attribute?(:attribute) returns true when marked read-only
    #read_only_attribute?(:attribute) returns false when not marked read-only (or not marked at all)
    #save! raises error when :attribute is read-only
    #save!(:context => :skip_read_only) is okay
    #save is invalid when :attribute is read-only
    #save(:context => :skip_read_only) is okay

In order to get to something “releasable” we needed a few more things, which we put on our To-Do list:

To do

  1. MIT License
  2. A gem specification
  3. Basic documentation in a README file

The list got longer as we fleshed out both the documentation and the integration tests, as you’ll see in a moment, but first, let’s talk about

Getting the legal issues resolved

Pivotal’s open sourcing policy is straightforward and simple to execute; We don’t touch it. We write code for our clients, it’s their code to do with as they please. My particular client liked the work we did for them and thought it would make a great open source gem. The Director of Engineering signed off on the idea and I paired with him to create the github repository during a lunch break. The first commit was tiny, just a basic directory structure and the existing code. I don’t think the tests passed because they lacked a proper RSpec infrastructure.

Creating the gem

bundler gem DIRECTORY

is your best friend. It set up the layout for us, including an MIT License and a gem specification. It had a boilerplate README, too.

Writing the documentation for the code you wished you had

Next, we wrote a draft of the README file which documented what we knew: You needed a migration to create a column called :read_only_attributes and you needed to include the module into the class. Then we started thinking about the pain points of using our code as is. Wouldn’t it be nice if we could create the migration automatically? Rails generators do that sort of thing, how hard could it be? (Famous last words…) It became clear that we needed to test drive out some new features of the gem that supported the actual module.

To do

  1. MIT License
  2. A gem specification
  3. Basic documentation in a README file
  4. Integration test

I am not a big cucumber fan, but…

Really, I’m not. I used to write Cucumber features all the time, but nowadays, I use a combination of RSpec and Capybara to get most of my day-to-day integration testing done. There is, however, one sweet spot for Cucumber that I’m finding more and more useful; A very high-level document that describes essential features in a way that a reader will say, “Ahhh, so that is how it is supposed to work!” Here’s a copy of the spec I wrote:

Feature: Read only attributes

Scenario: In a simple rails application
  Given a new rails application
  And I generate a new migration for the class "Person"
  And I generate an attribute access migration for the class "Person"
  And I have a test that exercises read-only
  When I run `rake spec`
  Then the output should contain "7 examples, 0 failures"

You probably won’t find any web-steps out there to handle these lines. I use Aruba to handle the dirty work of executing shell commands in a safe sandbox-y way. The step definition file hides most of the ugliness. Even so, most readers could figure out what to do, by hand, for each step.

To do

  1. MIT License
  2. A gem specification
  3. Basic documentation in a README file
  4. Integration test
  5. Generator

Big generators

This gem was my first attempt at writing a generator, so it was awkward. I still don’t understand Thor properly. Fortunately, I happened upon Ammeter, which helped me write out test specs for the generator. If you’ve got good specs, then you can sometimes stumble along until you learn enough to get it right. Alex Rothenberg’s original blog post about the gem was quite informative, as were the test cases from the Devise gem.

I have to admit; constructing the generator was more complex than the original module! There are more “moving parts;” templates, usage files, specs, in addition to the generator itself. So there is a certain amount of overhead that might overwhelm the original content. On the other hand, I learned quite a bit, and the gem is far more useful.

require "spec_helper"
require 'generators/attribute_access/attribute_access_generator'

describe AttributeAccessGenerator do
  before do
    prepare_destination
    Rails::Generators.options[:rails][:orm] = :active_record
  end

  describe "the migration" do
    before { run_generator %w(Person) }
    subject { migration_file('db/migrate/create_people.rb') }
    it { should exist }
    it { should be_a_migration }
    it { should contain 'class CreatePeople < ActiveRecord::Migration' }
    it { should contain 'create_table :people do |t|'}
    it { should contain 't.text :read_only_attributes'}
  end

  describe "the class" do
    before { run_generator %w(Person) }
    subject { file('app/models/person.rb') }
    it { should exist }
    it { should contain 'include AttributeAccessControllable' }
  end

Some interesting things to note; you must require the generator, since it is not pulled in by default. The subject of each suite is a file, not the class AttributeAccessGenerator. The migration_file helper prepends the TIMESTAMP onto the migration file for you. If you need to set up more things for your test, destination_root is a helper with a path to the temporary directory. It remains after the tests have run, which makes it useful when debugging.

Here’s something else that I did not know, but it might help new generator writers; the order in which you define your methods in the generator class is significant. I don’t know how this is done, but each “method” in the generator class is executed in turn. This is important for my generator; the model class definition must exist before I inject the new content that mixes in the module, so I had to write the generate_model method before the inject_attribute_access_content method. I was scratching my head over that one for quite awhile.

require "rails/generators/active_record"

class AttributeAccessGenerator < ActiveRecord::Generators::Base
  source_root File.expand_path('../templates', __FILE__)

  def create_migration_file
    if (behavior == :invoke && model_exists?)
      migration_template "migration.rb", "db/migrate/add_read_only_attributes_to_#{table_name}"
    else
      migration_template "migration_create.rb", "db/migrate/create_#{table_name}"
    end
  end

  def generate_model
    invoke "active_record:model", [name], :migration => false unless model_exists? && behavior == :invoke
  end

  def inject_attribute_access_content
    class_path = class_name.to_s.split('::')

    indent_depth = class_path.size
    content = "  " * indent_depth + 'include AttributeAccessControllable' + "n"

    inject_into_class(model_path, class_path.last, content)
  end

To do

  1. MIT License
  2. A gem specification
  3. Basic documentation in a README file
  4. Integration test
  5. Generator
  6. Shareable tests

Yo, I hear you like tests in your tests

Lastly, we want to share the testing love. The gem consumer should not have to write tests to drive out the same feature that we have already tested. That would not be very DRY. So, in order to make our shared behavior, er, um, shareable, we moved it into lib with a few wrappers, namely, the spec_support.rb file, which you can include in your own spec files to test drive adding the module to your own classes.

Which is where And I have a test that exercises read-only comes in. You can see this in the steps.rb file:

require 'spec_helper'
require 'attribute_access_controllable/spec_support'

describe Person do
  it_should_behave_like "it has AttributeAccessControllable", :attr1
end

To do

  1. MIT License
  2. A gem specification
  3. Basic documentation in a README file
  4. Integration test
  5. Generator
  6. Shareable tests

Don’t be afraid to release v1.0.0

I am a strong believer in semantic versioning. I simply can not understand why some core ruby tools are still living in version zero land, even after years and years of development and use. So, after a couple of internal commits, we released v1.0.0 of the gem, and less than a day later released v1.1.0 and then v1.1.1! (You probably shouldn’t use anything less than v1.1.1)

An interesting mix

In summary, we used a lot of tools and techniques to go from a simple commit to a shareable gem:

  • Rails generators
  • Cucumber
  • Aruba
  • Ammeter
  • RSpec shared behaviors
  • Integration tests
  • Generator tests
  • Module tests

I encourage everyone to release as much of their work as possible because it raises the state of the art for us all. There are limits, of course, but that still affords lots of wiggle room. Small gems like attribute_access_controllable won’t change the world, but they ease the pain of staying DRY and we all get to learn a little something.

Thanks

To Social Chorus for choosing to open source this code. And to Pivotal Labs for encouraging a better way to do software engineering.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Pivotal Labs

Interacting with popup windows in Cucumber/Selenium

Pivotal Labs
Monday, October 24, 2011

OAuth providers like LinkedIn often pop-up in a new browser window rather than in Javascript so that the user entering their credentials can see the location bar to be sure they are not being phished by the website requesting their credentials. This is great for security, but not so great for Cucumber testing.

features/signup.feature

Scenario: Sign Up with LinkedIn
  When I go to the home page
  And I follow "Sign Up"
  And I grant LinkedIn access
  Then I should be on the new user page

My application has a hyperlink that opens the OAuth login on the OAuth provider’s website in a new window. Let’s presume the simple matter of wiring this up is already coded in my view.

Testing this with Cucumber requires telling the Selenium web driver to interact with the new popup window. We can do this using page.driver.browser.window_handles to find the newest window handle and scoping out actions to that window.

features/support/signup_steps.rb

When /^I grant LinkedIn access$/ do
  begin
    main, popup = page.driver.browser.window_handles
    within_window(popup) do
      fill_in("Email", :with => "newlee@pivotallabs.com")
      fill_in("Password", :with => "password")
      click_on("Ok, I'll Allow It")
    end
  rescue
  end
end

And that’s it!

Keep in mind that if you use this test as-is, you will be hitting LinkedIn on the real Internet. This is great if you want a test that will always verify the real API, but not so good for CI, since it is Internet connection-dependent and slow. Consider using something like VCR or Artifice to stub out your service calls.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Ken Mayer

[Standup][sf] 2011-05-16 Too much cowbell

Ken Mayer
Monday, May 16, 2011

Needful Things; Help

  • How to test command line applications? Use the old stand-by, expect, patch into the highline library, or the new hotness, aruba (CLI steps for Cucumber).

Very Interesting Things

  • fbAsyncInit does not fire when Facebook is really ready, only kind of sorta, maybe ready.
  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Mike Gehard

Waiting for jQuery Ajax calls to finish in Cucumber

Mike Gehard
Tuesday, May 3, 2011

You may be asking yourself why you’d want to do this in the first place. Well here’s why I would want to do it.

We had some Webdriver based Cucumber tests that passed fine locally but kept failing on our CI box. Our CI box is a bit underpowered at the moment so I thought what might be happening is that our tests weren’t waiting long enough for the Ajaxy stuff to happen because the Ajax responses were taking a long time.

After some poking around in the source code of jQuery, I found the $.active property. This property keeps track of the number of active Ajax requests that are going on and I thought this might help us out.

What I came up with was this gist:

I added this step right after my Cucumber step that caused the Ajax call so that Cucumber would wait to move on until I knew that everything was done.

This step solved our CI failures and all was good in our test suite again.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Mike Gehard

Testing OmniAuth based login via Cucumber

Mike Gehard
Thursday, March 3, 2011

If you haven’t looked at OmniAuth for authentication with sites like Google, Github and Facebook, then you should take a look. It is pretty killer.

This morning we needed to write a Cucumber scenario to test that a user could log into the system using Google Apps.

We did a quick spike on getting OminAuth integrated, which was a super simple process, and poked around in the browser to make sure it was working OK.

Thanks to Jose Valim for providing some guidance, via the Devise test suite, on how to get this all up and running.

The basics can be found in this Gist:

I put that code in /features/support/omniauth.rb and then all I need to do is label any scenarios that need to deal with login with an @omniauth_test tag and we are all set.

As our features count grows, I could see us doing this before/after all Cucumber scenarios.

Note: You need to be using 0.2.0.beta5 of OmniAuth to get this to work. Earlier versions don’t have the testing functionality built in.

Also Note: This same functionality can be used in good, old RSpec integration tests or Steak tests as well.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Mike Gehard

Using Cucumber/Capybara with SauceLabs SauceOnDemand

Mike Gehard
Wednesday, March 2, 2011

SauceLabs is a cloud based way to test your site against different browsers.

Up until now, they only supported the older Selenium RC based tests.

For those of us using Capybara, we were out of luck because Capybara uses Webdriver.

Well that just changed, they now support Webdriver. Check out the instructions on how to get is set up here.

The one thing that I disagree with in that post is setting the default Capybara driver to :sauce (Capybara.default_driver = :sauce). This seems a little heavy handed to me since I may not want to run all of my scenarios through the Sauce driver.

Upon further review of the source code, it looks like after installing the sauce gem, they redirect any scenarios tagged with @selenium to the Sauce driver. I like this better so if you don’t want to switch over all of your scenarios over to Sauce, you can just ignore the line mentioned above and simply tag the scenarios you want to run on Sauce with @selenium.

I haven’t had a lot of time to play with this but at least it is a start in getting Capybara based Cucumber scenarios to run against Sauce Labs.

My next step is to figure out how to run one Cucumber scenario to run against multiple browsers on Sauce.

Another thing I’d like to figure out how to do is only run Selenium based tests on demand so they don’t run on Sauce every time I run my Cucumber suite. That could run up a decent Sauce bill, especially if you had multiple developers running Cucumber scenarios multiple times a day.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Ken Mayer

Standup 2010-11-16

Ken Mayer
Tuesday, November 16, 2010

Interesting Things

  • Project Sprouts from Luke Bayes “an open-source, cross-platform project generation and configuration tool for ActionScript 2, ActionScript 3, Adobe AIR Flash and Flex projects”

“Project Sprouts was originally designed (as AsProject) to solve a specific set of problems and was later entirely refactored to become a modular set of libraries that are built on top of Ruby, RubyGems and Rake.” — Luke Bayes

  • Sencha Touch 1.0 Ships – Now Free!

“So how will Sencha monetize? The company plans to sell its tools, like Sencha Animator, at a premium. It’ll also offer premium support plans.” — Tech Crunch

Helps

“Does anyone have experience with (slower) performance on EC2 compared to Heroku”

Some suggestions:

  • Test network lag
  • The small instance, the default, is just too wimpy to run as an application server
  • Make sure your database instance is big enough, and has enough memory
  • Any experience with RDS?

“Can you run cucumber with its own database instance?”

Responses:

  • By default, Cuke creates its own environment, but piggy-backs on the test database
...
cucumber:
  <<: *TEST
...
  • rake db:test:prepare is wired to :test and won’t support a :cucumber in the database.yml without extra rake tasks that have continuing maintenance costs
  • I’ve used the parallel_tests gem in the past, which has managed to retrofit db:test:prepare to work with multiple test databases, but it did require an extra step after each migration (and it didn’t play well with postgres text indexes).
  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Mike Gehard

Rails3, Caypbara, Cucumber, FakeWeb…oh my….

Mike Gehard
Thursday, November 4, 2010

While helping client upgrade a Rails 2.3.10 site to Rails 3.0.1, I came across a very perplexing problem with our WebDriver based Cucumber tests that all worked fine under 2.3.10.

We were “randomly” getting some very strange errors from Cucumber having to do with timeout problems and other strangeness like Cucumber not being able to find form fields to fill in.

The solution:
1) require => false for the FakeWeb line in the Gemfile
2) add require ‘fakeweb’ to the top of the test_helper.rb file

or optionally scrap FakeWeb for either Artifice or WebMock

It has something to do with FakeWeb inserting it into the HTTP stack strangely even if you tell it to allow non-local HTTP requests. We weren’t seeing it in 2.3.10 because we were using a cucumber environment to run the cucumber tests. Now under 3.0.1 we run the cucumber tests in the test environment.

I wish I had some more details but I was just happy to move past this strangeness so I didn’t really look back.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Mike Gehard

Using Firebug with WebDriver in Capybara/Cucumber

Mike Gehard
Tuesday, September 21, 2010

Ever wanted to be able to debug an HTML page using the power of Firebug while running Cucumber/Capybara features/steps?

Follow these simple steps and you can get it to work:

1) Create a new “WebDriver” Firefox profile using the instructions found here

2) Fire up Firefox using the newly created profile and install/configure Firebug the way you want it. See instructions above.

3) Run your Cucumber/Capybara steps and pause the feature using a sleep() statement long enough for you to poke around in the page with Firebug.

**Note this has been proven to work on OS X, your mileage on other OS’s may be limited.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter

Topics

  • agile (781)
  • rails (113)
  • testing (88)
  • ruby (83)
  • ruby on rails (70)
  • jobs (62)
  • javascript (55)
  • techtalk (44)
  • rspec (38)
  • ironblogger (32)
  • productivity (30)
  • activerecord (29)
  • gogaruco (29)
  • git (28)
  • nyc (27)
  • rubymine (26)
  • bloggerdome (23)
  • mobile (22)
  • process (21)
  • pivotal tracker (21)
  • cucumber (20)
  • design (19)
  • jasmine (19)
  • ios (18)
  • webos (17)
  • objective-c (17)
  • android (16)
  • tracker ecosystem (16)
  • palm (16)
  • "soft" ware (16)
  • fun (15)
  • ci (15)
  • cedar (15)
  • rails3 (14)
  • performance (14)
  • bdd (14)
  • gem (13)
  • css (13)
  • tdd (13)
  • selenium (12)
  • goruco (12)
  • bundler (12)
  • meetup (11)
  • railsconf (11)
  • nyc-standup (11)
  • capybara (10)
  • mac (10)
  • mojo (10)
  • chef (10)
  • api (10)
Subscribe to cucumber Feed
  1. 1
  2. 2
  3. →
  • About
  • Case Studies
  • Team
  • Community
  • Careers
  • Contact
  • Labs
  • Events

Contact Us

contact@pivotallabs.com
+1 415-77-PIVOT
TwitterLinkedInFacebook

Pivotal Tracker

Tracker is the award-winning agile project management tool that enables real-time collaboration around a shared, prioritized backlog.
Visit pivotaltracker.com >