Sponsor: Do you build complex software systems? See how NServiceBus makes it easier to design, build, and manage software systems that use message queues to achieve loose coupling. Get started for free.
Package Managers (npm, nuget, pip, composer, maven, etc) are an incredible tool for leveraging other libraries and frameworks into your products or projects. What seems to have been largely lost in the decision-making process on if you should take on a dependency and what the implications are. Once you do take a dependency, how much do you trust the vendor/author and semantic versioning? Before you do a quick npm install or update let me explain some things you should be considering.
Check out my YouTube channel where I post all kinds of content that accompanies my posts including this video showing everything that is in this post.
The theme of this post is really to emphasize that dependencies are your problem and you need to take ownership over the decision-making process of taking on a dependency.
Dependencies are nothing more than an extension of your own code. They require some serious consideration on what dependencies you’re taking on, why you’re taking the dependency, and should even be taking the dependency, to begin with.
Trust plays a role in taking on a dependency. If you’re working on a product that is going to be long-lived, you want to align yourself with dependencies that you’ll grow with. There’s a certain level of stability that you’ll want dependencies to have.
Meaning if you develop a product that lasts 10+ years, what dependencies will you take that will also live that long. These can either drag you down over time like an anchor or propel you forward with their own innovations.
As an example, I started a product in 2015 with .NET Framework 4.7 and ASP.NET just as .NET Core (now .NET5+) was emerging but not yet released. While the effort to move to ASP.NET Core took time and knowledge it was possible and was completed. We’ve kept up to date with .NET as it stands today and has been propelled forward by all of the advancements rather than being dragged down and being stuck on the .NET Framework.
So where does Semantic Versioning fit into any of this that I’ve written about so far? Well, Semantic Versioning is nothing more than a way to communicate that something changed in a package that you depend on. That’s it.
While the intent is to identify the degree of change with major, minor, and patch versions, that’s only as good as the author’s intent of following that definition. For example, if the patch version changes because of a bug fix that is done in a backward-compatible manner, what’s your level of trust that it actually still is backward-compatible? Just because the API surface didn’t change doesn’t mean it’s backward-compatible. What happens if you have a work-around for a bug, that then is fixed. That’s not backward-compatible to you if it breaks you now that it’s fixed.
Semantic Versioning tells you something changed. That’s it.
Even if the authors of a package have good intent and understanding of SemVer, that doesn’t mean what should be a non-breaking change won’t be breaking to you. The only way to satisfy this is to have the proper level of testing that validates your usage of a dependency.
You only need to concern yourself with the functionality and API surface that you actually use from that dependency.
Pin Versions & Upgrades
If you don’t have good test coverage or the ability to understand upgrades of the package, pin your versions. Don’t rely on ranges but rather have a cadence for manually dealing with updating packages.
The longer you wait to upgrade to a new version the more you’ll have to either change in the long run. If you don’t want to get on the upgrade train, don’t pick or bet on a dependency that’s constantly releasing. This could be because of feature enhancements that you don’t need or bug fixes due to instability.
It goes back to ownership and making a decision based on your context.
Context is King
If you’re working on a project or product that is going to be short-lived, almost nothing I’m talking about matters. You’ll likely not be even bothering to update any dependencies unless there’s some security issue you need to address.
However, if the project/product is going to be long-lived over many years, you’ll likely be constantly evolving the system. In doing so you’re going to likely need to update dependencies. The more dependencies you have the more work it is to manage them.
Developer-level members of my YouTube channel or Patreon get access to the full source for any working demo application that I post on my blog or YouTube. Check out the YouTube Membership or Patreon for more info.