-
-
Notifications
You must be signed in to change notification settings - Fork 233
RFC: change our Ruby version support policy for RSpec 4 #25
Comments
I believe that users who use a very old Ruby version but need to be on the latest Rspec version are very rare and not worth the effort you correctly mentioned. In my opinion, |
|
I'm most worried about ensuring we support bundler, though maybe with that being folded into rubygems it gets the same EOL policy as Ruby? In which case I'm more inclined towards a more aggressive N, maybe even matching them directly. @indirect do you have any concerns about RSpec dropping old ruby version support (above policy)? From the travis config, looks like bundler 2 is supporting 2.3+ but bundler 1.X is still supporting 1.8.7 https://github.com/bundler/bundler/blob/master/.travis.yml#L57 |
Older versions of Ruby, especially those I really don't think we should worry about the major version "expectation" we should just publicly state what we're doing and carry on, I'm also no at all concerned about references to versions in media, people expect those to be out of date, especially printed books. |
I disagree. Every additional version of ruby that we support adds to our maintenance burden. It is a qualitatively different burden for Ruby 2.x compared to 1.x, but it's still there. And even if we felt like the 1.x burden is the main thing needing to be addressed, I'd argue that's reason enough to consider a different policy. The reason we still support 1.x is because we chose a policy that dictates that the only time we can drop support for a version is as part of a major version release, which only gives us the opportunity every few years. When we release a new version, I don't want the ruby versions supported at that time to impose a hard requirement on the RSpec maintainers for the next 3+ years due to our versioning policy.
I assume we'd use the If bundler doesn't take that into account, it sounds like something we should push to have improved there.
My point was simply that we can't rev the major version as often as we'd like to be able to drop support for an old Ruby version. For example, my publisher really wouldn't have appreciated us releasing RSpec 4 right after they published my book on RSpec 3 (which took significant time and resources on their part). So I do not consider reving the major version of RSpec more often as a realistic possibility. |
Sure theoretically, in practise it's minimal. We spend more time solving peoples trivial issues that we do solving EOL'd Ruby bugs. If support burden is the only reason we drop Rubies we could drop RBX and JRuby which cause us the most grief.
It doesn't. Our own builds fall foul of this, which is why we have ruby version if blocks in them.
We haven't done it because we haven't felt the time is right, it's not that we can't.
If we made major releases more common, without the expectation of major features, this becomes a non issue. It was only an issue for 2 -> 3 because we are made other radical feature changes at the same time. Arguably having a 3 -> 4 release (as we've discussed before) that only discards Ruby versions makes us more stable not less. |
It's possible that I missed the point of what you said, but it seems to me that bundler takes the source "https://rubygems.org"
gem "rails" When I tried to force version
|
Thanks for actually trying it, @iGEL :). Seems like we don't have to worry about bundler auto-upgrading users to a version they can't use as long as we declare
EOL'd Ruby bugs are a tiny part of the maintenance cost I'm talking about. Here are some things I'm talking about:
Maybe you haven't felt that continuing to support old versions of Ruby is burdensome, but I certainly have. |
FWIW in practice I've found it pretty painful supporting old Ruby versions. Particularly when I was working actively with mocks. |
Our own builds say otherwise. From https://travis-ci.org/rspec/rspec-expectations/jobs/323984512 We, by merit of being one of the most popular testing framework have to be the lowest bar when it comes to Ruby support. If we drop a Ruby version we are effectively orphaning everyone on that Ruby version that depends on us. Currently we are able to say "upgrade to the latest version of RSpec" for a lot of enquiries from older versions, if we start dropping Ruby versions we may well have to start back porting bug fixes to the maintenance branches. I feel that burden outweighs the burden of supporting multiple older Rubies on the current branch. Especially when we don't have any stats of how many people actively use RSpec on those versions, if rubygems was able to provide us that I'd feel more confident we could do this safely. |
Speaking only as a grateful user of RSpec who otherwise has no skin in the game: I absolutely agree that you should find a way to gracefully drop support for EOL Ruby versions. I wish you had unlimited resources but I understand that you don’t. Your time is limited and precious, so please use it to maintain & improve RSpec for the vast majority of Ruby users. However, I want to say that I do disagree with the point about “community expectations” around the content, significance and rarity of major RSpec releases. It’s a somewhat circular argument: yes, at the moment it’s years between major RSpec versions, so they are de facto A Big Deal. But if you’re going to change something, that is an essentially harmless thing to change, versus violating the assumption that new minor releases don’t break compatibility. The scope of the “RSpec major releases are a big deal” expectation is only as large as the more engaged portion of the RSpec userbase; the scope of “minor releases don’t break things” is orders of magnitude larger, so it’s much harder to push against and, crucially, not something that you can ever change outside of your own project. But you can easily choose to cut major RSpec versions more often, and everyone will just get used to it. In summary, my gut feeling is that you’ll piss more people off by dropping Ruby support in minor releases than you will by simply releasing more frequent major versions of RSpec. People would quickly adapt to the latter, especially given the changes proposed in rspec/rspec-rails#1967. |
FWIW I would be happy dropping EOL ruby in major releases. |
late to chime in here, but I also would prefer that dropping a ruby version was a major, and that we accept that RSpec majors will happen yearly with Ruby version releases. |
Thanks for chiming in @tomstuart! Regarding cutting major releases more frequently, I have a few concerns:
In short, I think that yearly major releases for the purpose of dropping support for an EOL'd ruby version totally changes what "major release" means from containing stuff that significantly affects users (breaking changes and notable new features) to something that doesn't affect many users at all (dropping support for a Ruby version few users were using anyway).
This statement surprises me. Is it common and expected these days that projects only drop support for a language version in a major release? I was under the impression (perhaps mistaken) that RSpec was fairly unique in interpreting SemVer this way. For example, I don't believe Rails follows that (although I might be wrong: someone correct me if so). And as another counterexample, Elixir typically only supports the last couple Erlang/OTP versions, and drops support for old Erlang/OTP versions in nearly every minor release. More generally, if we're dropping support for a Ruby version that was EOL'd 12 or 24 months ago, are there really many users who remain on those versions while also upgrading to the latest and greatest RSpec release? |
Thanks @myronmarston, that all makes sense. I honestly don’t know much about the nuances of people’s expectations around semantic versioning when it comes to versions of foundational pieces like Ruby or Rails (versus conventional dependencies). My guess is that in many cases it may not be more nuanced than “I expect to be able to upgrade to a new minor version without anything breaking”, which would inherently include continuing compatibility with Ruby/Rails/whatever, but I don’t have a good sense of whether that’s a reasonable or realistic expectation in general. Hopefully others can clarify this. Regarding useful new features in new major releases: is it possible that some major release features (e.g. performance? API niceties?) could be enabled by dropping support for old Ruby versions? |
As someone who has benefited hugely from RSpec's generous backward-compatibility with Ruby versions (e.g. in re2, embiggen, fieldhand, etc.) and has been unpleasantly surprised when other programming languages' test frameworks don't follow suit, I'd second @tomstuart's recommendation that RSpec should drop language support in a major version, not minor. At the moment, I specify RSpec versions with an optimistic version constraint of, say, Of course, I happily support RSpec's decision to drop support for older Ruby versions due to the maintenance burden but I would definitely be surprised if this wasn't consider a major, breaking change. Having said all that, I think there is a very real tension here around financially supporting the maintenance of RSpec itself: that is, the major version of RSpec is used not only for prosaic dependency management reasons but also in order to market RSpec itself and books on the subject. Could this tension be alleviated by having some concept above major version numbers that communicates the amount of change in RSpec itself? It's not quite right but I'm thinking of the recent introduction of "editions" in Rust where the stability of Rust version numbers is divorced from major changes to the language itself. Would it help if you were still free to pen "Effective Testing with RSpec 2018" where "RSpec 2018" describes an "edition" of RSpec even if the major version number is RSpec 6? |
RSpec shouldn't have to support any version of ruby which is EOL'd. There really shouldn't be any time period after that, since those ruby versions have fallen off of security patch support and that means that someone is having to run potentially vulnerable instances of software in order to test and ship. Users that expect support after ruby versions are EOL are implicitly demanding that someone run potentially insecure infrastructure for them. That really shouldn't be allowed to happen. Also 👍 on interpreting SemVer to mean that you can define your own support policy around when you drop ruby language support and don't necessarily have to only drop language versions on major version bumps. Ideally SemVer would be clarified on this point (and I think if it does go towards mandating major version bumps to drop language version support that SemVer should be dropped or forked because that produces perverse outcomes of requiring major version bumps only to drop language support). The fact that RSpec still supports 1.8.7 and 1.9 today is an indication this policy has to change. That's a terrible thing to do to the authors. |
Very much this. Its surprising behaviour much further away from the norm than just increasing major releases more frequently. I think people would be fine if we did this every year when Ruby increases in version.
Not having any author experience myself (I think you're the only current team member that has authored a book on RSpec) I feel thats flawed, there shouldn't be an expectation from the publisher to stall or affect development just because a book has been released, after all publishers don't use RSpec, the community does. In any case in other eco systems an update is seen as a chance to update and re-market a book, e.g. Rails 3 in action was updated for Rails 4 and used to market itself as a whole new book. With coordination with the publisher it should be easy to update a book from RSpec 3 and RSpec 4 or 5, even easier with less major features. Given that we release features in minor releases books are already out of date anyway, missing functionality that now exists. All releasing a major version does is highlight this fact. |
It looks like bundler+rubygems may still not strip out transitive deps which no longer support the ruby version being used / in the Gemfile: rubygems/bundler#6471 |
They don't, they break our builds. |
As a casual RSpec contributor, I'd like old version support to be dropped soon, so dependencies can be upgraded and I don't need to learn a 3 years old, almost 3 majors old, cucumber version to contribute... 😅. Personally I agree with @myronmarston's proposal (drop EOL'd rubies support on minors), but I don't mind the alternative as long as the major version cycle becomes a bit more agile! :) Thanks for RSpec to older and newer maintainers, by the way ❤️. |
I'm fixing the issue reported by @lamont-granquist in rubygems/bundler#6728. Hopefully the |
Given that Rubygems and Bundler are now dropping Rubies < 2.3, I think its getting to the point where we should too. For RSpec 4 though there a few things I'd like to have:
Probably deserves its own issue for such plans |
6728: Fallback to sequentially fetching specs on 429s r=indirect a=deivid-rodriguez ### What was the end-user problem that led to this PR? The problem is that sometimes `bundler` is unable to resolve certain gemfiles. Specifically, sometimes it does not respect the `required_ruby_version` setting. This causes some people to assume that `bundler` will always try to install the latest version of any dependency, regardless of the ruby version being run, because as a matter of fact, this feature sometimes just doesn't work. See for example the discussion at rspec/rspec#25. The problem was consistently reproducible until a few minutes ago with the following `Gemfile` under `ruby 2.3.7` ```ruby source "https://rubygems.org" ruby "2.3.7" gem "berkshelf", "= 6.3.1" ``` ``` $ docker run -it --rm --volume $(pwd):/app ruby:2.3.7 sh -c "cd /app && rm -f Gemfile.lock && bundle install" Fetching gem metadata from https://rubygems.org/............. Fetching gem metadata from https://rubygems.org/.. Resolving dependencies.... Fetching public_suffix 3.0.3 Installing public_suffix 3.0.3 Fetching addressable 2.5.2 Installing addressable 2.5.2 Fetching buff-extensions 2.0.0 Installing buff-extensions 2.0.0 Fetching hashie 3.6.0 Installing hashie 3.6.0 Fetching varia_model 0.6.0 Installing varia_model 0.6.0 Fetching buff-config 2.0.0 Installing buff-config 2.0.0 Using bundler 1.16.5 Fetching fuzzyurl 0.9.0 Installing fuzzyurl 0.9.0 Fetching tomlrb 1.2.7 Installing tomlrb 1.2.7 Fetching mixlib-config 2.2.13 Installing mixlib-config 2.2.13 Fetching mixlib-shellout 2.4.0 Installing mixlib-shellout 2.4.0 Fetching chef-config 14.5.33 Installing chef-config 14.5.33 Fetching libyajl2 1.2.0 Installing libyajl2 1.2.0 with native extensions Fetching ffi-yajl 2.3.1 Installing ffi-yajl 2.3.1 with native extensions Fetching mixlib-log 2.0.4 Installing mixlib-log 2.0.4 Fetching rack 2.0.5 Installing rack 2.0.5 Fetching uuidtools 2.1.5 Installing uuidtools 2.1.5 Fetching chef-zero 14.0.6 Installing chef-zero 14.0.6 Gem::RuntimeRequirementNotMetError: chef-zero requires Ruby version >= 2.4.0. The current ruby version is 2.3.0. An error occurred while installing chef-zero (14.0.6), and Bundler cannot continue. Make sure that `gem install chef-zero -v '14.0.6' --source 'https://rubygems.org/'` succeeds before bundling. In Gemfile: berkshelf was resolved to 6.3.1, which depends on chef was resolved to 14.5.33, which depends on chef-zero ``` Funny enough, I can no longer reproduce it at the moment, I guess it depends on the specific load conditions of the rubygems.org servers? ### What was your diagnosis of the problem? My diagnosis was that sometimes our resolution falls back to the old dependency API that didn't implement the `required_ruby_version` setting. In particular, this happens because the new API returns `Net::HTTPTooManyRequests`, so `bundler` gives up and defaults to the old API. ### What is your fix for the problem, implemented in this PR? My fix is to, instead of directly fall back to the old API when rate limiting happens, try first to fetch the dependencies sequentially instead of in parallel still from the new API, so that rate limit does not affect us. ### Why did you choose this fix out of the possible options? I chose this fix because it was the only idea that came up. As a matter of fact, #6471 and #6639 were closed because there was nothing we could do, so it seems like it's the only idea so far :) Co-authored-by: David Rodríguez <[email protected]>
What should be OK for EOLed versions. As a very minor and unimportant user I am perfectly fine with EOL version being unsupported, and I consider weird that EOL version would be supported for months or longer after it is EOL. And if you want given Ruby version to be supported for longer than you should either volunteer for maintenance or fund someone who will do this) |
One way around dropping support for EOL'ed Rubies and only doing this in major versions is to release major versions once a year. E.g Ruby 2.4 is EOL in April 2020, RSpec 5 released in December 2021 and drops support for it. So:
This way, it will be still possible to update to RSpec 5 in December 2021 even though 2.5 is EOL in April 2021, and receive all RSpec fixes until December 2022, 1.5 years after Ruby 2.5 is EOL. I remember there is a policy to only support the latest major version. This relaxes constraints of supporting deprecations.
Probably even less than that in RSpec 5. |
RSpec supports Ruby for longer than Ruby does because real people don't always upgrade. I'm not incrementing RSpec every year just to drop Rubies, especially when they don't cause us that much trouble. |
@myronmarston - Minor thing but you say
Technically you support every version as per rubygems. Required ruby is >= 0. Could we add a small patch to the next release that sets the minimum version to whatever it is meant to be |
The next major version will do so. |
From RSpec 4, we will be adopted more of a "breakver" style of support for Ruby, every minor point release will support the "at time of first release supported Ruby versions" (and possibly recently end-of-lifed depending on timing) but we will switch to allowing dropping support on minor versions. I've written a bit about this in the monorepo blog post, and as part of triaging the old repos I'm closing this issue. |
TL;DR
I propose that we change our Ruby version support policy for RSpec 4 so that dropping support for old ruby versions is no longer coupled to major version releases. Instead, I recommend we adopt a policy based around supporting old Ruby versions for N months after the Ruby core team has EOL'd
it (for some reasonable value of N).
The Current State of Things
We currently support
106 versions of MRI:1.8.71.9.21.9.32.02.12.2In addition, we have been strictly interpreting SemVer to mean that the only time we can drop support for an old version of Ruby is when we do a major release. As a result, we drop support for old versions very, very rarely. In fact, in all my years of involvement with RSpec (dating back to 2010), I can only think of one version of Ruby we've ever dropped support for: we stopped supporting 1.8.6 when RSpec 3 was released.
I think the amount of effort we expend supporting old versions vastly exceeds the utility to our users.
Why is this a problem?
Supporting old Ruby versions has a very real maintenance cost:
3.15.2 is out. Cucumber does not support ruby 1.8.7 starting with Cucumber 2, so we haven't been able to upgrade. Staying on old versions of dependencies causes us to accumulate excess tech debt.Regarding SemVer
The SemVer spec does not specifically document when a library is allowed to drop support for an old version of a language. I'd argue that it's a grey area that we're allowed to decide on for our project. And even if it did explicitly document it, it's up to us to decide if we want to strictly follow it. IMO, the important thing about SemVer is that your project documents the semantics of your versioning and sticks to it--not necessarily that you follow the SemVer spec. IMO, if we realize that strict adherence to the SemVer spec was inhibiting our ability to serve our users due to extra work it requires, it would be wise and appropriate to choose not to follow the spec anymore, and decide on our own semantic that we think better serves our users.
That said, I don't believe the SemVer spec requires that we maintain support for old versions of the language until the next major release.
Coupling Version Drops to Major Releases is a problem
While we strive to follow SemVer, bumping RSpec's major version is not purely a technical decision. It's also a marketing decision. The Ruby community has certain expectations around a major release of a project like RSpec containing major new features. In addition, there are lots of published materials (such as my own book) that reference RSpec's version number.
That means that we can't simply rev the major version number more often, as a means to drop old ruby versions. Besides, I think our users appreciate the stability of a major RSpec version line lasting for years.
Given that major new RSpec versions have historically only happened every 3-5 years, and our recent productivity is, if anything, less than it's been in the past, I think that coupling Ruby version support to major releases is problematic. We could better serve our users (by more productively addressing their issues, building new features, etc) if we were able to drop support for old versions of Ruby between major versions.
So, I believe that beginning with RSpec 4, we should come up with a new Ruby version policy that is not coupled to major releases.
What should we do instead?
I propose that we allow ourselves to drop support for old versions of Ruby as part of a minor release (e.g.
x.y.0
) in addition to major releases. In addition, I think it would be beneficial to have a specific policy about when we will drop old versions, so that it's not arbitrary based on when we feel like it. The Ruby core team announces the support schedule for each version of Ruby, and that includes an EOL date. I think we should adopt a policy of dropping support for old versions of ruby in the next minor release that comes N months after a version is EOL'd (for some reasonable value of N, such as 6, 12, 18 or 24).Here's a concrete example. Ruby 2.0 was EOL'd on 2016-02-24. If we had adopted this policy for RSpec 3, and chose N=24, we would be dropping support for Ruby 2.0 in RSpec 3.8, which is the next minor release, since 2 years has elapsed since it was EOL'd.
How would this effect users?
Questions
The text was updated successfully, but these errors were encountered: