porting a complex - magento › rs › 585-ggd-959 › images › mlfr17...• you do not want to...
TRANSCRIPT
![Page 1: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/1.jpg)
![Page 2: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/2.jpg)
Porting A Complex
Extension To Magento 2
![Page 3: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/3.jpg)
Magento Developer at integer_net
Fabian Schmengler
![Page 4: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/4.jpg)
The ExtensionIntegerNet_Solr
![Page 5: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/5.jpg)
Improved Search And Layered Navigation
• More relevant search results
• Fuzzy search
• Autosuggest window
• Filters with multiple selection
• Search categories and CMS pages
• Boosting of products and attributes
• Fetch category pages from Solr for improved
performance
![Page 6: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/6.jpg)
![Page 7: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/7.jpg)
Metrics
• 2304 Logical Lines of Code
• 79 Classes (and 3 interfaces)
• 10 Class Rewrites
• 12 Observers
![Page 8: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/8.jpg)
Our Goal: Reuse
![Page 9: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/9.jpg)
Extract Independent Library
![Page 10: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/10.jpg)
Extract Independent Library
![Page 11: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/11.jpg)
Extract Independent Library
![Page 12: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/12.jpg)
Architecture
![Page 13: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/13.jpg)
Architecture
![Page 14: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/14.jpg)
Architecture
![Page 15: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/15.jpg)
Architecture
![Page 16: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/16.jpg)
The Plan
• Decouple / Extract Library
• Implement M2 Bridges
• Glue Together M2 Module
![Page 17: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/17.jpg)
Step 1: Refactoring
![Page 18: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/18.jpg)
First: TESTS! This is NOT optional!
• Make changes with confidence
• Receive fast feedback during
development
![Page 19: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/19.jpg)
First: TESTS!
• Must have: Integration Tests
– E.g. EcomDev_PHPUnit
• Nice to have: Functional Tests
– E.g. Selenium
• Useless: Unit Tests
– Don‘t write unit tests for existing code!
![Page 20: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/20.jpg)
Then: Refactor
Small Steps
• Introduce intermediate solutions if necessary
• Deprecate them immediately
Start Easy
• Find classes with least interaction with Magento
• Eliminate Dependencies
![Page 21: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/21.jpg)
![Page 22: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/22.jpg)
Mage Levels
• Mage::throwException()
• Mage::getStoreConfig()
• Mage::dispatchEvent()
• Mage::helper()
• Mage::getModel()
Level 1
Final Enemy
![Page 23: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/23.jpg)
Use Own Exceptions
Mage::throwException($msg);
=>
throw new IntegerNet_Solr_Exception($msg);
![Page 24: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/24.jpg)
Inject Configuration Values
public function __construct()
{$this->host = Mage::getStoreConfig('integernet_solr/server/host');…
}
=>
public function __construct($host, …){
$this->host = $host;
…
}
![Page 25: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/25.jpg)
Better: Use Value Objects
• Represent a value
• No identity
• Immutable
![Page 26: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/26.jpg)
Configuration Value Objects: Definition
namespace IntegerNet\Solr\Config;
final class ServerConfig
{
private $host, …;
public function __construct($host, …)
{
$this->host = $host;
…
}
public function getHost()
{
return $this->host;
}
}
![Page 27: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/27.jpg)
Configuration Value Objects: Usage
• Read configuration in Magento module
$serverConfig = new ServerConfig(
Mage::getStoreConfig('integernet_solr/server/host'),
…
);
• Pass $serverConfig value object to library
$solr = new SolrResource($serverConfig, …);
![Page 28: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/28.jpg)
Replace Helpers
public function __construct()
{$this->helper = Mage::helper('integernet_solr');…
}
$this->helper->getUserQueryText();
=>
public function __construct(UserQuery $userQuery){
$this->userQuery = $userQuery;
}
$this->userQuery->text();
![Page 29: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/29.jpg)
Replace Helpers: Introduce Interfaces
First, define interface for existing code
class IntegerNet_Solr_Helper_Data extends Mage_Core_Helper_Abstract
implements UserQuery
{
public function getUserQueryText() { … }}
namespace IntegerNet\Solr\Implementor;
interface UserQuery
{
public function getUserQueryText();
}
![Page 30: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/30.jpg)
Replace Helpers: Dependency Injection
Then, pass helpers as implementation of the interface
class IntegerNet_Solr_Helper_Factory
{
public function getSolrRequest()
{
return new SearchRequestFactory(
Mage::helper('integernet_solr'), // constructor expects UserQuery
…
)->createRequest();
}}
Note: No Dependency Injection framework involved!
![Page 31: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/31.jpg)
Build Bridges For Models
• “Implementor” interfaces define what
library needs from Magento
• Bridge implementation delegates to actual
Magento models
![Page 32: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/32.jpg)
Remember?
![Page 33: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/33.jpg)
ExampleA Bridge For The Product Model
![Page 34: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/34.jpg)
Service
class ProductModification
{
public function uppercaseDescription($sku) {
$product = $this->productRepository->getProduct($sku);
}}
Interfaces
interface ProductRepository {
public function getProduct($sku);
}
interface Product {
}
![Page 35: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/35.jpg)
Service
class ProductModification
{public function uppercaseDescription($sku) {
$product = $this->productRepository->getProduct($sku);
$product->setDescription(strtoupper($product->getDescription());
}}
Interfaces
interface ProductRepository {
public function getProduct($sku);
}
interface Product {
public function getDescription();
public function setDescription($description);
}
![Page 36: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/36.jpg)
Service
class ProductModification{
public function uppercaseDescription($sku) {$product = $this->productRepository->getProduct($sku);$product->setDescription(strtoupper($product->getDescription());$productRepository->saveProduct($product);
}}
Interfaces
interface ProductRepository {public function getProduct($sku);public function saveProduct(Product $product);
}interface Product {
public function getDescription();public function setDescription($description);
}
![Page 37: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/37.jpg)
Bridge: Product
class IntegerNet_Example_Model_Bridge_Product implements Product
{
protected $_product;
public function __construct(Mage_Catalog_Model_Product $product)
{
$this->_product = $product;
}
}
![Page 38: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/38.jpg)
Bridge: Product
class IntegerNet_Example_Model_Bridge_Product implements Product
{
protected $_product;
public function __construct(Mage_Catalog_Model_Product $product)
{
$this->_product = $product;
}
public function getDescription()
{
return $this->_product->getDescription();
}
public function setDescription($description)
{
$this->_product->setDescription($description);
}
}
![Page 39: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/39.jpg)
Bridge: Product (additional methods)
class IntegerNet_Example_Model_Bridge_Product implements Product
{
protected $_product;
/** @deprecated only use interface methods! */
public function __call($method, $args)
{
return call_user_func_array([$this->_product, $method], $args);
}
}
Useful during refactoring (deprecated!)
![Page 40: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/40.jpg)
Bridge: Product (additional methods)
class IntegerNet_Example_Model_Bridge_Product implements Product
{
protected $_product;
/** @return Mage_Catalog_Model_Product */
public function getMagentoProduct()
{
return $this->_product;
}
}
Only use within the Magento module!
![Page 41: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/41.jpg)
Bridge: Product Repository
class IntegerNet_Example_Model_Bridge_ProductRepository
implements ProductRepository
{
public function getProduct($sku)
{
$id = Mage::getModel('catalog/product')->getIdBySku($sku);
$magentoProduct = Mage::getModel('catalog/product')->load($id);
}
}
![Page 42: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/42.jpg)
Bridge: Product Repository
class IntegerNet_Example_Model_Bridge_ProductRepository
implements ProductRepository
{
public function getProduct($sku)
{
$id = Mage::getModel('catalog/product')->getIdBySku($sku);
$magentoProduct = Mage::getModel('catalog/product')->load($id);
return new IntegerNet_Example_Model_Bridge_Product($magentoProduct);
}
}
![Page 43: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/43.jpg)
Bridge: Product Repository
class IntegerNet_Example_Model_Bridge_ProductRepositoryimplements ProductRepository
{public function getProduct($sku){
$id = Mage::getModel('catalog/product')->getIdBySku($sku);$magentoProduct = Mage::getModel('catalog/product')->load($id);return new IntegerNet_Example_Model_Bridge_Product($magentoProduct);
}public function saveProduct(Product $product){
/** @var IntegerNet_Example_Model_Bridge_Prodcut $product */$product->getMagentoProduct()->save();
}}
Here we know the concrete type of $product,
so we are allowed to use getMagentoProduct()
![Page 44: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/44.jpg)
Usage Example From Controller: Instantiation
class IntegerNet_Example_Adminhtml_ModifierController
extends Mage_Adminhtml_Controller_Action
{
public function uppercaseDescriptionAction()
{
$modifier = new ProductModifier(
new IntegerNet_Example_Model_Bridge_ProductRepository()
);
}
}
Tipp: move all instantiation into factory “helper”
• Less duplication
• Magento rewrite system can still be used
![Page 45: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/45.jpg)
Usage Example From Controller: Service Call
class IntegerNet_Example_Adminhtml_ModifierController
extends Mage_Adminhtml_Controller_Action
{
public function uppercaseDescriptionAction()
{
$modifier = new ProductModifier(
new IntegerNet_Example_Model_Bridge_ProductRepository()
);
$modifier->uppercaseDescription($this->getParam('sku'));
}
}
![Page 46: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/46.jpg)
Divide And ConquerRefactoring Techniques
![Page 47: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/47.jpg)
Split Big Classes
Approach 1
• Extract methods that don’t use any mutable attributes of
$this to other classes
![Page 48: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/48.jpg)
Split Big Classes
Approach 1
• Extract methods that don’t use any mutable attributes of
$this to other classes
Approach 2
• Extract state, grouped with the methods operating on
this state
![Page 49: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/49.jpg)
Example
• Big “Result” singleton
![Page 50: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/50.jpg)
Example
• Big “Result” singleton after first extraction
![Page 51: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/51.jpg)
Split Big Classes
• Keep as Façade (@deprecated)
• Delecate calls to new structure
“Result” example:
• Before: 10 public methods, 221 LLOC
• After: 6 public methods, 31 LLOC
![Page 52: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/52.jpg)
Rebuild Components
• Small independent units
• Plan, develop bottom up
• Replace old implementation
• New code => TDD, Unit Tests (yay!)
![Page 53: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/53.jpg)
Rebuild Components: Example
• Query strings were escaped with a helper
• Used in several places in original code
![Page 54: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/54.jpg)
Rebuild Components: Example
• Query strings were escaped with a helper
• Used in several places in original code
Introduced value object
final class SearchString
{
public function __construct($rawString) { … }
public function rawString() { … }
public function escapedString() { … }
}
• Replaced strings that represent query string with SearchString instance
![Page 55: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/55.jpg)
How to reach the goalMore Refactoring Tips
![Page 56: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/56.jpg)
Visualize class dependencies
• Use doxygen or pen and paper
• Who is talking to whom?
• Where are the boundaries?
• Where do we want them to be?
• Can we minimize the interfaces?
![Page 57: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/57.jpg)
Avoid “gold-plating”
• No need for the perfect implementation
• Focus on good abstraction instead
• Small and well-defined interface is priority
When it’s good enough, stop!
![Page 58: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/58.jpg)
Step 2: M2 Bridge
![Page 59: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/59.jpg)
Code Convertion Tools
• Useful to get started with module XML files
• Do not use them for actual code
• Unirgy ConvertM1M2:
– https://github.com/unirgy/convertm1m2
• Magento Code Migration (official):
– https://github.com/magento/code-migration
![Page 60: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/60.jpg)
Implement Interfaces
• Completely test driven
• Do not test (and use) services from the library yet
• Unit tests
– where you know which levers to pull in the core
• Integration tests (exploratory)
– if you still have to figure it out
![Page 61: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/61.jpg)
Step 3: Integrate
![Page 62: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/62.jpg)
Integrate library and Magento 2
• Take remaining M1 module as example
• Drive development with integration tests
• Implement feature by feature
• Prefer plugins over events and rewrites
![Page 63: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/63.jpg)
Use The Latest Magento Version
• You do not want to support Magento 2.0 with a
new extension
• Lock module dependencies in composer.json
"magento/catalog": "^101.0.0"
![Page 64: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/64.jpg)
Magento 2 Module Development
• Follow recommended Magento 2 development
practices if possible
– Core code should not be taken as an example
– Refer to devdocs, Stack Exchange (there is a “best-
practice” tag), presentations
![Page 65: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/65.jpg)
Magento 2 Module Development
• Follow recommended Magento 2 development
practices if possible
– Core code should not be taken as an example
– Refer to devdocs, Stack Exchange (there is a “best-
practice” tag), presentations
• Be pragmatic
– Service contracts are still incomplete
– Models and collections are more flexible
![Page 66: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/66.jpg)
But never use the
Object Manager!
![Page 67: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/67.jpg)
Dependency Injection - Interfaces
• Always depend on the interfaces
• Define bridge as preference for implementor
![Page 68: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/68.jpg)
Dependency Injection - Services
• Library classes can be used in types and
preferences
• Factories and proxies can be generated for
library classes
![Page 69: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/69.jpg)
QuestionsFAQ
![Page 70: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/70.jpg)
FAQ: How long did this take?
• Original M1 module: ~300 hours
• Refactoring: ~150 hours
• M2 module: ~300 hours
![Page 71: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/71.jpg)
FAQ: Can you replace Solr with ElasticSearch?
• If you take the framework agnostic approach to the next level: Yes
– Create the same boundary between library and search engine than
between library and shop framework
– Write different adapters
![Page 72: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/72.jpg)
FAQ: Can you replace Solr with ElasticSearch?
• If you take the framework agnostic approach to the next level: Yes
– Create the same boundary between library and search engine than
between library and shop framework
– Write different adapters
• But why should we?
– Solr is more advanced, ElasticSearch easier to learn
– We already learned Solr
– YAGNI
![Page 73: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/73.jpg)
More useful resources
• Eating ElePHPants keynote (Larry Garfield on the Drupal 8
refactoring)
– https://www.youtube.com/watch?v=5jqY4NNnc3I
• SOLID MVC presentation (Stefan Priebsch on framework agnostic
domain code)
– https://www.youtube.com/watch?v=NdBMQsp_CpE
• Mage2Katas video tutorials (Vinai Kopp on TDD with Magento 2)
– http://mage2katas.com/
![Page 74: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/74.jpg)
Thank you!
Contact me:
• www.integer-net.com
• @integer_net
• @fschmengler
I’m here, talk to me ☺
Read more in our Blog:
• integer-net.com/m1m2
• (Shared Code For Extensions)
See refactoring in action:
• nomadmage.com
• (Refactoring to Framework
Independent Code)
![Page 75: Porting A Complex - Magento › rs › 585-GGD-959 › images › MLFR17...• You do not want to support Magento 2.0 with a new extension • Lock module dependencies in composer.json](https://reader034.vdocuments.mx/reader034/viewer/2022042406/5f20bd85d048aa67717efa2d/html5/thumbnails/75.jpg)