Sorry for the mess. I'm moving things around. It'll be better soon.

History of RSpec

9th May 2021

In 2001 I started teaching Test-Driven Development to teams. Back then it was still a fairly new concept. Few teams had automated tests of any kind, and fewer still had heard of XP and TDD. Writing tests first and using the practise as a design activity was a completely foreign concept, and folks had a really hard time grasping it. (This fact hasn’t changed entirely, two decades on.)

It was a tough sell in those days. I worked hard to present the concepts in the best way possible, and to bring teams around. But it was really difficult, and I struggled. More importantly, and the problem I aimed to solve: the people I was teaching struggled.

One of the common problems I was experiencing in those days was people having trouble with the word “test.” Not just the word “test” but all of the vocabulary around TDD was, understandly, very test-centric. People were very confused. “You can’t test something that doesn’t exist,” they used to say, and often they’d be smug and add, “therefore your entire premise is flawed.” The word “test” was giving them an excuse to disregard a concept and method that I found very valuable, and I sought to change that.

In searching for solutions, I learned about the Sapir-Worf hypothesis of linguistic-relativity, which suggested to me that by changing the words used to communicate the ideas, I could influence how the idea was received and interpreted. Others around me had discovered this as well. Aslak Hellesøy, Dan North, and Liz Keogh, to name a few, were early on this train and provided a lot of insight and help.

So I started creating tools to use in my training. I wanted to remove the testing-centric vocabulary. To slightly paraphrase a prophet, “Testing is not the preferred nomenclature, dude.” By 2003, I had started teaching TDD using Ruby. In those days, Ruby was still a niche language. Ruby on Rails hadn’t yet taken the world by storm, but I appreciated that it was a proper Object-Oriented language that I could use to implement these ideas.

When pairing with others of similar mind, I found their tests all had names like test_should_do_this_thing. The word test was still there, but they were using a better word to communicate intent: should.

How do we get rid of the word test? In Ruby, we can easily remove it. So I had a plan: create tools for teaching TDD as a way of describing the behaviour that the completed software should have. This idea was still new at the time, but represented what the creators of TDD had been saying all along: automated testing communicates the behaviour that the completed software should have.

The first tool I created was a small Ruby file called describer.rb that simply aimed to remove the word test. It looked something like this:

require 'test/unit'

Description = Test::Unit
Context = TestCase

# redefine Test::Unit::TestCase.suite to use methods starting with "should" instead of "test"

With this tool, your “test” would look like this:

require 'describer'

class SimpleAdditionDescription < Description::Context
  def should_add_one
    assert_equal 2, add_one 1
  end
end

Now we can write tests without ever using the word test! This was a beautifully simple solution: we’re still using all of the wonderful tooling that existed in Ruby’s built-in standard library, including the robust set of runners, while enabling new practitioners to be using different words that wouldn’t create a cognitive dissonance seemingly caused by the constant use of the word “test.”

I incorporated this into my TDD training. In my workshops, we would use this single file to write our software descriptions. I stopped using the word test in my training. Suddenly the hand-wringing around the word “test” disappeared.

I kept this up in each of my training sessions until the last day. On the last day, I would tell everyone: “These things you’re writing that descibe your software. They actually represent an automated test suite that can be run to test the software and ensure that it acts the correct way.” I would show my classes, here’s how you actually write your tests in Ruby when you leave here:

require 'test/unit'

class SimpleAdditionTest < Test::Unit::TestCase
  def test_add_one
    assert_equal 2, add_one 1
  end
end

And it worked! I wanted my attendees to use the “standard tooling”, but I wanted them to approach it with a new frame of mind. The introduction of the testing vocabulary at the end allowed my attendees to use standard tooling, but to approach the problem from the intended perspective. Finally my training was providing the value that it needed to, and reaching a wider variety of people. People who might have been very resistent, previously.

The remaining problem in my classes, and one I didn’t notice at first, was attendees reversing the parameters to the assertions. It was common for my attendees to reverse the expected and actual values in their assertions, leading to confusing error messages. I’ll admit that I made this mistake occasionally, but was familiar enough with it that I recognized the error quickly. I tried to fix this by writing the expectations in a way that read more like plain language. I added a method assert_that which took a block, and you could use the assertions on the returned object.

assert_that { expected }.equals actual

This solution was a lot of code for a single file library that I only intended for use in the classroom. So I looked for a simpler way. With the power of Ruby, we can fix this! So I dipped my toe in the metaprogramming waters, and mixed the assertions in to Object. (This was a mistake in the released library, but it was really great for teaching.)

class Object
  def should_equal expected
    assert_equal expected, self
  end

  # every other assertion
end

And with that change, the teaching tool was complete. But it wasn’t released. It only existed in my workshops. I never intended anyone to use this outside of my workshops: I thought they should be using the tools that existed in the standard library. The xUnit pattern was well understood, available in nearly all languages, and very well supported. I thought it would be a huge mistake to add a new library to the mix, and endure the maintenance overhead of this.

There was no need for new tools, I thought, which only changed some word usage around. In hindsight, it was silly of me to think that this was a valuable activity for the classroom, but wasn’t necessarily a valuable activity for practise.

I never wanted to release this tool. xUnit existed, and was fit for purpose. To me, the thing that became RSpec was nothing more than a teaching tool, and I didn’t think it should live outside the classroom. But, I was coerced.

RSpec is Born

In the mid-2000s, Bob Martin was trying to make the same impression while introducing TDD. He was saying the same thing others were saying, but in a different way: “Testing is about specification not verification.” And he talked about the tests as “executable specifications of the software.”

I liked this framing, but I always had problems with the word “specification.” I still do. To me, an elder of the Internet who implemented many things from RFCs and specifications, the word specification was a reserved word, that should not be used for new purposes. I thought we should find a new word.

But Bob Martin was a hero of mine, and he had developed a following around the specification-centric vocabulary. He was shown a demo of the tooling I had created for my workshops, and contacted me to encourage me to release it. He strongly encouraged me to focus on the specification-centric vocabulary.

I still think RSpec was the wrong name for RSpec. When I first gave in to the idea of releasing it, I was still calling it “describer” and I thought I might do the popular thing of the day: drop the e and call it DescribR. But I wasn’t really happy with this name either, and I didn’t feel I was qualified to argue with Bob Martin on what it should be called. So RSpec was born.

RSpec was released in 2005.

I was very happy with RSpec at that point, as a teaching tool, but I still didn’t think anyone should be using it. People fell in love with the idea, and they really wanted to write their tests in this way. It amazes me that it caught on so widely, and so quickly. There have been surveys on the matter, and by some reports, up to 90% of new Ruby on Rails projects go out of their way to use it instead of the built in xUnit style frameworks. Very quickly, “RSpec clones” started popping up in nearly every other language.

RSpec as a DSL

Around the time RSpec was released, the idea of Domain-Specific Languages was also becoming popular. As a fan of using language to change the way people think about software, I wanted to see if we could make RSpec even better by creating a complete DSL for specifying the behaviour of your software.

Joe O’Brien and I paired on the first version of this at RubyConf 2005. The words we used are different than the words used now, but the idea was solid. What Joe and I paired on at RubyConf 2005 ended up looking something like this:

specify "add numbers" {
  it_should "add one to the provided numer" {
    add_one(1).should_equal 2
  }
}

This change, we hoped, would cause people to stop thinking about code at all, and start focusing on the desired behaviour of the software instead. I am still pretty happy with the fact that we turned RSpec into a DSL.

Shortly after, we changed the keywords to describe and it, and the describe/it pattern of software description was born.

Hand-off and Lessons Learned

Making RSpec into a complete DSL was, I think, my last real code contribution to the project. I still wasn’t using RSpec myself, because I considered it a teaching tool, and preferred to use the “standard” utilties. And since I was (and still am) working in many languages, I wanted to use similar tools across my work. I didn’t understand why, after learning the appropriate way to think about TDD, they would choose to use a non-standard library whose DSL caused awkward interactions with the object model.

Since I didn’t understand why people used RSpec, and I didn’t use it myself (to date, I’ve only ever used it on projects that had already started using it; I never choose it myself), I didn’t feel that I would be an appropriate steward of the project. There were many others who were more excited about the future of the project than me. So at some point in 2006 or 2007, I gave the project to its most prolific and important contributor to date: David Chelimsky.

Chelimsky was an amazing steward of the project. I could not have made a more correct choice about this. Handing RSpec over to the more-than capable (more capable than me, especially) hands of David Chelimsky is possibly my most positive contribution to the project. More positive, even, than creating it.

I also thought (naïvely, the historical record has shown so far) that RSpec wasn’t going to be the only lasting contribution I made to the software industry as a whole. I was insistent, in 2007, that I wasn’t going to be a One Trick Pony. I still like to hope that I have many tricks left in me, but I’m less confident that I will be able to move the needle again in a similar way. I’ll be honest: this fact has caused me a lot of sadness over the years.

Lessons Learned and Apologies

There were a lot of mistakes I made. The main one is more soft: I built a thing that people enjoyed, that changed their way of thinking, and I strongly resisted releasing it and allowing them to use it in their own way. I didn’t realise until many years later, when I started getting “thank you” messages from people telling me that they were unable to grok TDD and BDD, or testing at all, until they came across RSpec. I am humbled and appreciative of such messages, and I’m sorry I tried to stand in your way.

On the technical front: it was a mistake to mix the assertions into Object. It caused a lot of pain for the early adopters, and in the early days of the project we spent a lot of time doubling down on that decision and working around the problems this caused instead of re-thinking and changing the expectation format. This was rectified in future versions with the expect(expected).to equal(actual) which is the most perfect way to write an expectation, in my opinion, and is closer to the original experiments I had before making the mistake of mixing in to Object. If you spent time annoyed by this in the early days, I am sorry for the pain I caused by doubling down on a bad decision, and causing your great efforts at building more robust software to be hampered by this.

I also regret letting others take credit for my work. An early mentor of mine, who I do not name here because he has proven himself to be a self-centred and generally abhorrent individual, and in hindsight a terrible mentor, tries to tell others that he created RSpec. That the things he built after RSpec was created were the thing that RSpec is based on and inspired by. RSpec is based on contributions of code and knowledge from many people, but this individual’s actual contributions to the project were minimal, and in the early days limited to stealing someone else’s code and throwing away the license headers, which is a thing I find reprehensible.

And finally, I regret putting distance between myself and the thing I’d created. I think I could have built more useful tools in the space, and helped more people in bigger ways if I was a bit more accepting of the fact that people were using a thing I created for purposes other than what I intended it for. I am sorry for not helping more people.

Gratitude and Future

I am grateful for the opportunity to have contributed to the software community in a small way, and to have helped people realise their own potential. And I hope to be able to help even more people realise their own potential in the future. I am eternally grateful for the appreciation for my creation, its continued use in the world. I am grateful for the many beers that people have bought me as thanks for a thing I never wanted to release.

I’m hoping there are more tricks left in this pony, but for now I’m focusing on helping individuals and teams do their best work. I will continue to be happy with the many small contributions I can make, and grateful for the opportunity to work with people to help me make those contributions.

And I’m grateful for the future contributions I will have with people who will help me help them, and I hope I can make the development of software just a little bit nicer for everyone involved.