Magento Best Practices - 1/53 Meet Magento IT – March 5th-6th, 2015 Magento Best Practices “there are at least two ways of developing things in Magento the best of which is usually the third” - Alessandro Ronchi -
Magento Best Practices - 1/53 Meet Magento IT – March 5th-6th, 2015
Magento Best Practices“there are at least two ways of developing things in Magento
the best of which is usually the third”
- Alessandro Ronchi -
Magento Best Practices - 2/53 Meet Magento IT – March 5th-6th, 2015
Magento Best Practices“there are at least two ways of developing things in Magento
the best of which is usually the third”
Magento Best Practices - 3/53 Meet Magento IT – March 5th-6th, 2015
About me● Long term Magento Developer
– 6+ years full-time work on Magento– 2+ years MCD
● Active Community member – 10+ free extensions– PUG MoRe main founder and coordinator– Organizer of Mageday 2013 and 2014
Magento Best Practices - 4/53 Meet Magento IT – March 5th-6th, 2015
About this talk
It's a dense technical talk:● mainly focused on Magento 1● some concepts are also valid for Magento 2● development experience required
Magento Best Practices - 5/53 Meet Magento IT – March 5th-6th, 2015
About you
● Developers?● Programmers?● Coders?● What else?
Magento Best Practices - 6/53 Meet Magento IT – March 5th-6th, 2015
Who we should aim to be
Software craftsmen
“Bad code can function but can bring an organization to its knees.”
“Craftsmanship comes from values that drive disciplines.” - R. Martin
“I’m just a good programmer with great habits.” - K. Beck
“Try to refactor code so that comment becomes superfluous.” - M. Fowler
Magento Best Practices - 7/53 Meet Magento IT – March 5th-6th, 2015
Tools
There are a lot of tools which support and improve the
development process
“9. Do you use the best tools money can buy?” - The Joel Test
Magento Best Practices - 8/53 Meet Magento IT – March 5th-6th, 2015
Tools● Effective IDEs (PhpStorm, Zend Studio)● Magicento (for PhpStorm) by Enrique Piatti● Commerce Bug by Alan Storm● n98-magerun by Christian Münch● Modman by Colin Mollenhour● Composer by Jordi Boggiano● Ultimate Module Creator by Marius Strajeru● Magento Code Sniffer Coding Standard by Magento ECG● Magento Project Mess Detector by Fabrizio Branca● Judge by Netresearch App Factory● Triplecheck.io by Allan MacGregor
Magento Best Practices - 9/53 Meet Magento IT – March 5th-6th, 2015
Tools: n98-magerun
● De facto standard command line toolkit to work with Magento
● Is also very useful to automate deployment tasks
● Extensible via plugins● Available reference book by Alan Storm
https://leanpub.com/command-line-magento
Magento Best Practices - 10/53 Meet Magento IT – March 5th-6th, 2015
Magento RuntimeWhy● to check code inside a full initialized
Magento application
How● Write a Module (slow)● Write a Shell Script (faster)● Use bash snippet (fastest)
Magento Best Practices - 11/53 Meet Magento IT – March 5th-6th, 2015
Magento Runtime: Shell Script● Extend Mage_Shell_Abstract● Set proper store scopeprotected $_appCode = 'admin';
● Override _applyPhpVariables()● Load app area in _construct()
– Mage_Core_Model_App_Area::AREA_FRONTEND
– Mage_Core_Model_App_Area::AREA_ADMINHTML
Magento Best Practices - 12/53 Meet Magento IT – March 5th-6th, 2015
Magento Runtime: bash snippet
<?php
if (isset($_SERVER['REQUEST_METHOD'])) {
die('Permission denied.'); // Prevent HTTP access
}
set_time_limit(0); // Avoid any time limit
ini_set('memory_limit', 1); // Avoid any memory limit
require_once 'app/Mage.php'; // Include base class
Mage::setIsDeveloperMode(true); // Enable developer mode
umask(0); // Set the default file creation mask
Mage::app(); // Init application with default store
Magento Best Practices - 13/53 Meet Magento IT – March 5th-6th, 2015
Magento Runtime: ready snippets
Customerhttps://gist.github.com/aleron75/190b25ea621c14a21d6b
Administratorhttps://gist.github.com/aleron75/9d6609e99153d19461f3
Magento Best Practices - 14/53 Meet Magento IT – March 5th-6th, 2015
Logging
Don't use static Mage::log()
A static method is a dependency:a hidden relation which increases coupling between classes
Magento Best Practices - 15/53 Meet Magento IT – March 5th-6th, 2015
Logging: Log Adapter
/** @var Mage_Core_Model_Log_Adapter $logger */
$logger = Mage::getModel(
'core/log_adapter',
'my_log_file_name.log');
$logger>log("Hello World");
Magento Best Practices - 16/53 Meet Magento IT – March 5th-6th, 2015
Logging: Log Adapter
Pros● No more Mage::log() dependency● Log file name specified once
Cons● Fixed severity for debug messages● Logs always - regardless of config
Magento Best Practices - 17/53 Meet Magento IT – March 5th-6th, 2015
Logging: Logger Model
/** @since Version 1.8.x */
/** @var Mage_Core_Model_Logger $logger */
$logger = Mage::getModel('core/logger');
$logger>log("Hello World");
$logger>logException(new Exception('Error'));
Magento Best Practices - 18/53 Meet Magento IT – March 5th-6th, 2015
Logging: Logger Model
Pros● No more Mage::log() dependency● No limitations on severity● Doesn't always force logs
Cons● Log file name specified always
Magento Best Practices - 19/53 Meet Magento IT – March 5th-6th, 2015
Logging: custom
Implement only pros:● No more Mage::log() dependency● No limitations on severity● Doesn't always force logs● Log file name specified once
Magento Best Practices - 20/53 Meet Magento IT – March 5th-6th, 2015
Logging: custom
Custom log wrapperhttps://github.com/aleron75/magelog
Monolog wrapperhttps://github.com/aleron75/magemonolog
Magento Best Practices - 21/53 Meet Magento IT – March 5th-6th, 2015
Autoloading
Magento’s autoloader is registered at the very beginning of framework's bootstrap: it is difficult (not impossible) to extend
It's not natively PSR−0 compliant(PHP-FIG's birth follows Magento's)
Magento Best Practices - 22/53 Meet Magento IT – March 5th-6th, 2015
The Magento-PSR-0-Autoloader extension registers an additional autoloader which gives the ability to include libraries adhering to PSR−0 Autoloading Standard (i.e.: Monolog)
Autoloading: enable PSR-0
Magento Best Practices - 23/53 Meet Magento IT – March 5th-6th, 2015
Effective MVC
MVC is a good exampleof separation of concerns principle
That doesn't mean we don't have to pay attention to avoid messing up
things anyway
Magento Best Practices - 24/53 Meet Magento IT – March 5th-6th, 2015
Effective MVC: Models
A Model is the entity which describes the problem we want to solve in terms
of states and business logic
Magento Best Practices - 25/53 Meet Magento IT – March 5th-6th, 2015
Effective MVC: Models
● Keep Models simple and focused on a single concern
● Choose the least visibility scope for methods and declare classes final
● Prefer composition over inheritance (as far as possible)
Magento Best Practices - 26/53 Meet Magento IT – March 5th-6th, 2015
Effective MVC: Models
Benefits of keeping Models simple:● fewer reasons to change● easier to upgrade● easier to test● clean interface● smaller method signatures
Magento Best Practices - 27/53 Meet Magento IT – March 5th-6th, 2015
Effective MVC: Blocks & Templates
Blocks are responsible for presentation data logic
Templates are responsible for presentation logic
Magento Best Practices - 28/53 Meet Magento IT – March 5th-6th, 2015
Effective MVC: Blocks & Templates
Prefer single points of definition:● No direct data/config access in Blocks;
use Models and Helpers instead● Delegate to children Blocks whenever possible
(i.e.: Mage_Catalog_Block_Product_Price)
● Templates should only interact with their Blocks● Enable cache on custom Blocks
Magento Best Practices - 29/53 Meet Magento IT – March 5th-6th, 2015
Effective MVC: Controllers
“a Controller accepts input and converts it to commands for the Model
or View” - Wikipedia
Controllers manage application flow
Magento Best Practices - 30/53 Meet Magento IT – March 5th-6th, 2015
Effective MVC: Controllers
● Check user input is well-formedi.e.: 16 digits required for a MasterCard number
● Don't perform business domain checksi.e.: whether a MasterCard number is authorized
Magento Best Practices - 31/53 Meet Magento IT – March 5th-6th, 2015
Effective MVC: Helpers
They are not waste baskets :)● utility methods containers
(Core Helpers represent a very good example)
● shouldn't implement logic.For complex logic use service Models@see Mage_Sales_Model_Service_Quote
Magento Best Practices - 32/53 Meet Magento IT – March 5th-6th, 2015
Working with Data
Adopting best practices can avoid unexpected performance downgrade or behaviour.
Simply put: write scalable code
Magento Best Practices - 33/53 Meet Magento IT – March 5th-6th, 2015
Working with Data: EAV and Flat
● Flat is never used for EAV entities in Admin Panel
● load() method always performs joins on EAV tables
● Flat for EAV entities is only used for Collections (unless filtering on non-flat attributes)
Magento Best Practices - 34/53 Meet Magento IT – March 5th-6th, 2015
Working with Data: Products
Don't try this at home: $products = Mage::getModel('catalog/product')
>getCollection();
foreach ($products as $prod) {
$prod>load($prod>getId()); # doesn't scale!
echo $prod>getDescription();
}
Magento Best Practices - 35/53 Meet Magento IT – March 5th-6th, 2015
Working with Data: Products
The following code is better for scalability: $products = Mage::getModel('catalog/product')
>getCollection()
>addAttributeToSelect(array('description'));
foreach ($products as $prod) {
echo $prod>getDescription();
}
Magento Best Practices - 36/53 Meet Magento IT – March 5th-6th, 2015
Working with Data: Products
Comparison table*:
Load type # queries # joins Time Memory
In loop 875 1072 ~4 sec ~7 MB
Outside loop 8 1 ~0.4 sec ~2.5 MB
* on a development machine with official sample data
Magento Best Practices - 37/53 Meet Magento IT – March 5th-6th, 2015
Working with Data: Collection size
Comparison table*:
Count type Time Memory
count() ~0.966 sec ~25 MB
getSize() ~0.081 sec ~1.8 MB
* on a development machine with ~8000 products
Magento Best Practices - 38/53 Meet Magento IT – March 5th-6th, 2015
Working with Data: iterate Collection
Iterating: non-scalable approach$products = Mage::getModel('catalog/product')
>getCollection();
/** @var Mage_Catalog_Model_Product $product */
foreach ($products as $product) {
// do something lazy loading is triggered
}
Magento Best Practices - 39/53 Meet Magento IT – March 5th-6th, 2015
Working with Data: iterate Collection
Iterating: scalable approach$products = Mage::getModel('catalog/product')
>getCollection();
/** @var array $productData */
foreach ($products>getData() as $productData) {
// do something
}
Magento Best Practices - 40/53 Meet Magento IT – March 5th-6th, 2015
Working with Data: iterate Collection
Iterating: alternative scalable approach$products = Mage::getModel('catalog/product')
>getCollection();
/** @var Varien_Object $object */
while ($object = $products>fetchItem()) {
// do something
}
Magento Best Practices - 41/53 Meet Magento IT – March 5th-6th, 2015
Working with Data: iterate Collection
Comparison table*:
Fetch collection items Time Memory
standard ~1.913 sec ~25 MB
getData() ~0.017 sec ~1.3 MB
fetchItem() ~0.026 sec ~1.1 MB
* on a development machine with official sample data
Magento Best Practices - 42/53 Meet Magento IT – March 5th-6th, 2015
Working with Data: save attribute value
The following code takes ~1.5 seconds to be executed on a development machine:
$product = Mage::getModel('catalog/product')
>load(<existing_product_id>);
$product
>setDataChanges(true) // force save
>save();
Magento Best Practices - 43/53 Meet Magento IT – March 5th-6th, 2015
Working with Data: save attribute value
To save only some values a better approach is: $product = Mage::getModel('catalog/product')
>load(<existing_product_id>)
>setName('New name')
>setDescription('New description')
>getResource()
>saveAttribute($product, 'name')
>saveAttribute($product, 'description');
Magento Best Practices - 44/53 Meet Magento IT – March 5th-6th, 2015
Working with Data: save attribute value
Comparison table*:
Save method Time Memory
save() ~1.5 sec ~5 MB
saveAttribute() ~0.02 sec a few KB
* on a development machine with official sample data
Magento Best Practices - 45/53 Meet Magento IT – March 5th-6th, 2015
Extending Magento
Never touch the core files!
Magento Best Practices - 46/53 Meet Magento IT – March 5th-6th, 2015
Extending Magento: monkey patch
Monkey patches are a (non upgrade safe) way to change a core class without touching the original file by copying it from the core code pool to the local one.
Possible use cases:● patching the core● rapid prototyping
Magento Best Practices - 47/53 Meet Magento IT – March 5th-6th, 2015
Extending Magento: rewrites
Rewrites are the first step towards extending Magento according to best practices.
Pros● upgrade safe
Cons● only one rewrite of same class → potential conflicts● not compliant with the open/closed principle
Magento Best Practices - 48/53 Meet Magento IT – March 5th-6th, 2015
Extending Magento: events
Events represent the standard best way to extend other classes behaviour.
Pros● upgrade safe● no conflicts: multiple observers on same event
Cons● no event → no observer
Magento Best Practices - 49/53 Meet Magento IT – March 5th-6th, 2015
Extending Magento: interceptors
Interceptors are a way to change the behavior of any public or protected method, by either executing code before or after that method.
They are native on Magento 2 but can be also added to Magento 1 thanks to: https://github.com/danslo/Danslo_Aop
Magento Best Practices - 50/53 Meet Magento IT – March 5th-6th, 2015
Extending Magento: interceptorsPros● Upgrade safe● No conflicts● Any public/protected method can be
intercepted, no need of events
Cons● Logic can be injected only at the beginning or
at the end, not in the middle of a method
Magento Best Practices - 51/53 Meet Magento IT – March 5th-6th, 2015
Conclusions● Use the best available tools
● Use runtime outside Magento modules
● Don't use Mage::log()
● Extending autoloading is possible and useful
● Write effective and solid MVC components
● Data: write scalable code
● Never touch the core, prefer events to rewrites, familiarize with interceptors
Magento Best Practices - 52/53 Meet Magento IT – March 5th-6th, 2015
The Handbookhttps://leanpub.com/magebp
● If you liked this talk you'll love the e-book :)
● Special 25% discount code for you: mm15it
● Release date: ~June 2015
Magento Best Practices - 53/53 Meet Magento IT – March 5th-6th, 2015
Thank you!
QUESTIONS?
https://twitter.com/aleron75
https://github.com/aleron75