Project Ramon

A learning journey from a Ruby noob perspective

An Introduction to Semantic Versioning

semantic_versioning1_header_img2

Hello and happy Monday!

Today I’ll be sharing my examinations into semantic versioning.

Most of my findings came from other informative blogs, so I’ll also include the links to these resources throughout this post.

What is Semantic Versioning?

I like this explanation from Red Hat the most:

The basic principle of semantic versioning is that an increment to a major, minor, or micro part of a version signals a particular degree of compatibility or incompatibility with previous versions of a package.

If we head on over to the Semantic Versioning 2.0.0 site we can gain more insight into it’s application.

Here’s a summary from their site:

Given a version number MAJOR.MINOR.PATCH, [we] increment the:

  1. MAJOR version when we make incompatible API changes,
  2. MINOR version when we add functionality in a backwards-compatible manner, and
  3. PATCH version when we make backwards-compatible bug fixes.

Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format.

Why Semantic Versioning?

These next two excerpts also comes from the Semantic Versioning site under the Introduction header.

The Problem:

In the world of software management there exists a dread[ed] place called “dependency hell.” The bigger your system grows and the more packages you integrate into your software, the more likely you are to find yourself, one day, in this pit of despair.

In systems with many dependencies, releasing new package versions can quickly become a nightmare. If the dependency specifications are too tight, you are in danger of version lock (the inability to upgrade a package without having to release new versions of every dependent package). If dependencies are specified too loosely, you will inevitably be bitten by version promiscuity (assuming compatibility with more future versions than is reasonable). Dependency hell is where you are when version lock and/or version promiscuity prevent you from easily and safely moving your project forward.

The Solution:

As a solution to this problem, I propose a simple set of rules and requirements that dictate how version numbers are assigned and incremented. These rules are based on but not necessarily limited to pre-existing widespread common practices in use in both closed and open-source software. For this system to work, you first need to declare a public API. This may consist of documentation or be enforced by the code itself. Regardless, it is important that this API be clear and precise. Once you identify your public API, you communicate changes to it with specific increments to your version number. Consider a version format of X.Y.Z (Major.Minor.Patch). Bug fixes not affecting the API increment the patch version, backwards compatible API additions/changes increment the minor version, and backwards incompatible API changes increment the major version.

Major, Minor and Patch Versions in Detail

I found this blog post by: Robert Reiz very descriptive in it’s explanation of when to change MAJOR.MINOR.PATCH versions in our software projects or libraries.

Patch Versions

Let’s say you are the maintainer of an open source library, an XML parser, with the version number “1.0.0”. And now you want to release a new version because you fixed some bugs.

For the bug-fix you:

  • changed some method implementations,
  • but you didn’t add new methods
  • and the changes are backwards compatible

In that case the new release is just a patch. That means you would update the patch version in your version string. That would be “1.0.1“.

Minor Versions

Now let’s say you want to add additional features to your software library. The current version “1.0.1” can read XML files from hard disk and now you want to add a new feature which allows to read XML files from the internet. For this new feature you are adding new methods and you extend the public API of your new library. That’s why you count up the minor version in your version number. So the next release looks like this “1.1.0″. And every time you count up the minor version you have to reset the patch version to 0.

Major Versions

During your work on this XML parser you learned a lot of new stuff and you decide to completely refactor the library to make it even more awesome! During the refactoring you change the public API on the library and the new version is not backwards compatible anymore. That’s why you release version “2.0.0″. It’s a major version! Every time you count up the major version number you have to reset the minor and patch version to 0.

People who rely on your XML parser can now immediately see that the new version will, very likely, lead to compilation errors and break their build. Seeing the version number they now know that they have to be careful with the update, they have to check the change logs and the migration path.

Semantic Versioning in the Real World

I found these next examples from this blog post by: Jurgen Van de Moere

He shows some nice illustrations of how to version our initial development staged projects as well as some examples of using Git tags to version our repository. Check out his full post to get the full educational experience.

Here are a few illustrations from Jurgen’s post that demonstrates semantic versioning in the real world.

Some unofficial conventions

0.y.z (a major component of zero) is generally used for initial development
When your code is used in production, you should increase to version 1.0.0 (a major component of one or higher)

A real world example

v0.0.0 # New project
v0.1.0 # Add some functionality
v0.2.0 # Add other new functionality
v0.2.1 # Fix bug
v0.3.0 # Add some functionality
v0.3.1 # Fix bug
v0.3.2 # Fix bug
v0.3.3 # Fix bug
v0.3.4 # Fix bug
v0.4.0 # Add some functionality
v0.4.1 # Fix bug
v0.4.2 # Fix bug
v1.0.0 # Code is being used in production
v1.1.0 # Add some functionality
v1.2.0 # Add other new functionality
v1.2.1 # Fix bug
v2.0.0 # Implement changes that causes public API of code to become backwards incompatible
...

Semantic versioning with Git

Git uses the concept of tags to assign versions to your Git repository:

To view the available tags of your repository:

git tag

To add a tag to your repository:

git tag -a v0.2.4 -m 'my version 0.2.4'

To push tags to a remote repository e.g. to origin:

git push origin --tags

Conclusion

Semantic versioning appears to be just what I need to keep my application from becoming dragged into the clutches of dependency hell.

Finally, here is a list of some additional resources I used to educate myself on this topic:

semantic_versioning1_header_img1

Stay tuned…

Advertisements

Categories: Uncategorized

2 replies

Trackbacks

  1. Semantic Versioning: Intro to the Git Branching Model | Project Ramon
  2. Git Branching Model [Support Branches]: A Look at the Release Branch | Project Ramon

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s