Introducing HashVer
Tags: python, devops, rails, webdev
Published: 2020-02-03 22:06:30

---
title: Introducing HashVer
published: true
description: Hash Versioning for Services
tags: python,devops,rails,webdev
---

I have been using a microservice like architecture at work for quite some time now ( about 2 years ). During this time I have mostly used [semantic versioning](http://semver.org) for my builds. Using docker and a staging environment my workflow was as follows:

1. Create a feature branch and pull request
1. After reviews, it is merged into master
1. Jenkins then builds a new `:stage` docker image and deploys into staging
1. After some time passes and we are satisfied with the stage build, we then prepare the next release
1. This involves updating the CHANGELOG.md, at first it was manual but then I built a tool
1. Then bumping the internal version field
1. Creating a new PR for these changes and letting Jenkins redeploy stage.
1. Then manually running a second job, which retags the latest stage image as the semantic version number and updates production

This works out pretty well and is quite an improvement over what others on my team are doing ( do not get me started on that ). However, a few things have bugged me about all this.

1. A lot of steps for a new release
1. Each release usually only had one maybe two small changes and really didn't need that much overhead
1. When going from stage to prod, we rebuilt the image after we did our testing
1. Our staging environment wasn't being used much and thus our testing wasn't significant
1. Finally, the semantic version wasn't helpful in this case ( read more below )

## Why not SemVer for services
Semantic versioning is by far the most popular and common versioning scheme out. It is very well documented over at https://semver.org and is used by countless systems such as NPM, PyPI, NuGet, etc. I recommend and use SemVer for most work, but for services, I do not.

The reason for this is SemVer aims to provide a means of safety, that is with each update you know if something will break or if its just bug fixes and is a safe upgrade. It aims to communicate a level of compatibility with other versions.

So if you are using version 1.2.0 and version 1.3.2 is the latest, you know the versions are compatible and are generally safe to upgrade. If you are using 1.2.1 and the latest is 2.1.0 you know there is at least something that may be incompatible and you will need to make changes on your end to resolve it.

But when you are working on a service presented straight to users this compatibility is largely unhelpful. A version change does not help most, if not all, users. If a new feature is added or major change is happening, you would want a large announcement to go along with it anyway. Additionally, if you merge and deploy often this extra effort of coming up with a version and updating the changelog is tedious.

## What does versioning do for you?
It is very common for sites and services to just not use any versioning at all. For example, I do not think dev.to has an explicit version number (at least, I couldn't find it anywhere). This is not really a problem, I mean, if your favorite sites did have a version would that help you as a user? No, probably not.

However, a version change achieves one big thing. It marks a new release. Think about a site you use frequently ( well, one that is also updated frequently ) how are you informed as a user of new changes? Do you get an email, notification, blog post, nothing?

See versions tie our application at a certain time with the capabilities it had. When a new version is released, there are more, less or better capabilities with it. 

## Hash Versioning
Version numbers for constantly updating services or sites are largely irrelevant but having some version number or string for every release allows us to reference old builds, see changes or diagnose new problems. ( A nice sanity check to make sure that production bug is actually a bug or if the service was never deployed ). So, I created [hashver](https://miniscruff.github.io/hashver/) which aims to build a generic version based on the date and git hash. 

These two pieces of information allow you to know approximately when the build was made which helps find stale builds and can signal the frequency of updates. The hash can be used to find the source. No need to git tag every release.

Note that HashVer is not anything too new, I have heard or seen instances where similar versions are used especially for nightly builds. But by writing up a formal definition it can be standardized and shared.

## Cool now what
Okay, so you have a version number attached to each deployment, now what?

Well, good point, this version number doesn't by itself provide any benefit to our users but we have now automated it. You no longer need to choose or guess your version numbers, what else can we automate.

Your changelog.

What about building our changelog during our build/deploy process. Include this in your final build or referenced somewhere for your users to see when and what was added or changed. You can use many tools but I created [hash version](https://github.com/miniscruff/hashversion-python) for python, [town crier](https://github.com/hawkowl/towncrier) is also popular. GitLab has built [changelog manager](https://docs.gitlab.com/charts/development/changelog-manager.html). Python uses [blurb](https://pypi.org/project/blurb/) for its official whats new page.

What else?
1. Automated announcements for big updates
1. Blog posts integrated into the changelog
1. In-app notification on updates

Once you have a place for automating release artifacts you can add many more.

## Why go through all this effort?
By including news and updates directly in your application, it allows users to take advantage of new features. How many times have you been using an application and discovered a cool feature and asked yourself "wow, this is cool when did they add this?". What about spending 3 months on a new awesome feature only to have no one use it cause it was hidden? Ever get asked about a new feature request and responded with "Oh, that is already available, and been there for 6 months?".

Version changes mark a new release. This point is your time to add as much metadata as you can in order to communicate this new release to your users.

## Okay you convinced me, how can I do this?
First, start tracking all your updates that affect the end-user. They generally do not care if you fixed linting issues or switched from PostgreSQL to MySQL. But they do want to know if markdown tables were added.

Second, automate everything. Version changes, news generation, everything. If it's not automated, it will fall behind. And we plan on making lots of changes so this has to be lean.

Finally, provide all this to your users somehow. I like to provide a link to my changelog down in the footer, it fits for my circumstances, but you do you.

Changelog updates are just one part of what goes into each release, hash version aims to provide a foundation of what steps you should, could or may take in each microrelease. ( Microservices need microreleases just saying )

Thanks for reading.