Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Backward Compatibility Developer's Guide in Magento 2


Published on

Presentation made on Meet Magento Croatia 2017
- Why Backward Compatibility matters
- Public vs Private code
- Semantic Versioning and Dependency Rules
- APIs vs SPIs (Extension Points) concept
- Prohibited Code changes
- How to make Refactoring complying with Backward Compatibility policy (SuppressWarning Coupling Between Objects)

Published in: Engineering
  • D0WNL0AD FULL ▶ ▶ ▶ ▶ ◀ ◀ ◀ ◀
    Are you sure you want to  Yes  No
    Your message goes here

Backward Compatibility Developer's Guide in Magento 2

  1. 1. © 2016 Magento, Inc. Page | 1 Backward Compatibility Developer’s guide Miniailo Igor, Magento 2 Architect
  2. 2. © 2016 Magento, Inc. Page | 2
  3. 3. © 2016 Magento, Inc. Page | 3 Backward Compatibility Backward compatibility is a property of a system, product, or technology that allows for interoperability with an older legacy system (c) - Wiki
  4. 4. © 2016 Magento, Inc. Page | 4 Why does BC matter? Merchants and developers want the process of upgrading between revisions of Magento 2 to be as easy as possible. For merchants, the process must be cost-effective, while developers want their extensions to be forward- compatible for as long as possible.
  5. 5. © 2016 Magento, Inc. Page | 5 Does Magento have a lot of bugs? Are these bugs annoying for Magento developers?
  6. 6. © 2016 Magento, Inc. Page | 6 Keep Magento backwards compatible vs. fixing its flaws?
  7. 7. © 2016 Magento, Inc. Page | 7 We MUST do BOTH
  8. 8. © 2016 Magento, Inc. Page | 8 Backward Compatible Fix *it works (most of the time), but code quality is far from good enough
  9. 9. © 2016 Magento, Inc. Page | 9 Backward compatibility (BC) policy for Magento code
  10. 10. © 2016 Magento, Inc. Page | 10 Semantic Versioning Version numbers are in the format MAJOR.MINOR.PATCH, where: – MAJOR indicates incompatible API changes – MINOR indicates backward-compatible functionality has been added – PATCH indicates backward-compatible bug fixes The backward compatibility policy applies to PHP code annotated with @api
  11. 11. © 2016 Magento, Inc. Page | 11 Public and Private code
  12. 12. © 2016 Magento, Inc. Page | 12 Public vs Private code Private code is not supposed to be used by third party modules, so, in most cases, its modifications will only trigger PATCH version bumps. Changes in public code always trigger MINOR or MAJOR version bumps.
  13. 13. © 2016 Magento, Inc. Page | 13 What examples of Public code Magento has? • PHP Interface (marked with @api) • PHP Class (marked with @api) • Javascript Interface (marked with @api) • Javascript Class (marked with @api) • Virtual Type (marked with @api) • URL paths • Console commands and their arguments • Less Variables & Mixins • Message queue topics and their data types • UI component declarations • Layout handles declared by modules • Events triggered by component (both static dynamic) • Schema of configuration types introduced by module • Structure of System Configuration fields used by module
  14. 14. © 2016 Magento, Inc. Page | 14 API vs SPI (Extension Points) A PHP Interface in Magento can be used several ways by the core product and extension developers. • As an API. An interface is called by PHP code. • As a Service Provider Interface (SPI). An interface can be implemented, allowing code to provide functionality to the platform. • As both. For example, in a service contract, we expect all calls to a module to be done through the Interface (API), but we also have support for third parties to provide alternate implementations (SPI). APIs and SPIs are not mutually exclusive. Therefore, we do not distinguish them separately. SPIs are annotated the same as APIs.
  15. 15. © 2016 Magento, Inc. Page | 15 Who decides whether interface/class belong to API or SPI? YOU
  16. 16. © 2016 Magento, Inc. Page | 16 Dependency Rules API If a module uses (calls) an API, it should be dependent on the MAJOR version and the system provides backward compatibility in scope of current major version. API dependency example { ... "require": { "magento/module-customer": "~100.0", // (>=100.0 <101.0.0) }, ... }
  17. 17. © 2016 Magento, Inc. Page | 17 Dependency Rules SPI If a module implements an API/SPI, it should be dependent on the MAJOR+MINOR version, and the system provides backward compatibility in scope of the current minor version. SPI dependency example { ... "require": { "magento/module-customer": "~100.0.0", // (>=100.0.0 <100.1.0) }, ... }
  18. 18. © 2016 Magento, Inc. Page | 18 incompatible-changes-2.1.html
  19. 19. © 2016 Magento, Inc. Page | 19 What keeps us from making mistakes? To minimize this risk we have developed a tool Semantic Version Checker Tool that analyzes two code bases and determines what part of the version need updating (MAJOR, MINOR, PATCH). As part of the delivery process, we must run this tool and use the results for input to the Version Setter tool.
  20. 20. © 2016 Magento, Inc. Page | 20 Prohibited Code Changes
  21. 21. © 2016 Magento, Inc. Page | 21 • Interface/class removal Mark with @deprecated tag instead of removing it. Mark also all its methods as deprecated, so IDE highlights them as deprecated. • Public & protected method removal Mark with @deprecated tag instead. Continue returning the same results from the method if possible, so the old functionality is preserved. • Introduction of a method to a class or interface Create a new interface with a new method. New interface may take over some existing methods from the class if it makes sense to group them together. In this case, corresponding methods in the old interface/class must be deprecated with @see annotation referencing the new interface/method. The old methods should proxy the calls to the new interface instead of duplicating the logic. PHP
  22. 22. © 2016 Magento, Inc. Page | 22 PHP • static function removal • parameter addition in public methods Add a new method with necessary parameters to new interface. Deprecate old method. Reference the new method in a @see tag as a recommended replacement. Include an explanation of why the old method was replaced with the new one (e.g., there is a bug in the old method). • parameter addition in protected methods Preserve the method as is. Create a new method with the new signature, and deprecate the old method. If possible declare the new method as private.
  23. 23. © 2016 Magento, Inc. Page | 23 PHP • method argument type modification • modification of types of thrown exceptions (unless a new exception is a subtype of the old one) • constructor modification Add the new optional parameter to the constructor at the end of arguments list. In the constructor body, if new dependency is not provided (value of introduced argument is null) fetch the dependency using MagentoFrameworkAppObjectionManager::getInstance().
  24. 24. © 2016 Magento, Inc. Page | 24 class ExistingClass { /** * @var NewDependencyInterface $newDependency */ private $newDependency; public function __construct( OldDependencyIntreface $oldDependency, $oldRequiredConstructorParameter, $oldOptinalConstructorParameter = null, NewDependencyInterface $newDependency = null ) { ... $this>newDependency = $newDependency ?: MagentoFrameworkAppObjectManager::getInstance() ->get(NewDependencyInterface::class); ... } public function existingFunction() { // Existing functionality ... // Use $this->newDependency wherever the new dependency is needed ... } }
  25. 25. © 2016 Magento, Inc. Page | 25 The main rule is that backwards compatibility is more important than niceness and effort of the implementation.
  26. 26. © 2016 Magento, Inc. Page | 26 Do all backward compatible fixes look ugly because we are not allowed to make refactoring?
  27. 27. © 2016 Magento, Inc. Page | 27 Coupling Between Objects Reaches Its Limit with a New Dependency
  28. 28. © 2016 Magento, Inc. Page | 28 Coupling Between Objects - Refactoring • For preserving backwards compatibility, public and protected interface of the class must be preserved. But the class should be reviewed and refactored so that parts of the logic go into smaller specialized classes. • The existing class then should be functioning as a facade to preserve backwards compatibility, so existing usages of the refactored methods were not broken • The old public/protected methods should be marked as deprecated with @see tag suggesting the new implementation for new usages • All unused private properties/methods can be removed now
  29. 29. © 2016 Magento, Inc. Page | 29 Coupling Between Objects - Refactoring • All unused protected properties must be marked as deprecated. • Type of the variable can be removed from the DocBlock, so it's not calculated as one of the dependencies To preserve constructor signature: • Remove type hinting for unused parameters. This will remove dependency on their type • Add @SuppressWarnings(PHPMD.UnusedFormalParameter) for unused parameters
  30. 30. © 2016 Magento, Inc. Page | 30 This is how Backward Compatible fix should look like
  31. 31. © 2016 Magento, Inc. Page | 31 Q & A @iminyaylo