This presentation accompanies a scientific article published in IEEE Transactions of Software Engineering in May 2019. See https://doi.org/10.1109/TSE.2019.2918315
The research was carried out by the Belgian Excellence of Science research project SECO-ASSIST, financed by F.R.S.-FNRS and FWO-Vlaanderen. See https://secoassist.github.io
Abstract of talk: The semantic versioning (semver) policy is commonly accepted by open source package management systems to inform whether new releases of software packages introduce possibly backward incompatible changes. Maintainers depending on such packages can use this information to avoid or reduce the risk of breaking changes in their own packages by specifying version constraints on their dependencies. Depending on the amount of control a package maintainer desires to have over her package dependencies, these constraints can range from very permissive to very restrictive. This article empirically compares semver compliance of four software packaging ecosystems (Cargo, npm, Packagist and Rubygems), and studies how this compliance evolves over time. We explore to what extent ecosystem-specific characteristics or policies influence the degree of compliance. We also propose an evaluation based on the "wisdom of the crowds" principle to help package maintainers decide which type of version constraints they should impose on their dependencies.
What do package dependencies tell us about semantic versioning?
1. Tom Mens, Alexandre Decan
Software Engineering Lab
What do package
dependencies tell us about
semantic versioning?
IEEE Transactions on Software Engineering, May 2019
https://doi.org/10.1109/TSE.2019.2918315
3. Characterising the evolution of
package dependency networks
Decan & Mens (2019) An Empirical Comparison of Dependency Network Evolution in
Seven Software Packaging Ecosystems. Empirical Software Engineering
830K packages – 5.8M package versions – 20.5M dependencies (April 2017)
4. Observation: Dependency Hell
Package updates may cause many maintainability
issues or even failures in dependent packages.
"Especially with respect to package
dependencies, the risk of things breaking at
some point due to the fact that a version of a
dependency has changed without you
knowing about it is immense. That actually
cost us weeks and months in a couple of
professional projects I was part of."
5. Observation: Outdated dependencies
Many package maintainers do not update the
dependencies of their packages.
> 1 out of 3 dependents never
� update their dependency
A Zerouali et al (Feb. 2019) A formal framework for measuring
technical lag in component repositories – and its application to npm.
Wiley Journal on Software Evolution and Process
6. Should package
maintainers upgrade
their dependencies?
https://chaoss.community
� Upgrades benefit from bug and security fixes
� Upgrading allows to use new features
� Upgrading requires effort
� Upgrading may introduce breaking changes
7. All Dependencies
Outdated Dependencies
Relation between dependency
constraints and outdatedness
Outdatedness is related to the type of dependency constraint being used
Strict constraints represent about 20% of all dependencies,
but about 33% of all outdated dependenciesSuggestion: Rely on semantic versioning
policy to set dependency constraints
8. How to avoid breaking changes?
Semantic Versioning to the rescue
• For package providers: Inform your dependents about
which releases are backwards compatible
• For package consumers: Decide and control which newer
dependency releases are permitted
major minor patch
3 9 2
Breaking
changes
Backwards
compatible
changes
Bug fixes
Semantic Versioning 2.0.0
https://semver.org
9. To which extent do packages follow
semantic versioning?
A comparison of 4 ecosystems
January 2018 dataset from libraries.io:
10. Dependency constraint syntax
across package managers
Different package managers interpret version constraints in different ways
Constraint normalization
More restrictive than semver
More permissive than semver
11. Should we treat 0.y.z releases differently?
Many packages depend
on 0.y.z package releases
According to Semantic Versioning 2.0.0 Specification
https://semver.org
“Major version zero (0.y.z) is for initial development. Anything MAY change
at any time. The public API SHOULD NOT be considered stable.”
Monthly proportion of required packages for
which at least one client is still relying on a 0.y.z
81%
35%
30%
12. Permissiveness of dependency constraints
across package managers
Pre-1.0.0 constraints are more permissive than semver
Proportion of dependency constraints that are semver-compliant or more permissive
13. Permissiveness of dependency constraints
across package managers
Post-1.0.0 constraints
Proportion of dependency constraints that are
semver-compliant, more permissive , or more restrictive
• >16% of dependency constraints in npm, Packagist
and Rubygems are restrictive, preventing backward compatible
upgrades from being automatically adopted.
• Cargo, npm and Packagist are mostly semver-compliant.
• All considered ecosystems become more compliant over time.
14. Compliance of packages with
semantic versioning
Proportion of required packages “specialized” towards a specific
constraint type for its reverse dependencies
Recommending dependency constraints based on “wisdom of the crowds”
15. Conclusion
• Different package managers have different policies
• RubyGems does not adhere to semantic versioning
• Cargo, Packagist, npm are mostly semver compliant
• Package managers are more permissive than semver for 0.y.z
releases
• Semantic versioning compliance is increasing over time
• The “wisdom of the crowds” principle could help to decide
which type of constraint to use for new dependencies to
existing required packages
What do package dependencies tell us about semantic versioning?
A. Decan, T. Mens. IEEE Transactions on Software Engineering, May 2019
https://doi.org/10.1109/TSE.2019.2918315
Hinweis der Redaktion
S5: Ce résultat inclut également les paquets qui sont abandonnés ou les paquets qui n'ont pas connu de nouvelles releases depuis l'introduction d'une contrainte (autrement dit : ce résultat n'a pas considéré la censure droite liée à l'absence d'opportunité de mettre à jour une dépendance). De même, certaines dépendances n'ont pas besoin d'être mise à jour car elles sont "universelles" (>=x, *, "latest", etc.) ou encore parce qu'aucune nouvelle version de la cible n'est disponible. Je dois pouvoir te calculer le "vrai" ratio si tu le souhaites, mais il sera sans doute plutôt aux alentours de 50% que de 33%.
S6: Tu peux ajouter quelque chose du genre "Older versions are usually no longer maintained" (on peut adopter les patchs d'une mineure/majeure précédente et donc bénéficier des "fixes", mais ça suppose que de tels patchs osnt encore déployés pour une ancienne mineure/majeure).
Talk about the dilemma of which type of dependency constraint to be used: strict ones require you to manually update your dependency constraints after each upgrade; permissive ones may pose backward incomp problems
A majority of required packages in Cargo and npm are still in an initial development phase. For these two ecosystems, more than one third of the dependency constraints are pre-1.0.0 constraints. For Rubygems and Packagist, even if this proportion is lower, it still repre- sent on average 15.5% and 9.5% of all constraints. It is therefore important to distinguish between pre-1.0.0 and post-1.0.0 constraints to analyze semver-compliance.
Cargo: 81%, npm 35%, packagist 15%, rubygems 30% at the last date
A majority of required packages in Cargo and npm are still in an initial development phase. For these two ecosystems, more than one third of the dependency constraints are pre-1.0.0 constraints. For Rubygems and Packagist, even if this proportion is lower, it still repre- sent on average 15.5% and 9.5% of all constraints. It is therefore important to distinguish between pre-1.0.0 and post-1.0.0 constraints to analyze semver-compliance.
PAR DEFAUT SEMVER NE PEUT PAS ETRE PLUS RESTRICTIVE
Oralement il sera sans doute intéressant de rappeler que semver considère que "tout peut casser" pour 0.x.y, et que cette interprétation impose qu'il n'existe pas de contraintes plus restrictives que semver. La raison pour laquelle cette remarque est utile est qu'elle est à l'origine de discussions importantes sur le fait qu'un patch doit ou ne doit pas être compatible. Ca explique la large proportion de contraintes "permissive".
Pour le premier item, j'ajouterai qu'un package manager ne peut que suggérer l'usage de semver, pas l'imposer (par définition de semver). Les 4 considérés le recommendent plus ou moins fortement (surtout cargo, puis npm, puis rubygems via une variante de semver et enfin packagist). En pratique, les paquets sont libres de choisir de respecter ou non semver, et on voit que certains le font (cargo ou dans une moindre mesure npm) mais pas tous (rubygems étant l'exemple parfait pour ça).
Specialised = 95% of the dependent package agree; and minimum 2 dependent package; (based on 1-year history only)
White zone = those for which no 95% agreement
We looked at post-1.0.0 constraints only for wisdom of the crowds…
We assessed and confirmed that the “wisdom of the crowds” principle can be used to allow to decide which type of constraint to use for new dependencies to existing required packages. If the large majority of dependencies to a given required package “agree” on the constraint type they use, this constraint type can be recommended for other packages desiring to depend on the same required package.
Newly added pre-1.0.0 constraints are more permissive than semver
Newly added post-1.0.0 constraints are mostly semver compliant
Different package managers have different policies
RubyGems does not adhere to semantic versioning
Semantic versioning compliance is increasing over time
Required packages are specialized towards a specific constraint type
The “wisdom of the crowds” principle could help to decide which type of constraint to use for new dependencies to existing required packages