Contenu connexe Similaire à MageConf 2017, Design API Best Practices (20) MageConf 2017, Design API Best Practices1. © 2017 Magento, Inc. Page | 1 ‘17
API Design
Best practices
Igor Miniailo
Magento Architect
8. © 2017 Magento, Inc. Page | 8 ‘17
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
9. © 2017 Magento, Inc. Page | 9 ‘17
The backward compatibility policy
applies to PHP code annotated with
@api
11. © 2017 Magento, Inc. Page | 11 ‘17
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.
12. © 2017 Magento, Inc. Page | 12 ‘17
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
13. © 2017 Magento, Inc. Page | 13 ‘17
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. is a set of interfaces and their
implementations that a module provides to other
modules
• As a Service Provider Interface (SPI). is a set of
interfaces that a module uses internally and allows their
implementation by other modules.
• As both. APIs and SPIs are not mutually exclusive.
14. © 2017 Magento, Inc. Page | 14 ‘17
After the code is released, both API and SPI can
be evolved in a backwards-compatible way. But
both have their specific limitations.
20. © 2017 Magento, Inc. Page | 20 ‘17
We do not distinguish them separately.
SPIs are annotated the same as APIs.
21. © 2017 Magento, Inc. Page | 21 ‘17
Who decides whether interface/class belong to API or SPI?
YOU
22. © 2017 Magento, Inc. Page | 22 ‘17
Dependency Rules API
If a module uses (calls) an API, it should be dependent on the MAJOR
version.
API dependency example
{
...
"require": {
"magento/module-customer": "~100.0", // (>=100.0 <101.0.0)
},
...
}
23. © 2017 Magento, Inc. Page | 23 ‘17
Dependency Rules SPI
If a module implements an API/SPI, it should be dependent on the
MAJOR+MINOR version.
SPI dependency example
{
...
"require": {
"magento/module-customer": "~100.0.0", // (>=100.0.0 <100.1.0)
},
...
}
24. © 2017 Magento, Inc. Page | 24 ‘17
http://devdocs.magento.com/guides/v2.1/release-notes/backward-
incompatible-changes-2.1.html
26. © 2017 Magento, Inc. Page | 26 ‘17
• Interface/class removal
• Public & protected method removal
• Introduction of a method to a class or
interface
PHP - Prohibited Code Changes
27. © 2017 Magento, Inc. Page | 27 ‘17
MagentoCatalogApiCategoryRepositoryInterface
28. © 2017 Magento, Inc. Page | 28 ‘17
MagentoCatalogApiCategoryListInterface
29. © 2017 Magento, Inc. Page | 29 ‘17
PHP - Prohibited Code Changes
• Static function removal
• Parameter addition in public methods
• Parameter addition in protected
methods
31. © 2017 Magento, Inc. Page | 31 ‘17
PHP - Prohibited Code Changes
• Method argument type modification
• Modification of types of thrown
exceptions (unless a new exception is
a subtype of the old one)
• Constructor modification
32. © 2017 Magento, Inc. Page | 32 ‘17
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
...
}
}
33. © 2017 Magento, Inc. Page | 33 ‘17
PHP - Prohibited Code Changes
• Modifying the default values of
optional arguments in public and
protected methods
• Removing or renaming constants
34. © 2017 Magento, Inc. Page | 34 ‘17
The main rule is that backwards compatibility
is more important than niceness and effort of
the implementation.
35. © 2017 Magento, Inc. Page | 35 ‘17
Coupling Between Objects Reaches Its Limit with
a New Dependency
36. © 2017 Magento, Inc. Page | 36 ‘17
We MUST do continuous Refactoring!
Backward Compatibility should not be an excuse
for not doing refactoring!
37. © 2017 Magento, Inc. Page | 37 ‘17
Backward Compatible Fix
*it works (most of the time), but code quality
is far from good enough
38. © 2017 Magento, Inc. Page | 38 ‘17
Good object oriented programming in the service layer is basically
functional programming:
• constructor injection
• immutable state
• single responsibility principle
• uniform interfaces
• value objects passed across services
Bringing these concepts to an extreme leads to single-method,
immutable objects.
41. © 2017 Magento, Inc. Page | 41 ‘17
Why to use `execute` but not __invoke?
42. © 2017 Magento, Inc. Page | 42 ‘17
Proposal to move towards Functional Objects
44. © 2017 Magento, Inc. Page | 44 ‘17
Pros
The main reason for __invoke usage proposal was elimination of
unneeded `execute` methods,
which look a bit artificial and redundant here
45. © 2017 Magento, Inc. Page | 45 ‘17
Cons
No autocomplete in
PHP Storm IDE
accessing via $this
47. © 2017 Magento, Inc. Page | 47 ‘17
Cons
Unit tests look frustrating and non intuitive
48. © 2017 Magento, Inc. Page | 48 ‘17
Repositories
In Magento 2 Repositories are considered as an implementation
of Facade pattern which provides a simplified interface to a larger body
of code responsible for Domain Entity management.
The main intention is to make API more readable and reduce
dependencies of business logic code on the inner workings of a
module, since most code uses the facade, thus allowing more flexibility
in developing the system.
52. © 2017 Magento, Inc. Page | 52 ‘17
Good API design
Don't make your client do anything you can do
for them (this reduces the amount of boilerplate
code your client will have)
Notes de l'éditeur We promise to be backward compatible for classes and methods annotated with @api within MINOR and PATCH updates to our components. As changes are introduced, we annotate methods with @deprecated. The methods are removed only with the next MAJOR component version.
Let’s recap what we had with Magento 1 – where everything is an extension points. All the protected mess and so on.
We can’t make changes in contract – all changes suppose to extend existing contract. Tilde = Significant Release Operator