Semver is a logical and straightforward versioning specification designed to prevent “dependency hell.” The good news is that many projects do adhere to Semver, or at least something pretty close to it. While being generally beneficial, it inadvertently creates a new problem: Developers are hesitant to increment their projects to 1.0.0 and stay in 0.x.x for a very long time, and possibly forever. Many open source projects languish in the 0.x.x state because the developer lost interest and stopped working on it. This stifles community adoption because it means that a stable public API was never defined.
Why do so many projects fail to reach 1.0.0? According to rule 4 of the Semver spec:
Major version zero (0.y.z) is for initial development. Anything may change at any time. The public API should not be considered stable.
This means that the developer isn’t obligated to follow any rules with regard to the changes they make to a codebase. They are free to add, remove and completely change functionality with breathless enthusiasm. As a developer, I can tell you that this is quite a bit of fun. 0.x.x allows you to experiment and try new ideas. Once you hit 1.0.0, though, the fun is over and you need to follow the rules (of Semver). All changes must be carefully considered, justified and documented. Any incompatible API changes require a major version bump, which increases the potential for user base fragmentation. Version 1.0.0 is where a project grows up and discovery and experimentation tend to subside. It’s not hard to see the appeal of staying in 0.x.x forever.
What, then, is the drawback of 0.x.x? It means that a project cannot be trusted. It would be unwise for a business-critical application to have a dependency that is young and prone to significant changes at any time. It also indicates that the dependency project simply isn’t done and might not be ready for use. Part of getting people to use your work is getting them to trust you as a developer, and the version number plays a part in gaining that trust.
When to move to 1.0.0
Knowing when a project is ready for its first stable release is difficult and depends on the project. Small projects may be worth stabilizing after a few iterations, and larger projects may take a few years. Backbone.js, for example, took about 2.5 years. My own project, Shifty, took about that long as well.
Determining when a project should be considered stable isn’t a matter of time, it’s a matter of maturity. Most projects eventually reach a point where significant changes become less frequent and the development direction becomes more clear. If not, that might be a sign that the project needs a clearer focus. In any case, it’s the point where the code becomes less volatile that 1.0.0 should be considered. However, tagging the 1.0.0 release too early is even more harmful than waiting too long.
One way to guage when a project is stable is by monitoring how others use your code. If you’re lucky, users will tweet or email you questions about your project, or blog posts will be written about it. More likely, you’ll have to find alternative approaches to learning how others use your work. In my case, I do Github code searches for projects that use my libraries. It’s not glamorous, but it gives me insight into how my projects get used in practice and how I can tailor my APIs to suit real users’ needs.
A case study: Kapi
My biggest failure with Kapi is that I didn’t wait for real user feedback. I built what seemed like an ideal design in my head, but it was never validated by actual users.
I ended up scrapping Kapi and went on to build Rekapi, which is designed to provide similar functionality to Kapi, but with a better development process. Currently, after over two years in development, Rekapi is still 0.x.x (though I will be focusing on wrapping up the 1.0.0 release in the near future).
Misconceptions about 1.0.0
For me, a 1.0.0 release has some unnecessary baggage associated with it. I tend to associate 1.0.0 with a finished project, including tests, documentation, a nice landing page, and a lot of sample code. While all of that is certainly important in its own right, these extra components of a project actually have nothing to do with the version number. The version number is a reference to the state of the API, not the state of the project. Semver doesn’t state any requirements for the quality of the documentation, it simply requires that it exists. It also doesn’t have any rules for tests, sample code, demos, a logo, IRC channel availability, or any other nice-to-haves that open source projects often provide. 1.0.0 is just a statement about the stability of the API — you are free to put off creating the extra content until whenever you get around to doing it.
This isn’t to say you shouldn’t writes tests and tutorials, they are invaluable for guiding your API decisions. Just don’t let that be what prevents your 1.0.0 release from ever happening.
Importantly, it is completely reasonable to increment the major version number. Emacs is currently at version 24, and Chrome is in the 30’s. You are allowed to make public API changes after 1.0.0, just do it judiciously and adhere to the rules of Semver.
Don’t forget to ship
With all things in software development, shipping is key. In open source, tagging the 1.0.0 release is comparable to shipping a final product. It’s natural to want to iterate on something endlessly, working towards that state of perfection that’s just out of reach. But every so often, we as developers need to take a step back and consider if what we have in front of us is as good as it needs to be. If it is, then it’s time for 1.0.0.