Deciding whether to go to version 1.0.0 for a crate

I have been thinking this morning about this issue. I have seen advice before advising against a premature move to 1.0.0, but thinking about it, I think if you believe a crate is working correctly, and is reasonably stable/functional ( albeit not perfect in every regard - but if you wait for that you may be waiting a long time), and is eligible ( doesn't have pre-1.0.0 dependencies ), it seems to me the right thing to do.

What good reasons are there NOT to go to 1.0.0, once the conditions given above are satisfied?

Reference is The Manifest Format - The Cargo Book

Sometimes I've seen crates that go 1.0 before their public dependencies do. It can be an oversight sometimes.

Let's say for example you think your crate is working well, but it's using num-complex's Complex type in its API. num-complex is only at version 0.4, and is relatively likely to have new versions. In this situation it's hard to say that your crate is 1.0-worthy, since it reuses num-complex in its public API.

Maybe there are situations where this is a acceptable trade-off and you'd go for 1.0, 2.0 etc anyway.

I think non-public dependencies don't really matter for if you go for 1.0 or not.

Those are the two big reasons I would say to avoid going 1.0 just yet.

I think a third, often unspoken, requirement is the willingness to actively support and maintain your crate going forward... There is an expectation that a 1.0 crate is being actively maintained, and maintaining the same open-source project for multiple years can be a massive physical/emotional drain on a single developer.

Yes, I should have put "public" in. In fact the crate I am considering doesn't have private pre-1.0 dependencies either.

My thinking is partly that it simply helps to have the three version components, without them you cannot distinguish between breaking change, an enhancement and a patch. I suppose it does mean you have the burden of issuing patches, if an outright bug is found.

A thought just occurred to me, you might (conceivably) have a situation where there is a bug, but you cannot fix it with a patch ( it is some major design flaw ), and it's best to deliberately issue a "breaking patch" to ensure people upgrade ( even if it requires changes to code). Does that ever happen? Honestly, there are issues here I have never had to think about much before.

Seems to me that any piece of software has requirements, features it has to have, call them A, B, and C. Of course there will likely be more but one should be able to list them and specify them.

When that set of requirements, A, B, C is reached and has been tested to work to some degree, why not go ahead and call it 1.0.0?

Of course there may be bugs to fix leading to 1.0.1 or 1.1.0 etc.

And, most pieces of software sprout requirements by virtue of their very existence. Or API's change with usage experience. Or original requirements, D, E, F, were postponed as they were not so necessary. When they get implemented it's time to move to 2.0.0.

It's not clear to me that having dependencies that have not reached 1.0.0 should stop a crate from reaching 1.0.0. If the crate works with a lesser version dependency and can always be built against it that should not be a problem. Surely that does not affect the API of the crate in question?

One possible issue would be a desgin flaw in the dependency that introduces unsoundness.

It's not clear to me either. I think it derives from this:

" 1. Major version zero (0.y.z) is for initial development. Anything MAY change at any time. The public API SHOULD NOT be considered stable."

If your public interface depends on something that isn't stable, well how can it be stable either? I think it's a convention, pre 1.0 you don't have to be careful about stability ( and while the minor version number SHOULD be incremented on a breaking change, the developer doesn't have to be super-careful, whereas after 1.0 he or she should be super-careful. There is that expectionation. ).

Another thing I am not entirely sure about. From

https://doc.rust-lang.org/cargo/reference/manifest.html#the-version-field

"In Rust, breaking changes include adding fields to structs or variants to enums."

Well, isn't this an over-simplification? Doesn't it depend on the details? If a struct has private fields ( so cannot be constructed outside the crate ), is adding a new public field a breaking change? ( I may be missing something, but I don't see how it is. ).

If a struct can be deconstructed:

let Complex { re, im } = complex_number;

then it's a breaking change to add additional public fields. So it applies when the struct already has zero or more public fields and no private fields.

I would say yes, it always depends on details.

If you think it’s ready, just go for it. Your “what if” scenarios can be assuaged with good test coverage. If there’s a problem afterwards you can fix it. It’s not a crime to make mistakes and learn from them.

And let’s be honest, version 0.1.973737 is just inscrutable and defeats the purpose of semver. 1.0.0 tells me that the author wants to offer stability. I cannot reasonably ask for more.

1 Like

Once the API has been stable for a few months, there are users, and no known major bugs, please go to 1.x.x. We had a previous topic on this, discussing the problem of too many major crates upon which others depend being at 0.x.x. You can still fix bugs after 1.x.x; it's more of an announcement that the external interface is done for now.

1 Like

Cargo doesn't follow semver strictly. The convention you mention is required by cargo.

2 Likes

One reason to avoid going to 1.0 is to avoid needless churn. If you've got a perfectly working 0.13.4 why introduce a false server incompatibility by spelling what could have been 0.13.5 as 1.0? It causes crates that don't update their Cargo.toml to miss out on bug fixes, and makes it likely that binaries will ship with two versions of your library, as the ecosystem catches up with your lurching change.

Of course, if you're making a breaking change anyhow, then this won't apply. But many crates that are "ready" for 1.0 no longer make breaking changes.

1 Like

I have been reading the FAQ https://semver.org/ it's quite helpful ( but buried a long way down ). It starts:

How should I deal with revisions in the 0.y.z initial development phase?

The simplest thing to do is start your initial development release at 0.1.0 and then increment the minor version for each subsequent release.

How do I know when to release 1.0.0?

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.

This can be alleviated by uploading a 1.0 crate, and a 0.13.5 crate that depends on 1.0 and reexports everything from it.

I'd argue every crate that is currently sticking to 0.x.y because of such concerns about 1.0 should do so.

3 Likes

Testing was mentioned only once above here, so I'll mention it again. If you think that your crate might be ready for 1.0, take a look again to see how good your test coverage is. Unless you're actively trying to reason about and test for every corner case then you don't really know what the corner cases are.

Other than that, it's a matter of deciding that, here, this is where the public API is considered finished.

Once again, cargo has additional requirements beyond semver. Quoting semver for how "relaxed" something can be is unhelpful.

Interesting discussion. But in my opinion, coming from JavaScript land and having been burned a few times by "patch" versions with breaking changes (people make mistakes), I have resolved to always pin whatever version is current while in development and update only after extensive testing.

Semver is a nice indication of what the author thought they were doing, but that's all it is and should not be relied upon when reliability really counts.

More to the point of this discussion, especially in the rust ecosystem where authors seem overly cautious about moving to a 1.x.x version, again in my opinion, the version number of a crate doesn't really carry much weight, some but not too much.

I consider the responsibility for reliable software falls on the developer. If you use other people's software in yours, that in no way absolves you of that responsibility.

Yes, I see it as a reason to go to 1.0 early so you don't end up with this dilemma. Before you have users ( and with Rust / crates . io you don't even know if you have users or not ). I suggest if there is even a possibility the crate is useful, and you MAY have users, you SHOULD be on 1.0. People seem to be turning it on it's head, and we have these perfectly good, useable crates that never make it to 1.0 even after years of nothing changing, and with hundreds of users.

It seems like an impossible standard? How can I apply this to ndarray, for example? We'd presumably be talking about version 4, 5, 6 etc by now and not gain so much from that..