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
  • Tools
  • Contact
    • Press Room
    • Press Releases
    • In The News
    • Press Kit
  • All
  • Labs
  • Standup
  • Tracker

Specific interfaces – in the small

Stephan Hagemann
Wednesday, March 7, 2012

Everyone on the Web I found who states that quote I was looking for says “I don’t know who said it, but be ‘Generous on input, strict on output’” (or some variation on this). While I am unsure about the first proposition, I wholeheartedly agree with the second.

Edit 3/8: the quote is known in a different wording as Postel’s Law, which shows up as the Robustness Principle in RFC 793, the specification of TCP. Thanks for the hint, Austin!

Unfortunately, the closest a Rubyist typically gets to the implementation of an interface specification is his tests. This provides a pretty good, but somewhat disconnected specification that can sometimes cover up imprecisions in the interface’s implementation.

On top of that, sometimes our frameworks make it easy to forget what our tests are asserting or spec’ing.

Take rspec’s predicate matchers and this example:

require 'rspec/core'

class VeryImportantQuestions
  def self.really?(answer)
    answer == 'Yes. I am telling you.'
  end

  def self.really_really?(answer)
    answer == 'Yes. I am telling you.' ? 42 : nil
  end
end

describe "really?" do
  context "using rspec predicate matchers" do
    context "if someone is telling you" do
      it "should be really really the case and return true" do
        VeryImportantQuestions.really?('Yes. I am telling you.').should be_true
      end
    end
    context "if someone is not sure" do
      it "should return false" do
        VeryImportantQuestions.really?('I am not sure.').should be_false
      end
    end
  end
end

describe "really_really?" do
  context "using rspec predicate matchers" do
    context "if someone is telling you" do
      it "should be really really the case and return true" do
        VeryImportantQuestions.really_really?('Yes. I am telling you.').should be_true
      end
    end
    context "if someone is not sure" do
      it "should return false" do
        VeryImportantQuestions.really_really?('I am not sure.').should be_false
      end
    end
  end
end

be_true and be_false effectively hide the fact that what’s actually spec’ed is truthiness and falsiness. Only when the following context is added is this imprecision revealed:

  context "spec'ing the actual output of the method fails" do
    context "if someone is telling you" do
      it "should be really really the case and return true" do
        VeryImportantQuestions.really_really?('Yes. I am telling you.').should == true
      end
    end
    context "if someone is not sure" do
      it "should return false" do
        VeryImportantQuestions.really_really?('I am not sure.').should == false
      end
    end
  end

With regard to rspec, I suggest to consider twice whether the benefits of using specific matchers to not outweigh their benefits in your situation. You might get nicer test output, but you might lose the ability to immediately tell what you’re spec’ing.

With regard to tests in general: be specific about what you output – aka be specific about what you test.

Here is the gist: https://gist.github.com/1998462

  • 0 Shares
  • Share on Facebook
  • Share on Twitter

5 Comments

  1. Avdi Grimm says:

    Not sure if it changes your argument at all, but both of those RSpec uses are highly un-idiomatic and they’d be flagged in one of our code reviews. They read awkwardly and give RSpec no opportunity to generate meaningful specdoc or failure messages.

    More idiomatic would be ‘should be_really’. This reads a little awkwardly as well, which usually indicates the predicate isn’t quite in line with Ruby conventions. Rename the method to #really_true and you get ‘should be_really_true’, which is both readable and will generate a meaningful message if it fails.

    Of course, they don’t check for a boolean result, but in a somewhat more on-topic note I’m not sure how much utility there is in requiring predicates to return boolean, so long as their truthiness/falsiness is correct.

    March 7, 2012 at 6:08 pm

  2. Adam Milligan says:

    Methods that end with a question mark in Ruby should return a boolean value. This suggests that the method should be free to return **any value** that properly resolves to the expected boolean result.

    At it turns out, in Ruby, 42 resolves to boolean true, and nil resolves to boolean false. Verifying that the method returns those specific values over-specifies the interface; the #be_true and #be_false matchers are more appropriate.

    March 7, 2012 at 6:57 pm

  3. Stephan Hagemann says:

    Thanks for your responses Avdi and Adam!

    As far as the method name goes, Avdi, you’re absolutely right: `really_true?` is better and fits better with how the `be_really_true` matcher would read. I do not understand however how `be_true` is more or less idiomatic (with regard to Ruby) than `be_really_true`.

    Both of you don’t buy my truthiness/falsiness argument – dang – the part I really cared about when writing this.

    Granted, the benefit is small in this example, but saying that a method will “return true” (as above) is something else than saying that it will “return something truthy”. Even if, as is the case in Ruby, [every object has a Boolean value](http://www.skorks.com/2009/09/true-false-and-nil-objects-in-ruby/). That said, “Methods that end with a question mark in Ruby should return a Boolean value.”, since any object has a truthiness value I can thus return anything from such a method? I thought this rule was there to tell me a bit more about what I can expect as a return value form a method… I’d like to read it like “return either the True or the False object”.

    Finally, consider a public API that contains the result of the `really?` method. You might _want to_ do casting into a desired format, but with the lenient interpretation you definitively _have to_. Or can you be sure that the true/false interpretations of objects exist/are the same for any consumer?

    In conclusion, I still don’t think spec’ing `== true` over-specifies it. `be_true` under-specifies it.

    March 7, 2012 at 8:38 pm

  4. Austin Putman says:

    Jon Postel is the quotable person you seek.

    March 8, 2012 at 12:32 am

  5. Stephan Hagemann says:

    Here is a short example that shows why I think question mark methods should return `true` or `false` (the actual objects of the respective class):

    require ‘rspec/core’

    class TheClassThatIsTrueButNeverInTheSameWay
    def initialize(truthiness)
    @truthiness = truthiness
    end

    def truthy?
    @truthiness ? Time.now : false
    end
    end

    describe “the class that is true but never in the same way’s truthy method” do
    context “initialized with false” do
    it “should be falsy” do
    TheClassThatIsTrueButNeverInTheSameWay.new(false).should_not be_truthy
    end
    end

    context “initialized with true” do
    it “should be truthy” do
    TheClassThatIsTrueButNeverInTheSameWay.new(true).should be_truthy
    end

    it “should not be the same truthy for different objects” do
    never_the_same_way_1 = TheClassThatIsTrueButNeverInTheSameWay.new(true)
    never_the_same_way_2 = TheClassThatIsTrueButNeverInTheSameWay.new(true)
    never_the_same_way_1.truthy?.should_not == never_the_same_way_2.truthy?
    end
    end
    end

    March 8, 2012 at 3:52 pm

Add New Comment Cancel reply

Your email address will not be published.

Stephan Hagemann

Stephan Hagemann
Boulder

Recent Posts

  • Getting “by” with rspec feature specs
  • Rails autoloading for your gem [Rails application suites series]
  • Showing and hiding conditional HTML without Javascript
Subscribe to Stephan's Feed

Author Topics

bdd (1)
feature specs (1)
journey specs (1)
rspec (5)
testing (5)
engines (3)
gems (1)
rails (3)
rails application suites (3)
css (1)
html (1)
javascript (1)
conferences (1)
boulder (1)
jobs (1)
refactoring (1)
ruby (3)
cancan (1)
rubymine (2)
rake (1)
basics (1)
  • About
  • Case Studies
  • Team
  • Community
  • Careers
  • Tools
  • 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 >