Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to handle backwards compatibility #1599

Closed
ioquatix opened this issue Feb 12, 2020 · 6 comments
Closed

How to handle backwards compatibility #1599

ioquatix opened this issue Feb 12, 2020 · 6 comments
Assignees
Milestone

Comments

@ioquatix
Copy link
Member

ioquatix commented Feb 12, 2020

After working on the lower case header issue, I can't remember who suggested it, but we can create a middleware, e.g. Rack::NormalizeHeaders which adjusts header keys according to the updated SPEC.

That being said, anyone who adopts Rack 3.x with middleware designed for Rack 2.x will need to insert this middleware themselves.

This won't be the only point of backwards incompatibility, and I feel like every feature we introduce in Rack 3 should at least attempt to provide backwards compatibility if possible.

Therefore, I want to introduce some new concept to Rack::Builder to manage this.

There are several approaches.

General Version

# config.ru

# The version of rack that this middleware was compatible with. We will automatically 
# insert middleware as required to adapt the 2.2 SPEC to the currently running version.
rack_version "2.2"

Specific Features

# config.ru

# Specific features are itemised, which indicate that this app would expect headers to be
# a hash, rack.hijack support, and support `headers[key] => Array`
rack_feature :header_hash, :hijack, :header_array

Alternatives?

I'm open to ideas, or doing nothing at all. However, it seems like if we can reduce the pain of breaking changes, it would make sense. That means by default, a Rack 2.x application should run unchanged on Rack 3.x and all Rack 3.x features are opt-in, or have compatibility layers suitable for Rack 2.x.

Implementation Notes

In Rack::Builder.to_app we would check the version and/or feature flags, and insert compatibility middleware as required.

@ioquatix ioquatix self-assigned this Feb 12, 2020
@ioquatix ioquatix added this to the v2.3.0 milestone Feb 12, 2020
@ioquatix
Copy link
Member Author

Also, I think if we do decide to implement this, we should kick it off in Rack 2.3, so there is a suitable migration path. Even in Rack 2.3 it is a no-op, or at best, an error if a feature is unsupported.

@simi
Copy link
Contributor

simi commented Feb 12, 2020

Great idea @ioquatix. Let me share few ideas/questions after initial look.

I like the "General Version", reminds me Rails versioned migration classes. The question is how long rack should support old "General Versions". Until next major? Support for "2.2" would be removed in "4.0" and deprecated at "3.99999" (last 3.x version)? Or until second next major?

How to handle this in generated config.ru (for example by Rails generator)? How to handle update of rack there (technically you're not "owner" of config.ru in Rails, the app generator/update process is maintaining this for you in common cases).

🤔 having those standard parts of config.ru, what about to introduce some simple generator ensuring those "constraints" are present in generated config.ru according to current version aka ⚙️ rack init? I can open separate issue for this idea.

@ioquatix
Copy link
Member Author

I'm on the fence as to whether this is a good idea.

e.g. https://github.com/kickstarter/rack-attack/blob/master/rack-attack.gemspec is okay.

The reality is, the Rack::NormalizeHeaders can only fix certain kinds of issues... There are some issues it can't fix. If we introduce such a feature flags, I can't help but feel we give a false sense of security.

I think where it makes sense to me is if we do get to the point where certain servers expose certain functionality and we want to know right off the bat, this application is compatible with this server. But if we can avoid that, it will be better for everyone IMHO.

@simi
Copy link
Contributor

simi commented Feb 12, 2020

You're not alone on that fence, in general I mean it is good idea to handle backwards compatibility. I have no idea which approach would work the best.

On the other side (personally) I wasn't missing this for last few years. It can be caused by minimal amount of huge/breaking changes done in last few months/years. Also I rarely use rack directly on long-term projects and maybe frameworks build on top of rack are doing great job handling those changes internally for me.

@ioquatix
Copy link
Member Author

ioquatix commented Feb 12, 2020

Rack hasn't really had a major release for 5 years. There have been a bunch of minor bug fix releases and security issues, but about a month ago there were about 100 outstanding PRs and the same number of open issues. So things have changed in the past few weeks quite a bit... but we haven't seen a huge number of issues come in mostly because I think we did alright managing the compatibility/changes and the test suite is pretty decent.

@ioquatix
Copy link
Member Author

We will start to address feature flags and feature detection in #1720.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants