Libraries should communicate dependencies’ versions constraints. However, doing so properly puts more burden on the package maintainer.
- You need to specify the proper lower boundary. The proper lower boundary is usually not immediately obvious and depends on what subset of the interface you use. It might be a couple of major versions lower.
You need to maintain the proper upper bound. When using semantic versioning, the proper assumption is to limit upper bound to the current major version. However, when a new version of a dependency is released, it might be possible that your package still works with it without any changes (A major version bump does not imply incompatibility)—but you still need to bump the upper boundary of your package and release a new version. (Similar cases often happen in Haskell ecosystem.)
- Some package managers allow overriding the dependency of your dependency, ignoring the version constraints—this alleviates the pain if the maintainer does not bump the upper bound.
Setting proper lower boundary is (mostly) one-off effort but maintaining upper boundary requires continuous effort.
This happens because package managers operate on versions (Interface is second-class for package managers), Version numbers version package interface as a whole, but Packages only use a subset of other packages’ interfaces.
- Packages could declare their dependencies’ interface instead of version constraint—a thought experiment on a different approach to dependency-management