Talks

Cleaning house with RSpec Rails 4

Cleaning house with RSpec Rails 4

by Sam Phippen

In the talk "Cleaning House with RSpec Rails 4" presented at RailsConf 2019, Sam Phippen discusses the evolution and strategy behind versioning within the RSpec framework, particularly focusing on compatibility and how it relates to the open-source ecosystem. The presentation highlights the importance of maintaining robust test suites in Rails applications and addresses the challenges faced by developers when upgrading dependencies.

Key Points Discussed:

  • Introduction to RSpec Rails: Sam introduces himself and provides context about his work as an RSpec maintainer and developer advocate at Google.
  • Compatibility Concerns: The concept of compatibility is explored, particularly how dependencies function together in a Rails application and how changes in versioning can cause issues.
  • Semantic Versioning: Sam explains the principles of semantic versioning (SemVer) and how they apply to Ruby and RSpec. He discusses how major, minor, and patch version increments signal different types of changes and their implications on application functionality.
  • Breaking Changes: Examples are provided to evaluate what constitutes a breaking change in a library, emphasizing that breaking changes often depend on context rather than just source code.
  • Versioning Strategy Changes: The talk transitions into discussing how RSpec's versioning strategy is evolving, particularly that RSpec Rails will now be versioned separately from the core RSpec libraries, allowing faster adaptation to new Rails releases.
  • Current Status of RSpec: Phippen outlines the supported versions and recent changes made to RSpec and its libraries, including plans for future releases.
  • Call to Action: Sam concludes with an appeal for contributors to assist in the maintenance and development of RSpec Rails, indicating the growing need for community support and involvement.

Main Takeaways:

  • RSpec has been actively working towards a flexible and responsive versioning strategy that reflects the rapidly changing Rails landscape.
  • The relationship between library authors and users should be rooted in clear communication about versioning decisions and the intended consequences of changes.
  • Community engagement is crucial for the continued evolution and support of open-source projects like RSpec Rails, emphasizing the necessity for more contributors and maintainers within the ecosystem.
00:00:20.660 So, I wasn't expecting to be introduced as the birthday boy. Amongst my many credentials, that's not the one I was expecting Chris to lead with. Thank you. We'll get to it, I promise. This talk is titled "Cleaning House with RSpec Rails 4"; let's get started.
00:00:28.829 To introduce myself, my name is Sam Phippen, and I am @SamPhippen basically everywhere on the Internet. This profile picture was taken on a very fancy camera before I removed my beard. I'm an RSpec maintainer, as Chris said, and I work at Google as a Developer Advocate for the Google Ads team. Today is my birthday; I’m 28! The day has been a little bit reflective for me. I spoke to my parents earlier, and my mom was like, "Of course, you're at a computer conference. We always knew you were going to be a computer programmer." I wondered how she could know that about me when I was just one year old on an IBM PC portable.
00:01:23.729 When writing this talk, I thought a lot about how there are many different ways to present at a conference. The speaking and slide structure we've seen is quite common at this point. So, I did what any reasonable person would do: I went to Twitter. I posted a poll asking if people would listen to an unstructured rant where I simply talked about RSpec for 40 minutes without any planning. Interestingly, 59% said yes, and 41% said no. With that, I calculated the p-value to determine if the result was significant or not.
00:01:59.099 So Chris, don’t worry; we have a structured talk exactly as I submitted to the CFP, and I won't just be yelling at you for 40 minutes. I want to talk about the word 'compatibility.' When you hear the word 'compatibility', what does it bring to mind? Perhaps it’s how well the libraries in your application mesh together or whether an upgrade will cause anything to break. Is your test suite functional? Is your application functioning? Most of our applications are not just our own code; they are built on the shoulders of giants.
00:02:29.489 As we are here at RailsConf, I would wager that for most of you, Rails has more code in it than you have written in your application. I know it's the end of the conference and everyone's feeling a bit low-energy, so can everyone please raise their hands? We're going to do a quick poll! Put your hands down if your application has no test suite at all. Now, put your hands down if you have a test suite but aren’t particularly happy with it — maybe it’s flaky or breaks all the time.
00:02:51.340 I think I spotted a few GitHub employees at the front who just put their hands down, so we should all feel great about that! Who here has a really great test suite? Keep your hands up if your test suite is consistently green and you'd push to production with no fear whatsoever. That's a good number of people! It's very impressive. I'm proud of you all. The Ruby community does value testing, and everyone can put their hands down now. However, some of us have confidence in the test suites of our applications. But what if I did this to your app? What if I came in, deleted your Gemfile.lock, ran bundle update, committed, pushed, and immediately deployed to production? Everyone's probably screaming in fear emoji right now!
00:03:55.720 You're going to get the newest versions of every dependency that your application has with no bounds or constraints whatsoever. You better make sure that your Gemfile is pinning every dependency exactly how you want it. If you don’t, things could get messy! Let's come back to compatibility. When we write a Gemfile, we specify which versions we want, and when we run a bundle install, it locks these versions. But if we delete the lock file, Bundler is free to pull in any version available.
00:04:43.780 If you have a pinned version for something critical, running a bundle install with no lock file will just pull the latest version in. This can potentially break your application's functionality. Conversely, if we have extremely specific pins, and we try to upgrade something else, we might fail to bundle, leaving our application several versions behind the latest offerings. This situation can lead to overly restrictive pins causing constraints and technical debt within our applications. That’s why it’s vital to exercise diligence and caution when specifying pins in your Gemfile.
00:06:07.550 In the Ruby community, we have largely standardized on semantic versioning, which provides a clear mechanism for discussing how to version our libraries. Semantic versioning specifies a major, minor, and patch version level, helping us categorize and communicate our changes effectively. This aspect is crucial for understanding version strings like 1.10.3, where '1' is the major, '10' is the minor, and '3' is the patch level.
00:07:05.539 Semantic versioning also outlines when to change these numbers. For instance, if you fix a bug, you increment the patch level; if you introduce a new feature or change an API surface that remains backwards-compatible, you increment the minor version; and for any breaking changes, you increment the major version. However, the specification does not explicitly define what constitutes a breaking change. This intentionality allows the specification to remain universal across various programming languages, so while it defines guidelines for version increments, it leaves the definitions up to the library maintainers themselves.
00:08:32.180 At the beginning of this conference, David showed us the full text of the MIT license, focusing particularly on a paragraph defining the responsibilities of maintainer. This basically states that any maintainer of an open-source package can 'break' your application at any time for any reason. While I am not criticizing this trade-off (because free software comes with its own set of responsibilities), it does highlight the relationship between semantic versioning and the maintainership of libraries.
00:09:30.900 To illustrate the impact of these breaking changes, consider the following hypothetical situation. Let’s say we have a function called 'status_message' that traditionally returns the number '123'. If I change it to return the string '123', is that a breaking change? The type has clearly changed, so its usage might differ in certain contexts; however, if the author intended for the function to be used only within template rendering — where the returned value would be string-interpolated — the change would cause no issues.
00:10:21.340 Now, let's look at another case with a function named 'count_rows' returning the integer '123'. Changing this function from returning an integer to a string may be viewed as more confusing due to its name suggesting a count operation. Inconsistencies in return types can lead to unexpected behavior, demonstrating how context and naming can influence the perceived stability of changes.
00:11:06.340 Essentially, breaking changes cannot be purely defined by assessing the source code. Their implications can vary broadly based on how objects are intended to be utilized. In the Ruby community, we utilize semantic versioning to communicate author intent about the stability and reliability of library behavior. Hence, versioning transcends being a mere technical consideration; it involves a philosophical understanding of the implications of our changes.
00:12:05.920 Now, let’s discuss how this framework applies to RSpec. For a long while, the semantic versioning guarantee with RSpec was simple: between major versions, we will never break your tests. This is vital for a testing framework; we wouldn’t want tests to suddenly break after a minor version upgrade. Thus, if you pin to RSpec 3.0 in your Gemfile, we assure you that, as the maintainers, we won’t break your tests as long as you are not changing any other dependencies that may affect it.
00:12:57.220 This versioning strategy guides both our maintenance efforts with RSpec and your efforts to keep your tests functional through updates. Moving forward, I want to address the structure of RSpec and how it will evolve. RSpec is actually a collection of individual gems that together create a comprehensive testing framework. Thus, when you use gems like 'rspec-core', 'rspec-mocks', and 'rspec-expectations', you are pulling in independent libraries that have been designed to work well together.
00:13:44.370 For example, if you're writing a test suite using Minitest and you're struggling to set up a mock in the right place, you can incorporate RSpec Mocks as an alternative mocking library to facilitate your testing. All these components interact with one another, allowing for rich capabilities throughout the RSpec ecosystem. However, RSpec Rails, a separate library specifically for Rails applications, adds Rails-specific functionality to enable testing in those applications.
00:14:40.700 Currently, all of RSpec's libraries, including RSpec Core, RSpec Mocks, and RSpec Expectations, are versioned together in lockstep and are currently at version 3.8.x. The intention here is to ensure that when we release a new version for RSpec, all dependent libraries also receive the latest updates simultaneously. Given that there hasn’t been a major RSpec change in nearly four years, we have been able to transition smoothly through the 3.x series without significant risk to user tests.
00:15:39.760 Because Rails is evolving quickly and we are supporting a vast array of Rails versions — back to 3.0, alongside Ruby versions as old as 1.8.7 — it poses a considerable challenge for us. As we have not released a major version, our users are aware that RSpec Rails also supports the original Rails 3 functionality. However, by introducin in stability by updating the versioning strategy to accommodate new Rails major releases, we can both remain compatible while maintaining a flexible and relevant testing environment.
00:16:32.640 Consequently, RSpec Rails will now be versioned separately from the other RSpec libraries. This strategy ensures that we are not held back by the pace of RSpec's updates; when a new Rails major version is introduced, we'll produce a new major version of RSpec Rails. This streamlining allows us to provide timely support and integration for each Rails version while maintaining continuous support for previous versions.
00:18:07.980 With all of this in mind, we've implemented a development strategy for RSpec Rails which involves maintaining ongoing awareness of bugs and enhancements that need addressing. I invite any interested parties to engage with our issues tracker and contribute to bug fixes. You are not required to be a maintainer to improve RSpec; substantial changes can be suggested or proposed through our platforms. I am currently searching for more contributors to help handle attention on the RSpec Rails project.
00:18:51.850 That’s all from me; thank you for your time! If anyone wishes to connect, here is my email address.