Semantic versioning for bundles

Posted by Unknown on Saturday, September 27, 2014

A short introduction to semantic versioning


Semantic versioning is an agreement between the user of a package and its maintainer. The maintainer should be able to fix bugs, add new features or completely change the API of the software they provide. At the same time, the user of the package should not be forced to make changes to their own project whenever a package maintainer decides to release a new version.


The most extreme solution to this problem is: the package should never change, the user should never need to upgrade. But this is totally useless, since the user wants new features too, they just shouldn't jeopardize their existing, functioning code. At the same time the package maintainer wants to release new features too, and they may even want to redo things completely every once in a while.


Semantic versioning assumes a package to have a version number that consists of three numbers, separated by dots, like 2.5.1. The first number is called the "major version", the second number is called the "minor version", the last number is called the "patch version". The semantic versioning agreement in short tells the package maintainer to increment the:



MAJOR version when you make incompatible API changes,


MINOR version when you add functionality in a backwards-compatible manner, and


PATCH version when you make backwards-compatible bug fixes.



You can read the full explanation of the concept and what you are agreeing upon if you say that your package "follows semantic versioning" on semver.org.


Symfony and semver


As of version 2.3 the Symfony framework officially uses semver. They also apply some extra rules for parts of the code (classes, interfaces, methods) which they label as being part of the official Symfony API by adding an @api annotation to the respective doc comments. Semantic versioning and public API labeling together this consistutes Symfony's backwards compatibility promise.



In short, Semantic Versioning means that only major releases (such as 2.0, 3.0 etc.) are allowed to break backwards compatibility. Minor releases (such as 2.5, 2.6 etc.) may introduce new features, but must do so without breaking the existing API of that release branch (2.x in the previous example).



Bundles and semver


I was asked by Paul Rogers from the Symfony Live London crew:



How should you version a bundle? Should it be related to the library version, like ElasticBundle does?



As a matter of fact, I had already spent some toughts on this issue. The answer to the first question is: apply semver, just like any package should do. And the answer to the second is: no. It should not per se be related to the library version for which the bundle provides a framework-specific integration layer. I think this second answer requires some more detailed reasoning from my side.


Bundles expose an API themselves


The code in a library package exposes an API. People are going to use that API in a particular way. They are going to instantiate some of the classes from the package with a particular set of constructor arguments. They are going to call some of its methods with a particular set of arguments. This is the reason why semantic versioning should be applied to such packages in the first place: the maintainer should not be allowed to change any of the things the user relies on, like class names, method names, required parameters, etc.


A bundle mostly doesn't expose an API consisting of classes and methods. The API of a bundle consists of *services, or service definitions, and parameters. These are different types of entities. Yet they share some characteristics: service definitions often provide constructor arguments in a particular order, they sometimes contain method calls used for setter injection, they are public or private, abstract or concrete, have a certain name, etc.


Some changes, like making a private service public won't make a difference for an existing user.



services:
formerly_a_private_service:
public: true


If a service was formerly a private service, the user could not have relied on it in any way that a public service doesn't support. So that kind of a change should not to be considered a backward compatibility (BC) break.


The other way around - making a public service private - on the contrary should be considered a BC break.



services:
formerly_a_public_service:
public: false


Some users may rely on it being public. For example they may call



$container->

Truncated by Planet PHP, read more at the original (another 2695 bytes)




more

{ 0 comments... » Semantic versioning for bundles read them below or add one }

Post a Comment

Popular Posts