DEV Community

Andries
Andries

Posted on

Semantic Versioning

Semantic version number is a special series of numbers denoting a version, but not all version numbers can be considered as semantic.

Let me explain. A semantic version number has a specific meaning in relation to the actual software being release with it.

The official document explains this very succinctly:

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

  • MAJOR version when you make incompatible API changes,
  • MINOR version when you add functionality in a backward compatible manner,
  • PATCH version when you make backwards compatible bug fixes.

Why this is important

Applying semantic versioning to the development effort ensures that consumers can rely on the version number when it comes to choose a specific release of your library/product.

Consider what happens if software products have no versions, or if the version numbers are not semantic:

  1. Scenario A

A Customer has a problem with the last library. You realize that it could easily be fixed, but between the last release and the subsequent discussion many more changes were made to the library. How are you going to fix this without introduce more instability to customer which are running an very old "version" of your library?

  1. Scenario B

You don't have a customer, but it is an internal library. All a sudden things start breaking because your team are extending the library. You cannot just pull in the last development version, or maybe you have. How do you make sure breaking/unstable changes do not leak into your project?

Following these semantic rules means that a consumer may with reasonable confidence pick any patched version, and apply it to a product in production with the same major and minor version numbers.

This scheme has some important benefits for the developer and consumers.

  • For consumers:

    • A consumer may pick the next higher minor version with relative safety to include of the latest patches and fixes work.
    • A consumer may also pick the next higher version just below the next major number for starting/developing a new feature, as this will include some new features, including the latest fixes.
  • For developers.

    • Bug fixes can always be made on the version which is actually breaking.
    • In the case of a bug reported which has already been fixed with a prior patch, means no work needs to be done, except pointing the consumer to the version of the patch fixing the error.

A simple workflow

  1. Changing the development branch to the next snapshot version
  2. Update the build version to next planned release version.
  3. Developers do their thing.
  4. Testers do their thing.
  5. The product team compile release notes of all the upcoming changes/features.
  6. You tag a release of the software in version control.
  7. Merge develop branch into master.
  8. Build release from master branch at a specific tag.
  9. Publish artifacts to repository.
  10. Start at 1 again!

How to choose a semantic version number:

From left to right:

  1. Major changes, including breaking changes to the API.

    You increase the major version if your library is the release includes breaking changes and new features to your library. Minor and patch numbers reset to 0.

  2. Adding of new features without any breaking changes.

    You increase the minor version number of the library when you add new features, but does definitely not include any breaking changes to the previous release (with same major version number). You reset the patch number to zero.

  3. Making non breaking fixes, or small improvements without breaking changes.

    You increase the patch number if you fixed a bug, or patched some code to make the library more stable.

Practical Example

Let's say your library is on version 0.1.22. As part the work for the upcoming release of the library you will just introduce a few new features. As a matter of importance you have decided to not introduce any breaking changes to the consumers of your library. This makes the choice of the next version number easy: 0.2.0.

To follow this above workflow, do the following:

  1. Update develop branch project build version to 0.2.0-SNAPSHOT.
  2. Push this update into the development branch.
  3. Everyone does their thing and merge and pull from the development branch.

At the end the 0.2.0-SNAPSHOT version will simply be changed to 0.2.0.

So after a few weeks of development and testing everybody feels it ready for the next release.

At this point, you decided to first have a few release candidates so that selective users of your library may have a chance to test upcoming features and maybe you want to incorporate and last minute changes/suggestions. So your change the version number of the library on the development branch to say 0.2.0-RC1 (RELEASE CANDIDATE 1). You may go through many of such iterations deciding to collect changes and feedback and may decide to have another 2 release candidates (0.2.0-RC2 & 0.2.0-RC3).

On release day, you perform the following on your library development branch:

  1. You change the version number to 0.2.0.
  2. You tag your development branch with a version number, for example v_0.2.0.
  3. You merge your development branch into master.
  4. You kick of your CI build chain to build and publish your library artifacts to the internal/public repository (for example a JAR, or ZIP).

Consumers may now pull your library artifacts with confidence ๐Ÿ˜€.

Top comments (0)