Category Archives: Design

Semantic Versioning for the Enterprise

There is a lot to like about the Semantic Versioning system as documented here:  http://semver.org/.  Having the ability to easily control when dependency changes are picked up by your builds without the heavy burden of managing static dependencies is important for efficient software configuration management.

The semantic version system works well as designed when there is only one active stream for each dependency artifact – with stream being defined as the set of branches related to a single development initiative.  Feature branches are able to shield themselves from receiving breaking changes until the feature team is ready for them.  But what happens when product A build needs a major feature change made to its dependency library build C; while at the same time product B build needs a different major feature change from the same dependency library C?  The answer may be multiple development streams are active for library C at the same time, with one stream intended for the next release of product A and another stream for the next release of product B.

As defined, the semantic version system is great for startup organizations, but breaks down when multiple development streams are active at the same time, as is often the case with enterprise level software organizations supporting multiple legacy versions or concurrently working on multiple new product releases at the same time.  The reason is the lack of protection against multiple active source code branches publishing to the same version space when the intended changes on the branches are for different development initiatives, such the different product releases.

Numerous developers have responded to my concerns about semantic versioning with statements like, “We just have to manage that,” and “Everyone just needs to be careful.”  I have learned to recognize responses that are indicators of processes or systems that are neither automate-able, nor scale-able.  We can be careful with version numbers when the project is small and manual, but that does not work in a highly automated, enterprise world.  We need systems with management solutions baked right into the process.

How can we have all the benefits of semantic versioning at enterprise scale?  The solution I propose starts with identifying situations where dissimilar code streams might eventually be publishing the same versions.  Here are some activities that will cause this to happen: concurrent development on multiple release streams, customer escalation work, and reuse of the dependency artifact by multiple products.

Concurrent release development can be resolved by pre-pending another element to the version number ahead of the major, minor, and patch elements.  If we called this digit the ‘stream’ identifier, the resulting version string becomes ‘stream.major.minor.patch’ and the problem is resolved.  Each development release is assigned a stream id and all of the increment rules apply as usual – except for being shifted to the right by the stream number.  There will never be cross-stream confusion no matter how many times the semantic increment rules trigger an increment of the major, minor, or patch numbers.

The customer escalation problem is a little more difficult to resolve.  It’s never known ahead of time when an escalation will occur, when an escalation branch will be needed, nor how many escalation branches will be needed.  We can rule out the stream identifier solution for customer escalation branches, since all of the consumer artifacts would also need corresponding dependency constraint changes, and that is exactly the kind of management overhead we are trying to avoid.  One solution is to forego the semantic version increment rules on escalation branches.  The version of the main development stream branch at the branch point becomes the version for all builds on the escalation branch, regardless of the type of change.  Suspending the increment rules on escalation branches will prevent them from incrementing their way into another existing branch’s version space; or into the next escalation branch’s space.

With these reasonably simple changes, semantic versioning can exist at scale in the traditional, multi-development stream enterprise environment, and can then be automated if desired.

As with most software problems, there are often numerous ways to solve the same problem.  The solutions presented here are not the only possible solutions.  This semantic versioning limitation can also be solved by eliminating multi-stream, development through the use of solutions like the BranchByAbstraction technique described here: https://martinfowler.com/bliki/BranchByAbstraction.html.

Understand the limitations of the SCM solutions you are considering and always select one that is suitable for the purpose.