New Versioning Scheme for React
facebook.github.io
facebook.github.io
The main issue with getting hung up on "what is a 1.0" or "when is this 2.0?" is that even if you finally make sense of it for YOURSELF, everyone outside has such a different interpretation that its meaningless no matter what. However, semver for engineering changes has meaning no matter what. Why hurt your users by introducing a breaking API change in the minor category just because "it doesn't feel like a major change"?
I wish we could just rename version to build, have it be semver and be done with it. Then version can be whatever you want and is completely ignored by computers and engineers. Call it version 1.0, version dog, version whatever "feels" right, while we start moving to a world where we can start maker safer decisions.
I wish semver simply moved all digits up one place. The second digit can then mean 'api break', whereas we can easily use the first for marketing purposes.
0.9.9 -> 1.0.0 means the opposite of 1.9.9 -> 2.0.0 - the former is an observation of stability ("things are so stable we can leave the 0.x.x series"), the latter is an active statement of a breaking change ("we can't honour the 1.x.x API any longer"). Lots of projects miss the window somewhere around the 0.3.0-0.7.0 versions.
We badly need a Semver', which is identical to Semver but starts from 1.0.0 and removes the 0.x.x rule. React is basically retro-fitting Semver' into their project.
They realized React is _already_ used in production, so it should _already_ be 1.0, and they should be using semver so consumers know when there are breaking changes between versions and when there aren't.
They did exactly the right thing.
The semver doc already says:
> If your software is being used in production, it should probably already be 1.0.0. If you have a stable API on which users have come to depend, you should be 1.0.0. If you’re worrying a lot about backwards compatibility, you should probably already be 1.0.0.
But it is true that this is frequently ignored by people who otherwise think they're doing semver.
I guess _one_ way to deal with that would be to remove "0.x" from semver altogether -- the first version you are allowed to release is 1.0, and it must follow semver rules.
But there are plenty of people who don't use semver at all, that would just increase if you removed the availability of pre-1.0 unstable releases.
I wish everyone used semver, and I wish everyone who said they were using it actually were using it, and I wish everyone using it followed that part about "If it's being used by tons of people in production and/or you are thinking about backwards compat at all, it should already be 1.0" But what can you do.
The semver spec is good already -- I don't agree there's a "fundamental problem" with it in the area you speak of, the problem is people not caring about semver. Changing what's written in the spec won't improve people's behavior in these areas, alas.
It would be impossible for a computer to correctly bump a piece of software to 1.0.0, and humans mostly get it wrong too.
It's not always that simple, and it may not be totally objective down to the timestamp, but we can think of _many_ cases where people kept an 0.x version number _long_ after it was obvious they shoudln't be -- the authors were using it in production, they knew hundreds or thousands of developers were using it in production, they knew they _were_ thinking of backwards compatibility.
React was my prime example before now.
The problem isn't different judgements on grey areas, the problem is people completely ignoring the intent of the 0.x versioning -- so they can maybe sort of pretend they are doing semver, while not doing it at all.
The first time you realize you can't make an enormous backwards compatible change without telling anyone, or you're a jerk -- is another good milestone.
Who cares if sometimes it could have been somewhat earlier or later. I'm pretty sure if everyone actually tried, it'd work out orders of magnitude better.
If 0.x versions just "weren't allowed", it doesn't _reduce_ the temptation people have _not_ to do semver. 0.x is just a big advertisement "We're NOT using semver... yet, but plan to later. And also this software is super unstable and you really ought not to use it in production" And should be understood thusly.
The problem is when people keep using 0.x, but are clearly _not_ sending that signal. Those people should be shamed.
So, as long as it is relatively stable when bumped to 1.0.0, and later releases follow to major/minor rules of semver, it doesn't matter much.
If it the major version changes for us, the API has probably changed. If it's a minor version bump, the API has DEFINITELY not changed. Rev changes are your typical bug security/performance fixes that are limited in scope.
Who decides all this? If there's any question, just pick the more important signal of the two.
http://semver.org/#spec-item-5
http://semver.org/#how-do-i-know-when-to-release-100
But yes, developers are terrible at reading this. Just get rid of 0.X.Y.
It's a statement about hindsight, not planning. IE, if I'm wondering if can I make a 1.0.0 release even if I think the project won't have users until, 1.4.x but 1.0.0 represents a logical core, that scenario is not addressed by the "should probably already be 1.0.0" after the fact tests provided.
It's about what to do with your code as it is right now -- at every now.
>IE, if I'm wondering if can I make a 1.0.0 release even if I think the project won't have users until, 1.4.x but 1.0.0 represents a logical core, that scenario is not addressed by the "should probably already be 1.0.0" after the fact tests provided.
I don't think project authors should be worried about making an 1.0.0 in advance, that is, before they have written the code and releases several versions. At which point it comes down to the "hindsight" answer as a heuristic.
E.g. "if I'm wondering if can I make a 1.0.0 release even if I think the project won't have users until, 1.4.x" -- there's just no way to knowing whether the project will "have users" until it has.
[dev || qa || prod].[BreakingChange#].date
prod.4.2016.02.19
qa.5.2016.02.19
dev.5.2016.02.19
Useful semantic information is the real series of events, presence of a breaking change, and a statement of relative release stability.
This desire to do X.x.x series never made sense to me.
Dev is frequently the next breaking change and/or code tested solely by is creator.
QA is code going through the in-house QA process and is basically a previously nightly build which is trusted enough to be tested against live data.
Prod is the last QA promoted to production + any hotfixes.
Library changes are slow due to the need to verify we aren't breaking production systems so we frequently have a Prod that doesn't match QA that doesn't match Dev because the process can take a month for breaking changes.
Even for non-breaking changes, we generally freeze production for ~1 week if the changes are substantial enough that we might have missed something.
We can't exactly ignore production bugs for 1-4 weeks.
---
The problem with Julian Dates isn't they aren't immediately human readable which is useful for lining up what was running when.
(You could determine something like this mechanically pretty easily... if your platform had anything like "ABI specification files", the way many platforms have "dependency specification files." 1.0.0 would then be the first time you generated an ABI "lock file", that would then be used by your toolchain to fail builds that violate it across the 1.x.x series. To delete-and-regenerate the ABI lockfile would be to bump the major version.)
The real problem, though, is that many projects are too big to have a single version sum them up. People need to break components down along stability boundaries—places where rate-of-change changes—and then give versions to those components. NPM libraries are a sort-of-good example of this, though I think there might be better.
Wouldn't that discourage releasing experimental code? I think the very first public release of react was 1.0.0 and they incremented the major version for subsequent incompatible changes, the current major version would be ridiculously high. I know if I did this for experimental code I throw up on github, this would be true.
React-native was handed out via email zip files. Github exists.
> the current major version would be ridiculously high
So?
Just because code is experimental doesn't mean it doesn't need to go in a package manager or, more to the point, doesn't mean it won't benefit from having version numbers.
I can see the desire for this from a code consumer's perspective, I'll argue that this is mostly impossible. New projects often start because there's a new problem (a software architecture, a set of algorithmic tools, etc.) with an inherent learning curve. The 0.x releases reflect the inherent instability of this real-world learning process. Switching to your proposed Semver' model implies that projects must use the compatibility modes (e.g. deprecate-before-removal as this post describes React adopting) of more mature software before their ideas are even partially baked. Many 0.x-era updates (e.g. x++) are near-complete rewrites of the API or sometimes even the entire nascent codebase. I'll hypothesize that a major contributing factor to successful projects gaining wide adoption is the ability go through that vital period of rapid churn.
The idea of 0.x.x reflecting a level of instability not reflected by MAJOR version bumps is cute in theory but broken in practice.
That's not a problem with semver. That's a problem with these projects not being stable and being continually changing.
If after a period of rapid development a project has been stable, and with no major bugs for months, with only minor changes, they can just as well jump to 1.0.0.
Not that it really matters, I guess.
I've been burned badly before by breaking API changes in patch releases. (Rails 2.4.5). If you're not afraid of bumping the major number on even a minor API change, then it makes it more likely that you will actually do so rather than paying lip service to the idea of semver.
So, contrary to what spicyj is saying, to me it seems to create the most confusion in the long run at the expense of addressing some short-term concerns ("people already call it React 14"). I'd much prefer they switched to 1.0.
Don’t forget Facebook has a large React codebase so it cares very much about automating migrations.
If React switched to 1.0, with some breaking changes every three months, it would be 14.0 again in a couple of years. Then googling for tutorials would get confusing. Why not do that now?
I like the upgrade paths but can you really say with a straight face that an API is stable if the code you write could be invalid a few months later? That's a maintenance nightmare!
Are you using React? I’m curious if this is your feedback on the pace of changes, or if this is just a guess.
In reality React API surface area is pretty small so most changes are automated by codemods. Codemods are programs that modify your source code. They work pretty well because Facebook uses them on a large scale.
Not everything is covered by codemods but generally the feeling I get from talking to the community is that React moves at an acceptable rate, and changes take about a day to apply once a three months for most apps. Deprecation warnings also give you several months to fix use cases that will be unsupported in the next version.
In return, this allows React to become a better library and not stagnate. I see your point in theory but please talk to the people using React, and you might find that it is not a problem in practice.
Once every 3 months is too frequent. Imagine curl broke compatibility every 3 months and you had to relearn curl. How terrible! I'm pretty sure you'd use something else after a while.
I'm not saying React should be as stable as curl, but it should be striving to become that. The JavaScript community loves to have these eternally evolving libraries that are never actually stable and that's not good for anyone. You should have a long term plan that says "we still don't know what this library should be, but within 2 years we should have it figured out". In reality it feels like JS libs only become stable after they've been abandoned.
Every three months might be too often for a tool like curl. In case of React, the community seems to be happy with the tradeoff between moving forward and keeping the old code working.
You might want to ask a few people who use React to draw the conclusions. I talk to a lot of people in the React ecosystem, and so far the feedback I heard is that updating React has been the least of their worries, compared to some other libraries in the ecosystem which are far less stable.
Personally, I updated a fairly large (~1000 modules) app from React 0.11, to 0.12, to 0.13. After the ecosystem catches up and libraries release compatible updates (if they need to), it always took less than a day to upgrade. Doesn’t seem like a big price to pay for avoiding stagnation and actually improving the library.
And I wasn’t even using codemods which React team ships (and widely uses internally at Facebook). Codemods just convert your code through most of the API changes automatically.
Yes.
> Every three months might be too often for a tool like curl.
Why should a tool for creating dynamic HTML be held to a lesser standard? I wouldn't expect the level of stability that curl has yet, but I would expect it to be an eventual goal of the project. The reason why we build abstractions is so we can eventually stop worrying about a problem; that can't happen without stability.
> You might want to ask a few people who use React to draw the conclusions. I talk to a lot of people in the React ecosystem, and so far the feedback I heard is that updating React has been the least of their worries, compared to some other libraries in the ecosystem which are far less stable.
That's because you talk to other enthusiasts who are happy about changes. Try asking people outside of the React Slack channel for a wider perspective.
I've had people complain on my projects about upgrading apps using APIs deprecated 2 or 3 years prior. And I feel genuinely bad about it, because if they are having to justify spending 3 or 4 days refactoring their app (which is hard to do in a lot of companies) because I made an API mistake 3 years ago... I feel bad about it. We should strive for better stability.
If React 15 was good enough for you when you started using it, it doesn't necessarily fundamentally stop working when React 16 ships.
No, but your project is seldom 100% finished either. So as you do minor changes to it, and want to use some new lib, you find out that it's not compatible with your old version.
And libraries stop get maintained too -- and when you finally try to make the conversion it will be harder the longer you have waited, because aside from porting your code to all new React stuff, you'll also need to find replacement for all those libs at once (not piecemeal, which would be the case if you kept the project up to date faster).
This could also happen for all kinds of external reasons too -- e.g. you use a third party service and they change their API. Or you update your OS and your old libs suddenly stops working. Or a browser deprecates some feature (like Object.observe that Google warns that it will be removed on March).
- Version numbers are now little-endian
I wish many of these libs could stick to an api instead of needing every piece of new Javascript hotness every version. =/
Facebook has a large and growing React codebase, and they use master version of React. Therefore making migrations easy is in its best interests.
Community projects like React Router move faster but this is not something the React team can help you with. If you don’t want to keep up with the breaking changes there, you can wait for the project to stabilize. For example, you can use Backbone Router which hasn’t changed for years.
Finally, if you use something as experimental as hot reloading, please expect it to be tricky to set up until it’s part of official React. This is very experimental territory and there is so much work involved in just making it work that making it stable and easy is not a priority yet.
Better late than never, I suppose, but I just don't understand the pointless sentiment that results in waiting to release a fabled "1.0" release.
With Symfony, major version changes are not there to break things or bring in tons of new stuff. Instead, it just removes BC layers for stuff that has previously been working but deprecated (with appropriate deprecation warnings).
This makes it easy to switch to a new major version: simply fix all deprecated calls and upgrade, done. At least that's what I experienced moving a project from Symfony 2.x to Symfony 3.x.
> Therefore, we're committed to making it easy for most components and libraries built on top of React to be compatible with two major versions at the same time. We will do this by introducing new APIs before completely removing the old ones, thereby avoiding those cliffs.
As long as they provide deprecation warnings for APIs that will be removed in the next version, it'll work exactly like you say.
I have no idea why it has never occurred to me to ask the following question [1]: how is version numbering done in disciplines other than software?
Software is young compared to most engineering disciplines. Surely this problem was solved long ago in non-software disciplines and their solutions have been tested by decades, or in some fields even centuries, of practice.
[1] idiocy is a plausible theory
Use ISO 8601, and add whatever flags you need, and establish some minimum standard vocabulary the AI can search for. :>
Development #D:
"2016-02-16T15:17:32+00#D#API"
Release #R:
"2016-02-19T17:37:21+00#R#API"
Now anything can look for dates to figure out the age of whatever it is that's running on the system, and maybe even warn about it, disable it, exploit it, etc.(AmigaOS encouraged a $VER: prefix you could scan for, IIRC.)
If you still want a custom numbering scheme, just append it to the version string somewhere:
"2016-02-19T17:37:21+00#R#API#(1.4.2 Loopy Leopard)"
#API could mean there was a change to the API. Review your dependencies.#+API could mean a function was added, but the existing API is stable. (Unless #API was also added separately, in which case a review of the change log is needed.)
#-API could mean a function was removed. Review your dependencies.
..or whatever the syntax would be.
At a very brief glance I didn't notice the change between 16 and 19, and my eyes were drawn to the time, which let's face it, is probably next to useless.
And it also doesn't have any of the benefits of semver, like signaling breaking changes.
The format should be programmatically scanned for, and extracted, and represented in various ways; days ago, hours ago, minutes ago; sorted by newest, oldest; grouped by last three months, etc.
> And it also doesn't have any of the benefits of semver, like signaling breaking changes.
That's the function of tags. Agree on using #Fix for a corrective release, #Feature for a feature release, and whatever else makes sense. Ideally, there would be a minimum, standard vocabulary that makes sense.
2016-01-01T11:51:10+00#R#+Feature#(Semver 13.0)
2016-01-07T10:50:21+00#R#Fix#(Semver 13.1)
2016-02-11T09:31:44+00#R#-Feature#(Semver 15.0)
2016-02-20T10:20:51+00#R#Fix#(Semver 15.1)
(I'm prefixing it with Semver because it's defined.)This scheme is mainly about making the date and time an intergral part of a versioning format, which in turn makes it easy for machines to figure out the age of components, and automate checks.
Perhaps tags could then help add more information.
So just search for "$Version:" across multiple platforms; text files/scripts, videos, pictures, executables, etc.
Problems: Text encoding. A search may have to cover all variants. UTF-LE, UTF-BE, UTF-8, etc, but if written in isolation, it should be UTF-8.
There could be established standards for where to store such information, to optimize lookup for specific data formats.
1.2016.2.20
ISO 8601 is an established format.
It's better to differentiate a new format from the old, common build number formats w.x.y.z.
One of the tags could also contain the file name, or other context within [].
Syntax:
$Version:YYYY-MM-DDThh:mm:ss+00#Tag#(Custom)#[Context]
Minimum: $Version:YYYY-MM-DDThh:mm:ss+00
Minimum with your own version: $Version:YYYY-MM-DDThh:mm:ss+00#(a.b.c.d)
The +00 is to emphasize UTC time (which all of these datestamps are stored as).I suspect some people find it too verbose to use dates, but that's irrelevant; this is the minimum amount of information required for a more general versioning scheme, in my opinion.
The reasoning for the strategy is sound, but does anyone know the rough cost of leaving in the deprecated apis from the previous version, in terms of additional gzipped file size percentage? Say from 13 to 14 as an example?
Further to that, anyone know how effective various dead code elimination tools are at stripping out those unused deprecated apis, for bundled apps that don't have any dependencies requiring anything less than the latest react version?
It seems like there's a fear in making the call. Version 1 should be celebrated.
There seems to be a lot of FUD around this subject.
They choice 15 as the starting MAJOR version because people already referred to 0.14.x as "React 14", avoiding any possible naming confusion. They will remain at 15 as long as there are no major features or API breaking changes introduced.
[1] Thank you
Yeah, it doesn't sound too stable to me either. </sarcasm>
We have had React in production for almost 2 years...it has been extremely stable.
It should be clear that React is very mature, I think 15.0.0 fits.
Never. A hobby project nobody touches, an internal project at a Fortune 10 company, a huge open source project like WordPress, and a moderately successful SaaS app do not need to have identical versioning systems behind them.