Navigating Semantic Versioning In An Increasingly Packaged World

The What, How and Why of Semantic VersioningIntroductionThe world of programming is built upon countless libraries dependent on each other. Semantic Versioning enables programmers to communicate a versioning policy that can be easily understood by cons…


This content originally appeared on Bits and Pieces - Medium and was authored by James Won

The What, How and Why of Semantic Versioning

Introduction

The world of programming is built upon countless libraries dependent on each other. Semantic Versioning enables programmers to communicate a versioning policy that can be easily understood by consumers of their libraries.

A couple of years ago I was part of a team that maintained an internal JavaScript library of a relatively large organisation. I got to see firsthand the importance of Semantic Versioning both as a maintainer and a consumer.

In this article, I will focus on the what, how and why of Semantic Versioning and delve into some of the lessons I learned during my experience working with it.

Warning: reading discretion is advised for anyone suffering from JavaScript package fatigue.

What is Semantic Versioning?

Semantic Versioning is a set of guidelines that specify how developers set version numbers for their package libraries.

Why use semantic versioning?

The single biggest problem in communication is the illusion that it has taken place.” — George Bernard Shaw

My TL;DR is that it all comes down to simplifying communication of risk.

When using other people’s code we have a tightrope to walk between two extremes.

  • We want to ensure that managing packages aren’t done too tightly where you can never upgrade.
  • But, on the other hand, we don’t want to be in a situation where we are too loose with upgrades and your code starts to break unexpectedly.

The importance of balancing these two extreme risks is elevated by the sheer size of dependencies that a typical project depends on. And then that is not the full picture. Dependencies are only at the tip of the iceberg, with your dependencies relying on their dependencies (your ‘sub-dependencies’) and so on.

Npm package iceberg

Even the most well-resourced teams just don’t have the ability to thoroughly go through the code and check everything. That’s why a simple versioning system like Semantic Versioning is so important.

It creates a clear and specific set of rules for every developer to follow when versioning their libraries.

How To Use Semantic Versioning

Using Semantic Versioning is relatively straightforward.

There are three sets of numbers separated by two . ‘s. Each communicates different risks and information:

  1. Major — “This is a breaking change, be careful”.
  2. Minor — “This is a new addition that shouldn’t break your code”
  3. Patch — “This is patching a bug”

I’ve created a table below with some examples:

Note. There are nuances between teams and organisations — for example, a popular offshoot of semantic versioning is conventional commits but the principle is very similar.

Who Uses Semantic Versioning?

Pretty much all software developers, knowingly or unknowingly use Semantic Versioning.

Sourced from NPM’s article “This year in JavaScript: 2018 in review and npm’s predictions for 2019”

Every time you use a package manager for whatever language or ecosystem you are using code that other developers have versioned using Semantic Versioning.

For example, JavaScript developers using Node Package Manager (NPM), and C# developers using Nuget, all rely on packages which have been semantically versioned.

The quality of the Semantic Versioning can vary.

  • Small personal projects or half-baked packages (of which there are many) may have wildly inflated version numbers.
  • On the other hand, conservative packages such as React Native haven’t even gotten to the first major despite being downloaded more than 1.3 million times (0.71.8 last time I checked).
React Native’s NPM page stats

Personal Learnings

The following quote captures succinctly my experiences using packages.

Hoping for the best, prepared for the worst, and unsurprised by anything in between. — Maya Angelou

Some key lessons I’ve taken away over the years are:

1. The Spec is only as good as the discipline of the person/group of individuals enforcing it.

Photo by Dave Lowe on Unsplash
To err is human, to forgive divine — Alexander Pope

As they say “To err is human”. I’ve both been the cause and recipient of errors with versioning.

Sometimes understanding when a code is considered “Breaking” can be difficult.

Changing a React prop name from oldProp to breakingProp obviously is a breaking change.

But what about if your design system changed the padding of a button by 1px? Is the visual regression enough to be considered “breaking”.

Sometimes decisions can get nuanced by context.

For example. imagine that you maintain an internally hosted design system accessible only to members of your organisation. The consumers of the package are few and you see them every day. In this context, the weight of getting the versioning right doesn’t weigh as heavily as if you were maintaining a big library like React for example.

I totally understand these difficulties as I have faced them before, and I’m not saying that a dogmatic answer is always the solution.

The key though is for developers as much as possible to adhere closely to Semantic Versioning and by default enforce it unless there are good reasons not to, even in the scenario I mentioned above where the library is internal.

2. People really hate change. But you have to fight through it.

Photo by Chris Lawton on Unsplash
Change is inevitable. Growth is optional — John C. Maxwell

StackOverflow, Reddit and Github issues are full of complaints about how changes to a certain package or another have caused them untold pain.

But what is certain is that delaying updating packages is perilous and to keep.

As maintainers, unless you have a package that is self-reliant with no or very few dependencies you will need to update your packages at a certain point or risk security issues or obsolescence if a key dependency moves on.

  • An example is Enzyme. Until React 17, Enzyme was an incredibly popular testing library used for React applications. But it just couldn’t keep up and update support. An issue for this has been open since August 2020, and since this time React has moved on even further with 18.

As consumers the longer you wait the harder upgrading will become. You will continue to write potentially redundant code and the snowball is continuing to build into an avalanche of technical debt that will surely arrive.

  • For example, I saw the spectre of React upgrades daunting consumers and preventing them from upgrading our library. After teams fell behind more than 1–2 versions, the unknowns become a psychological boogeyman that made it even harder to upgrade.

No matter what you do, the world of packages will move on.

💡 Note: Bit is an open-source tool that provides SemVer-based tagging of different components inside a single project (i.e. library or application). Using the bit tag command each component can be tagged with a SemVer. Upon tagging a version update, Bit prompts you which other components should be updated as well, and lets you auto-tag all of them together. Versioned components can be exported and distributed across teams and projects. When a component is updated with a new version, it can be independently updated by different applications, using SemVer rules.

Learn more about versioning with Bit here:

Versioning Independent Components

3. Even when you do everything right, things can and still will go wrong

Some packages won’t survive, and you may need to deal with it.

For example. until React 17, the design system team I worked on at the time happily relied on Enzyme to do React component behaviour testing. We initially tried to hang on with an unofficial adapter package, but when we realised a proper upgrade wasn’t on its way we had no choice but to bite the bullet and transition off Enzyme.

And while it was painful it led to us using React Testing Library with full gusto which honestly turned out to be a great move for us.

I have nothing but love towards the maintainer of Enzyme, I know firsthand how hard it is to maintain a library (albeit I was on a team with the economic might of a big tech company helping to keep it churning along) and I can only imagine how difficult keeping a project alive open-sourced. But the fact is we had to move on, and we did.

Sometimes everything fails. A web of packages relying on each other means trust is its strength and weakness.

An example is left-pad in 2016. Long story short (the story is absolutely fascinating so definitely have a look if you have time to burn) the developer had deleted all of his NPM repositories including a tiny package composed of 11 lines. This broke a bunch of widely used npm packages including React, leading to an emergency where NPM force reinstated the package.

There are also numerous examples of malicious software disguised as legitimate ones propagating out to infect computers with malware and crypto-mining.

Thankfully it isn’t something I’ve had to personally deal with so far. But it is the small price we pay for being in a world full of free open-source software. Being aware of this is important and having good upgrade practices to avoid the worst.

Some Tips To Make The Road Less Bumpy

  1. Read release notes — Making a habit of skimming release notes of dependencies really helps identify possible failure points. It also is a great way to learn how other libraries maintain their libraries. I personally advocate this as a ‘should’ for a minor upgrade and a ‘must’ for a major upgrade.
  2. Sanity check builds in a non-prod environment. Ideally, you should know which areas of the codebase the update affected and you should walk through the user flow to make sure nothing broke. You will already be doing this for majors (I hope!) but it is a good practice to apply for minor and patch updates.
  3. Over-communicate as a maintainer of a library. We can always do more to communicate better. Write comprehensive release notes, if it isn’t feasible for all releases then do so for at least your major releases. Write clear commits and PRs with good descriptions. This is a good thing to do anyway, but it’s even more important as consumers may need to review the why, what and how of your code. Even if you are a small or closed library, I’d recommend this as good habits have a tendency not to be important until it’s too late 😂.
  4. Update packages regularly. This goes without saying but having a process to regularly and proactively audit, assess and update packages goes a long way.
  5. Keep vigilant. Hope for the best but be prepared for the worst!

Conclusion

Semantic Versioning is an important guideline to help developers communicate with consumers of their packages effectively. It is a powerful tool that simplifies communication of risk and enables the huge web of packages that power our world today.

It is important to note that a guideline is only as good as the person or group of people implementing it. Semantic Versioning is no different. At the end of the day we are all human (at least at the moment anyway). It is always important to keep this in mind and to do our best both as consumers and maintainers to proactively apply good practices and be vigilant to reduce the negative impact of errant packages.

Resources For Further Reading

Versioning independent components the easy way using Bit

Bit’s open-source tool help 250,000+ devs to build apps with components.

Turn any UI, feature, or page into a reusable component — and share it across your applications. It’s easier to collaborate and build faster.

Learn more

Split apps into components to make app development easier, and enjoy the best experience for the workflows you want:

Micro-Frontends

Design System

Code-Sharing and reuse

Monorepo

Learn more:


Navigating Semantic Versioning In An Increasingly Packaged World was originally published in Bits and Pieces on Medium, where people are continuing the conversation by highlighting and responding to this story.


This content originally appeared on Bits and Pieces - Medium and was authored by James Won


Print Share Comment Cite Upload Translate Updates
APA

James Won | Sciencx (2023-05-31T06:02:17+00:00) Navigating Semantic Versioning In An Increasingly Packaged World. Retrieved from https://www.scien.cx/2023/05/31/navigating-semantic-versioning-in-an-increasingly-packaged-world/

MLA
" » Navigating Semantic Versioning In An Increasingly Packaged World." James Won | Sciencx - Wednesday May 31, 2023, https://www.scien.cx/2023/05/31/navigating-semantic-versioning-in-an-increasingly-packaged-world/
HARVARD
James Won | Sciencx Wednesday May 31, 2023 » Navigating Semantic Versioning In An Increasingly Packaged World., viewed ,<https://www.scien.cx/2023/05/31/navigating-semantic-versioning-in-an-increasingly-packaged-world/>
VANCOUVER
James Won | Sciencx - » Navigating Semantic Versioning In An Increasingly Packaged World. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2023/05/31/navigating-semantic-versioning-in-an-increasingly-packaged-world/
CHICAGO
" » Navigating Semantic Versioning In An Increasingly Packaged World." James Won | Sciencx - Accessed . https://www.scien.cx/2023/05/31/navigating-semantic-versioning-in-an-increasingly-packaged-world/
IEEE
" » Navigating Semantic Versioning In An Increasingly Packaged World." James Won | Sciencx [Online]. Available: https://www.scien.cx/2023/05/31/navigating-semantic-versioning-in-an-increasingly-packaged-world/. [Accessed: ]
rf:citation
» Navigating Semantic Versioning In An Increasingly Packaged World | James Won | Sciencx | https://www.scien.cx/2023/05/31/navigating-semantic-versioning-in-an-increasingly-packaged-world/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.