Close
Glad You're Ready. Let's Get Started!

Let us know how we can contact you.

Thank you!

We'll respond shortly.

LABS
Specific interfaces – in the small

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

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.

  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.

  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.

  4. Austin Putman says:

    Jon Postel is the quotable person you seek.

  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

Post a Comment

Your Information (Name required. Email address will not be displayed with comment.)

* Copy This Password *

* Type Or Paste Password Here *