Inconsistency as a Feature

The image below depicts the logos of the 2 most deadly package managers massively used by almost every JS developer.

Bower & NPM

Interacting with them is straightforward and easy through a few CLI commands. What they do is pretty simple, download packages for you according to specific version. The left logo belongs to bower and the right one to npm of course.

Experiences Bower & npm

I’ve been using bower for quite some time now (more than 1 year), since I work with front-end and my experience with it is not entirely pleasant. In fact I think I hate it. On the other side we have npm the package manager mainly used by node.js developers (backend/front-end). I have used extensively both and I dislike both of them, but I think that NPM is worse than bower.

More or less my interaction with these package managers is the same, they even have the same commands, which sometimes yield to different results. For example, installing a package (the most used feature of all) in bower installs in bower_components (by default), but in npm it installs in node_modules. OK, different name, who cares. Well, the trick is inside each directory. Bower keeps all dependencies with a flat structure in mind, on the contrary npm keeps all dependencies with a hierarchical structure in mind. That means that if you want one dependency, in your project’s node_module directory you will have only that dependency, but inside that there might be another node_modules directory which contains the dependencies of your dependency and this goes on… That probably is not a bad idea, since you isolate the dependencies and it saves you from trouble. Well that’s until node 4.x.x, from version 5.x.x they use a flat structure as well.

Be careful Windows users nested directories are painful…

Versioning

In a project that I worked we were supposed to use semantic versioning, but not the normal form, but the one that is used when under development, i.e. 0.Y.Z. However, we use this X.Y.beta-Z, where Z auto-increments upon release. In SemVer it states that a library should have a public API, which is the interface of the library. That shouldn’t change that often right??

Both bower & npm have the same weird rules for version resolution, which allows many different ways to define your dependencies. I really don’t know why someone would want more than 1 or 2 ways to resolve versions of a project’s dependencies, but whatever.

The 2 most ridiculous version ranges ^ and ~

Tilda range versioning rules

Complicated don’t you think? Wait for the next…

Caret range versioning rules

Too many rules for a simple task. I don’t get why these 2 semantics are useful for handling versions. They just complicate your life and make your development environment inconsistent.

The Problem

If you are a working on a small project probably you don’t experience any problems when using the above version resolution rules, but if you work on very big project with a lot of dependencies between multiple teams, then things become complicated. You are always wondering about the versions that you are running. Is it x.y.z or x.y1.z2? You need to search inside each package to make sure that you use the correct version instead of just looking on the single place where the truth should be i.e. bower.json or package.json.

Fundamentally you are maintaining an inconsistent system

Well, what I mean with inconsistent system is that dependencies might change from one day to the next without you knowing it. This is the very likely to happen when you have automatic CI builds. So, you are willingly generating a different system every time your dependencies get updated, without you knowing. In a way you made an alive system that evolves automatically. I don’t know if that’s a good thing after all.

Example

You have a system which contains:

You maintain lib-A.js and lib-B.js internally within all of your teams and they get updated constantly, i.e. a couple of minor versions per week. ext-lib-C and D are external and they are not updated so often. Then you consume A and B in your product, using x.y.* semantics, thus you install minor changes (which in this case might include new features).

So you have a system that includes libraries that is unclear what they contain and is unclear if they are working properly or not. JavaScript is a dynamic language and it’s hard to know what happens unless you run your code. On top of that add lack of integration tests, function tests (or even E2E tests) and you have the perfect recipe for inconsistency and system fragility.

Merit(s)

You don’t have to care about updates, they are done “automagically”.

I can’t imagine any other merit…

Guy looking

Issues

Conclusion

Variable package versioning makes it hard to maintain and develop a system, since it can break any time without you knowing. The larger the project gets the harder it will become to maintain it and be sure that something didn’t break. In general keep it simple, use specific versions of packages and everything will be much easier.

NOTE: originally posted on medium https://medium.com/hackernoon/inconsistency-as-a-feature-f5f1a28356d4