-
Notifications
You must be signed in to change notification settings - Fork 29.8k
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
Stability Policy/Statement #725
Comments
Also, we might want to consider vendoring |
I think this is harmful long-term. See the entire promises co-existence discussion. Saying everything will never change locks you into a position where everything you do is stuck as legacy forever. |
@Fishrock123 the thing is, that statement is already pretty true. We still can't even remove the If we ever wanted to move to a better promise-centric API we would probably do that along with support for the new modules spec and all the API changes would only be accessible through new-style modules which would make that an API addition and not a backwards incompatible change. We've got an ecosystem of 130K modules, it'll be 200K before the end of the year. Any backwards incompatible change will break tens of thousands of modules, not to mention all the applications that rely on them. At this point in the projects maturity it just isn't conceivable that we can make real backwards incompatible breaks. |
From the Tracing WG: Do we consider the tracing probe endpoints part of the public API and as such removals & additions effecting the major/minor bumps? What is our policy on compatibility changes here? |
I would say moving the probes from core to userland should be allowed, but in a major version bump. The primary users are enterprise that care about that functionality a lot, and moving the parts out of core may require changes to their tooling. |
I understand this sentiment, but in practice that's not accurate:
In short, I think the best we can promise is that we will be very conservative about breaking changes, and message them to community (along with remediation approaches) far in advance of the change, with specific steps to prepare for the change.
100% yesplease.
By this, do you mean no "net new" modules? For instance, if we added a In addition, I think having a stance on the cadence of releases is important as well – node got away with ad-hoc releases without fatiguing the community primarily because the releases were so infrequent, IMO. This ties back into the releases document I worked on, and letting the community know that there will be "LTS" or stable releases that bugfixes will be backported to, and at what rate those releases will be made available. I've taken a bit of a break from working on that doc. I'll revisit it this weekend and see about addressing concerns / simplifying it. Getting to see the release process as it exists now should help inform the document. |
That was a typo, should have been
I would like to entirely separate the issue of stability from cadence. We should state our policy for stability, what we are willing to do and not to do and what version number changes will correspond to those changes. If we can't comply with those commitments then the cadence will drop and we will have to invest in better tooling and automation in order to pick back up the cadence while still complying with our stability commitments.
Sure, it's software, we never know anything with 100% certainty, what this says is that if/when we do that it's a bug and entirely unintentional and that will will take every measure available to fix it and ensure it doesn't happen again. If it happens often we'll have to change our release/automation strategy to better detect issues like this or slow down releases. We do almost nothing now (although still more than we did under node.js), there are 130K modules we could automate the testing of to see if there are changes from one version to the next. Having a strong goal is important, it's what motivates us and the community to step up and create better tooling like this.
I don't think keep-alive support was a breaking change. I think that IMO
Again, I think this is something that will need to continue to evolve. The goal of these channels is to increase confidence that what we are saying (this doesn't break in these ways) is actually true. I have big concerns about allowing intentional breaks in the JS API in major version bumps. We don't know for sure yet how often we'll have to increment the major version based on v8 changes but let's be really pessimistic and say that every 6-8 weeks we have to do a major version bump. So now our version number is about as meaningless as Chrome's is at messaging big changes. Slipping a JS API change which has a far wider reach in to such a release and would be difficult if not impossible to message properly. One idea I had for a selection of big changes (like supporting ES6 Modules but giving them a more ES6 centric API instead of the current one) we would have a branch/channel for it for a long time, something like iojs-NG (Next Generation) and we get people experimenting with that channel for a long time before we announce an integration date and a version number it would land in. But even this is something we should, and I believe we can, do in a backwards compatible way without breaking any existing JS modules. I don't actually think that dedicating ourselves to not breaking backwards compatibility in the JS API is that huge of a burden. It's the same burden TC39 has and they've mitigated it by coming up with creative ways to separate the new from the old so that the new can be handled differently, we can do the same. |
I don't think that's going to work, at least not in the near term. Best case, symbol clashes would happen when io.js ships nan 1.5 but an add-on depends on nan 1.4. Worst case, there are no symbol clashes but the add-on quietly starts doing the wrong thing.
The Linux kernel counts tracepoints as part of the public API and it occasionally really hampers progress. I would advocate minor version bumps only with no promise of stability for now. |
Could we please get some sort of official stance via a blog post or something? (I take it that's what this issue is trying to get done?) I couldn't find information as to what's going on with Streams 3 and the other changes introduced in nodejs 0.12 and how it relates to io.js. Without an official statement there is the very real danger of FUD spreading. I, for example, am honestly concerned about potential continued divergence of the two projects. It could split the node community in two in a way that is bad for everyone. Request: reassuring words backed by reassuring actions, plz. |
@taoeffect we only have the ability to talk about what we intend to do. In regard to divergence between the projects we can't speak to what Joyent will decide to do or what direction they might take things. This policy is an attempt to come to a consensus then message and implement a policy or |
@mikeal Well then what does |
@taoeffect everything they just shipped in 0.12 we've been shipping for weeks. In addtion, we have a newer version of v8 and libuv (both of which are still supported, unlike the versions in 0.12). The features in 0.12 were built by people in io.js, some of them more than a year ago. |
@mikeal That's good to hear, but you seem to be avoiding the question, which keeps me nervous. The main concern is: what happens when nodejs 0.13, 0.14 and 0.15 are released with features and/or API changes that don't exist in |
I think the problem is with joyents attempt to keep the node community from moving to io.js and in doing so they are making it impossible for the two projects to be compatible. I think what io.js should be doing is working to make is suitable replacement for nodejs |
@Oteng What types of things are they doing to slow the switch? |
@benjaminProgram |
Well we certainly can't have them doing that. Bad Joyent! Stop developing the software you created for great justice! sigh... Some sort of reconciliation is needed. |
@taoeffect Definitely. |
That presupposes joyent are driving node development forward, which despite 0.12 there are no signs of happening. We can speculate this is due to the fact that the majority of the top top contributors (5 of 8?), are now working on io.js. So you're asking mikeal for a statement on if, hypothetically, joyent finds/hires developers to start pushing things forwards, and despite the node advisory board decide to go in a direction that doesn't make sense, what happens then? ... not sure it's a reasonable question to ask. And regarding reconciliation. The driving members behind io.j says they hope io.js, one day, when joyent gets their act together, will be merged back into node. |
@algesten I appreciate the rosy optimistic picture you are trying to paint, but let's keep our heads here in reality and be aware of the potential significant harm that can be done to the community by ignoring this question. Note that the question has still been ignored. It has not been answered by your post either (which dismissed the question). Note also that if we took your line of thinking as the reality of how things are then Joyent souldn't have had any reason to release 0.12 because supposedly, according your narrative (paraphrased) "iojs is the future and should one day be merged back into node". But they did release it. If everyone keeps turning a blind eye to this issue it will cause harm the community. Please consider the worst case scenario and have an answer for it. |
@taoeffect we aren't ignoring it, it's just literally impossible for us to tell you what someone else will do :) All the harm you're talking about will be the result of someone else's actions so there isn't much that we can do to alleviate your concerns other than to stop shipping code. |
We're now back where we started. Let's break this loop.
|
From: http://thechangelog.com/139/
Consider the above comments some community feedback. 😉 Would you consider, as part of the roadmap work, polling the community to see whether they want reconciliation or further divergence? (Edit: Or similar / related questions?) |
@taoeffect we worked w/ Joyent for 6 months before forking, we are still trying ;) it isn't public at their request. |
@mikeal What is not public? |
Added notes about long term support and a proposal for how to better handle unsupported versions of v8. |
I'm not sure 100% backwards compatibility is the right strong goal for io.js. While we absolutely need tooling to start seeing how changes in core affect the ecosystem at large, I don't think that seeing breakage should preclude those changes. To re-hash that anecdotal example: keep-alive broke tests at npm, IIRC, but the ecosystem is healthier for the change overall. I may be doomsaying a bit here, but: if we never make breaking changes, it becomes harder to onboard new contributors effectively. They will have an entire project-history's-worth of backwards compatibility to learn before they can navigate the project and make meaningful changes. It becomes harder to document effectively, because old APIs don't die, and efforts have to be made to point newcomers to the "right way" to use the project. It becomes harder to make changes in general, to navigate the maze of backwards compatibility. When I see "no breaking changes in the JavaScript API", I see Python: if we can't fix problems for fear of breaking downstream code, the natural recourse seems to be to spread the backwards-incompatible APIs across a new set of core modules. If we state how we deprecate APIs and how we delete them, we make a promise of stability to our users that stands less of a chance of stalling the project, and is more realistic overall. We can still state what APIs are off-limits, but on a more granular scale. We have to strike a balance between our users' investment in io.js versus our users' io.js code. A 100% backwards compatibility policy protects the code to the exclusion of the investment. Iterating and moving io.js forward protects the users' investment. A stated deprecation policy, I think, gives us the best of both worlds. |
@mikeal I'm with @chrisdickinson, I don't think that's a good idea or even feasible. A more constructive approach is to outline a policy for deprecating and removing broken features. To take the sys module that you mentioned elsewhere as an example: the reason it's still in core is that it's not really broken and has zero maintenance and run-time overhead. Compare that to domains: domains do have a significant maintenance and run-time cost and are good candidates for deprecation (already happened) and removal.
What is the rationale for a separate repository? joyent/node lands patches in the in-tree copy of V8 and that seems like a reasonable approach to me. It's less work than maintaining a second repository. I have mixed feelings about pledging support for versions of V8 that upstream has abandoned. Back-porting fixes quickly becomes infeasible due to the ever-growing delta. |
I don't think we are sharing a vision for what "backwards compatibility" means. More accurately, I don't think we're sharing a definition of what the scope of the public API is that we're dedicated to supporting. The
Those aren't breaks in backwards compatibility. We aren't going to mint the exact text of every error message forever, or refrain from improving keep-alive support or even changing the default to use keep-alive so long as we can do so without altering the public function signature and expected resulting output. Coming back to streams, I think that streams1 -> streams2 was a backwards break and is the kind of thing we should dedicate ourselves to avoiding. But, streams2 -> streams3 did not break or alter prior behavior in a breaking way and should not be considered a breaking change.
Think back to this Also, this is the goal and should drive more than just core changes. The roadmap includes mention of better tooling to understand how much of the ecosystem a change might break and how much uses a particular API.
Why are we still pretending we can do this? Let's be honest, we're not ever going to be able to remove
All language is subject. A hosting company that is always up is actually up 99.99% of the time. If we understand how many people use an API and how much we might break by making slight alterations we can effectively mitigate the result of small changes without scaring people by messaging that as a "breaking change." If you take the most conservative view here you could say that the new error messages from libuv are a breaking change but that isn't what we're talking about now and it isn't what anyone expects.
Statements like this really do scare people that have node in production. While this is very true, the API is terrible and has a bad impact, can we really break a significant portion of the module ecosystem and production applications to get rid of it entirely? What I suspect we'll do is continue to reduce the impact of its use. Hell, I could even see us turning all its APIs in to noops but to actually remove the module entirely to the point where everyone who was pulling it in will see an exception seems like a situation where the cost will always be too great.
What I'm trying to do here is separate and parallelize the efforts of LTS and current development. The work of back-porting fixes is a burden we don't want to put on the majority of contributors, and definitely shouldn't be somewhere that you're spending your time. But, there are a number of contributors from companies with large financial incentives to keep older lines of node functional and secure because they have customers on them that won't switch. The only reason to break out the repo is to give the LTS people a place to do that work that they more or less own (similar to a working group) and also to make it clear when we're taking responsibility for a particular line of v8 (any versions that aren't in that repository we are effectively saying must be fixed in upstream v8). There may be a better way to organize this, it's a problem we don't quite have yet since we're so new, the real point here is that we're saying definitively "when v8 ends support we will inherit it and continue to support it as long as there is a community landing patches." |
If it would be easy or straightforward, then the fork wouldn't make sense in the first place. IMO io.js it's not aimed to be a replacement for Node itself, but for what the community was expecting from Node. In the future, Joyent can change whatever they want in Node but that doesn't mean you (or any of us) should follow that religiously. |
@chrisdickinson what do you think about these alternatives as a replace for "will not break backwards compat in JS API"
|
Some quick knowledge share so that people can see where I'm coming from. Perception vs. RealityThe reality of this project is that the code is still being reviewed and maintained by the people who have been building node for many years, we just have a lot more contributors helping now. The perception however is that we are a new project with a new v8 and that we have diverged from node.js. The feelings and sentiments people have about compatibility between node.js versions has not ported to us, at all. The node.js project has no official written policy about any of this and has made some big mistakes we're still living with (streams2, domains) but the perception is that they are more stable and more dedicated to stability. Whatever we come up with needs not only to alleviate people's concerns about this but make it clear that we won't make the mistakes node.js has made in the past. Two important ones come to mind:
The node.js project's strategy of marking specific APIs with varying degrees of stability does not live in reality. The cost of changes is directly proportional to the number of modules and applications they will break. The stated "stability" of an API has far less bearing on how much we can change it than the number of modules in the ecosystem which decide to depend on it. npm napkin mathI understand the attraction to "reserving the right" to deprecate an API but we all know that there is a threshold of modules/applications we are just unwilling to break no matter how bad the API is that they are dependent on. Your initial impression might be "how many modules can possibly be dependent on this?" I'll have real numbers soon enough based on actual code analysis but let's just do some basic guess math. The last time I checked (9 months ago) the average dep list per package was a little more than 8 but growing every quarter (yes, not just the overall package ecosystem is growing, even the average dep tree is also growing). That means that every package has an average of 8 deps, which in turn have an average of 8 deps, and so on. So, say we want to get rid of domains and we figure that only about 1% of the packages in npm actually use it (roughly 1,300 packages today). Removal won't just break 1,300 packages. Potentially, removal could break (1,300 * 8 * 8) or 83,000 packages (more than half the registry). This is, of course, not entirely accurate. Core packages that have been around longer are more likely to be depended on, as are npm packages themselves so newer APIs will have a much smaller reach. This also doesn't account for overlap (deep deps depending on the same packages). But, this should give you an idea of how big a role these deep dependency trees play in the cost of deprecations. |
@mikeal ^ that should be on medium too to get more visibility |
@a0viedo I'd like to reach a conclusion here about stability before I write something like that up, but it will definitely happen :) |
Part of the reason we pretend to be able to deprecate things is that the tooling to see the results of our actions isn't there yet. If we had that in line we'd be able to make better decisions about what to deprecate/delete, and when to do so. We are, and have been, flying blind in that respect for a very long time, so our decisions in that realm tend to be ultraconservative. Given the opportunity to judge the results of our options with hard numbers would allow us to be more nuanced and data-driven than intuition-driven.
The other side of this is that the npm ecosystem rapidly heals around breakage from core – even faster when we telegraph it. I'm not saying we would, for example, delete sys immediately, but we should message ahead of time through deprecation notices and the blog / release notes that these things will be going away. I don't want to pile up breaking changes and eventually be forced into a Python3 situation, where the only way to clean up the codebase is to make breaking changes in bulk. The NG solution is interesting, but it's a solution we only get to use once, which means we have to get the entire reworked API right the first time it's released. I don't like those odds: good APIs evolve, they aren't constructed in one fell swoop, except in rare, lucky cases. The idea of splitting the codebase for NG is also worrisome – NG sounds like another v0.12 branch. I'd rather iterate on the NG concepts behind feature flags, and get that functionality out into all io.js users hands quicker (and see the breakage in core faster!) than to develop it on a separate branch.
I agree that we need to alleviate people's concerns, but it's nearly impossible to tell a good idea from a mistake with certainty until it's already implemented and in people's hands. We should own up to that – by stating that we will, when necessary, own up to API mistakes. We commit to cleaning them up, and giving clear, repeatable instruction on how to migrate away from those APIs when they happen, whether that be through compatibility modes via require.extensions,
I'm advocating for something like the following: "io.js is a conservative, stable project. Changes will be judged based on their value relative to the breakage they could introduce in the ecosystem. Breaking changes will not be introduced without going through a widely-communicated deprecation process, giving downstream code ample time and instruction on how to adapt to the new codebase. Breaking changes will never be introduced in bulk. Frozen APIs will only accept breaking changes for security fixes." |
+1 |
This does not fit on a slide deck :( |
We tried to do exactly this years ago and had to back it out. That was when npm was a quarter the size it is now. What exactly has changed where we think this would work now? We did a full cycle with warnings, spent a ton of time letting everyone know it was going away, but it didn't matter, it broke too many people to pull it out so we didn't. Whatever we might think about the technical merits of of keeping or removing an API the largest consideration about if we can actually remove it will be how may people we break.
I don't think this is true. Breaks in compatibility between versions persist for quite a while because of the same deep dep map math I mentioned earlier. No matter how fast we get the maintainers of packages to fix themselves it still takes a ton of time to get all of the people depending on them to bump their required versions.
I don't think this is accurate either. First of all, we have an undefined amount of time to work on the new API in a branch with only nightly releases where we can change and break compat whenever we like. We also have the option of building the new stdlib the same way Most importantly, this isn't really a "one time thing." This is actually the latest mechanism in a history of mechanisms TC39 has been using to bring the language forward. It's just another way to define a set of future code that falls under new rules like "strict mode." 5 years from now we could find ourselves using a similar method if the standard style of JavaScript changes dramatically enough and we won't have to make such a drastic change unless it does. Also, if you want to come up with a better way to handle breaking changes in a way that won't break the ecosystem you'll have a new shot at it when we build NG :)
Do you have an example where we were actually able to remove an API that we all know was a mistake? I can't actually think of one. We certainly should own up to the fact that these are mistakes, I think we are doing that with
This isn't something we can message properly. I understand what you're saying, because I'm in TC meetings and I know all the people involved and so I can trust it, but someone who isn't familiar with this project doesn't know what this actually means. Their question is simple: "are you going to break this application that I just wrote?" And we want the answer to be something that makes them feel comfortable enough to build their app on this platform. I don't want to lie to people, but we need to find a policy here that we can actually message well. Small changes in error messages and defaulting to |
How is this for a statement:
Notice the use of the language removed. Being present doesn't mean it is still supported, Of course, if we make those kinds of changes we'll need to bump the major version. |
I think io.js should delete APIs that were mistakes. Don't do it every month, but do do it every year. Too often and people hate you. Too infrequently, and people grow to assume DOS3.1-like stability, and develop a culture of not accepting any breaking changes (python3, I'm looking at you). Its a delicate balance, maybe, but ruby and lua break with big new releases, and the community accept it, as long as the reasons are clearly articulated, and the changes are obviously improvements. node moved too quickly from rapid exploratory API development to frozen-in-amber API, IMHO. 0.8, 0.10,0.12,1.0... we've had a long run of API frozenness, lets move on before ancient mistakes are frozen in place forever. Unlike other languages, node/io.js has the option of leaning heavily on npm to deliver features, in particular, that multiple versions of modules can be used simultaneously. Another approach would be for io.js to reduce its API to something minimal, but given the rate of feature addition and where it started, io.js is pretty far from minimal... we'd have to delete domains, streams, cluster, and probably http and https at least to even pretend to be a minimal async io core. Perhaps not a popular way to go, it would make it difficult to write pure io.js code of any kind without pulling in deps from npm, but it would give both core and user-land the freedom to innovate. |
Closing here, continued discussion will need to take place on #886 |
Something that is coming up over and over again is fear about the stability of io.js between versions.
Because we made such a big jump in functionality from 0.10 to 1.0 people fear that we broke reverse compatibility. The increased pace of releases only feeds in to the fear that we are going to continually break people's applications and parts of the ecosystem.
As we build the roadmap it's important that we have a clear policy about what we will and will not break and what signals we intend to give in those releases to signal the changes.
Here's a starting point, I'm sure it will drum up a bunch of feedback and we will need to continue to iterate on it.
Stability Policy
io.js will not break backwards compatibility in the core JavaScript API.
io.js will will continue to adopt new v8 releases.
nan
the minor version of io.js will be increased.
nan
the major version of io.js will be increased.
minor version number will be increased. TC39 has stated clearly that no
backwards incompatible changes will be made to the language so it is
appropriate to increase the minor rather than major.
No new API will be added in patch releases.
Any API addition will correspond to an increase in the minor version.
Long Term Support
iojs
intends to support old version as long as community members are fixing bugs in them. As long as people at committing bug fixes and improvements that don't change or add API we will push patch releases.legacy-v8
When the
v8
team stops supporting a version that a prioriojs
release depends on we will create a branch iniojs/legacy-v8
. This branch will be used to continue to land fixes in unsupported lines of v8. These branches will be pulled in to future patch releases ofiojs
.The text was updated successfully, but these errors were encountered: