magento best practices

53
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 -

Upload: alessandro-ronchi

Post on 14-Jul-2015

1.683 views

Category:

Technology


2 download

TRANSCRIPT

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