Open bendlas opened 2 months ago
There are two parts to this problem:
I recognize that sometimes, breaking changes are unavoidable. I've also made changes from time to time without paying attention to backwards compatibility. But I lean towards avoiding breaking changes whenever possible, aligning with the Clojure ideal of growing without breaking. When changes are necessary, they should be introduced thoughtfully. Some of the things we can do here are:
system.stateVersion
or something similar to maintain compatibility with options that might have changed.To put these into practice, we could:
Achieving perfect long-term backward compatibility is practically impossible given the scale of nixpkgs. But we can get closer to this ideal by setting policies and leveraging tools to enforce them. By prioritizing stability and careful growth, we maintain user trust and make the ecosystem more robust for everyone.
Where do you think the line of "if necessary" should fall?
First and foremost, breaking changes should only be introduced if there's a clear (large) benefit to the usage of the module options, package/lib attributes, etc. When this does occur, backwards compatibility should be implemented via aliases or small wrapper layers unless it is deemed too large of a maintenance burden, or the change is such is so large that it isn't feasible to use either
How close do you think we can with long-term backwards compatibility - to the Clojure ideal [1] - given the scale of nixpkgs?
I don't think breakages will ever be avoidable, nor will we be able to adopt something similar to Hickey's idea of only growing our collection. However, a lot of tools in nixpkgs -- like pkgs/top-level/aliases.nix
and especially functions in our module library such as mkMergedOptionModule
and mkAliasOptionModule
-- can get us to an approximation of not removing user-facing interfaces that will ease the stress of breaking changes over time
And as said above by illustris, CI checks to flag breaking changes can also assist here by ensuring things are only broken when we explicitly intend to, it's necessary (as defined by above), and that there are no better paths to retaining backwards compatibility according to not just the author, but the wider contributor base. Some prior art here is the Rust community's Crater project, which runs automated tests across crates in their ecosystem and compares the results between a new and older version of the compiler
(Also small side note: thanks for linking that keynote! It's been a good listen and I plan on finishing it tonight now :p)
I am happy and always open about specific proposals, as an RFC or other-wise, to improve "backwards-compatibility"; but I don't think it's an urgent problem at this point in time.
NixOS is much better than most other systems in allowing you to build and/or switch back to quite old releases, even with a binary cache still available!
Keeping stability in terms of code is a much broader topic. I think the policy to allow breakage between releases is a good one, but you are right that we should elaborate that "if necessary" part.
Nix offers an unparalleled story for backwards compatibility, or it could, with some architectural changes (and should!). It's entirely reasonable to expect that a future iteration will enable module- or even function-level version pinning, allowing for trivial backwards compatibility of critical components while the rest of the system moves forward.
I'm happy to stick to the current pattern of ensuring compatibility for supported stable branches while allowing for breaking changes in the unstable branches.
Projects under the nix-community organization, unofficial as they are, have different expectations. As I answered in #11, I consider nix-community to be the development and staging ground for new feature additions to the main projects. While the specific details of those features are worked out, one should expect possibly-frequent breaking changes.
In #16 I discussed the full-reproducibility goal, and this applies here also: achieving perfect bitwise reproducibility will go a long way towards satisfying some maximal vision of backwards-compat.
I would leave this up to the individual maintainers of the affected components. Maintaining backwards compatibility can be a pain and they are the people who actually do the job. Though I would still recommend providing a clear migration path in the contributing documentation whenever practical.
Question
Currently, we seem to be promising compatibility for stable branches, but in new releases, we are allowed to break "if necessary". Where do you think the line of "if necessary" should fall?
How close do you think we can with long-term backwards compatibility - to the Clojure ideal [1] - given the scale of nixpkgs?
Can you answer specifically about NixOS module options, as well as generally for nix community projects?
[1] "There are only two ways to change software: growing it and breaking it. We don't break."
Candidates I'd like to get an answer from
No response
Reminder of the Q&A rules
Please adhere to the Q&A guidelines and rules