Showing results for 
Search instead for 
Did you mean: 

Service Contracts in Separate Packages

Regular Contributor

Service contracts (defined using PHP interfaces) are currently included in same module that implements the interfaces and are versioned with the rest of Magento. One strategy under consideration is to separate into two modules the PHP interfaces that define service contracts and their implementation. The version number of the modules holding the service contracts would then only change if the contract changes. This provides more stability for extension developers.


What Are Service Contracts?


Service contracts are PHP interfaces that define the API for interacting with a given module. By using PHP interfaces, this allows different implementations to be swapped in more easily. For example, see the Customer module Api directory on GitHub.


The concept of contracts in this blog post is restricted to PHP interfaces. The definition needs to be expanded to whatever one module may need to depend on in another module, such as block ids in layout files and events, but that is beyond the scope of this blog post.


Why is Versioning So Hard?


The source code for Magento Community Edition is currently all in one git repo. This may change in the future, but that is how the code is today. Git only supports branching at the git repo level – you cannot branch different subdirectories independently. Magento creates a repository branch each minor release of Community Edition (2.0, 2.1, 2.2 etc). Patches for that release level are then created on that release branch (2.0.1 is created on the 2.0 release branch, 2.2.5 is created on the 2.2 release branch, etc).


To avoid the same version number of a module existing on two branches, each minor release (e.g. going from 2.1 to 2.2) always increments the minor or major number (first or second digit) of every module in the repository; on the release branch, only patch number increments are allowed (third digit), never the major or minor number (first or second digit). This strategy guarantees you can never get two branches in the git repository having different code with the same version number. It also guarantees that all patches are cumulative on release branches. The problem is it sometimes forces the minor version number change for a module even if the module is unchanged. This is unfortunate.


If each module was in a separate git repo, a different strategy could be used. When moving from 2.1 to 2.2 a decision could be made per module whether the same minor version of that module can be shared between the two release levels. For example, 2.1 and 2.2 could both point to 100.1.* of the Magento Customer module. If it is shared, any patch to that module would be shared by both releases. That also avoids back-porting bug fixes to as many releases.


The only reason this is not done today is all the modules are in the one git repo and share the same branching strategy. This may change in the future, but has not been done to date for two pragmatic reasons:


  • It is more cumbersome for core developers having to manage hundreds of separate repositories. A global change would require separate coordinated releases of multiple modules.
  • There have been higher priority things to fix first. Changing the approach requires work on release scripts, test frameworks, documentation, etc.


This blog post is a first step in the direction of splitting the Magento code base into independent git repos.




The proposal is as follows:


  • Move everything except service contracts (the Api directories) out of existing modules (such as “Magento_Customer”) into new modules (such as “Magento_CustomerImpl”). You can think of this like creating a PHP interface (the contract module) that a class implements (the implementation module).
  • Create a new git repo per contract module. Contract modules will then only have new versions created if the contract changes, providing projects and extension developers more stability. (Extensions specify the module version they depend on. If they depend on a contract module, and that contract module major/minor version is shared between two releases, the extension does not need to change to support the new release.)
  • Implementation packages continue to be versioned per Community Edition release as they are today.
  • Product metapackages (the metapackage that lists all the exact module versions for, say, Community Edition 2.1.6) would reference both the contract packages and the implementation packages that implement those contracts.
  • Extensions may need to be updated to depend on the new implementation modules if there is an implementation-level dependency. (Such dependencies are undesirable, but may still be needed at times.)




There are some considerations with this proposal.


  • There will be more modules than today due to the separation of contract modules from implementation modules.
  • Existing code will need modifying due to code being moved.
  • This may be a good opportunity to group related contract modules together so there is a “promotions contract module” even if today the functionality resides in a range of implementation modules.




The goal of separating contracts from implementation modules is for contracts to capture all the touch points needed by extensions. If an extension can 100% depend on a contract module and not on an implementation module, this provides Magento the flexibility and freedom to refactor and improve the implementation module with the stability that extension developers crave. As a result, extensions could support multiple Magento releases without change. To be effective, this will require Magento and extension developers coming together to work out what each contract should be.