The beautiful Magento module - MageTitans 2014

Post on 20-Aug-2015

1.763 views 1 download

Tags:

Transcript of The beautiful Magento module - MageTitans 2014

Manchester, November 1st 2014

Vinai Kopp

Introduction

2 The beautiful Magento Module November, 1st 2014

Magento 1.x

Introduction

3 The beautiful Magento Module November, 1st 2014

Magento 1.x

It has contributed to the collective knowledge of the PHP community.

Both as a good and a bad example :)

Introduction

4 The beautiful Magento Module November, 1st 2014

This is not an introduction into Magento development.

Introduction

5 The beautiful Magento Module November, 1st 2014

How cana Magento modulebe "beautiful"?

Introduction

6 The beautiful Magento Module November, 1st 2014

Qualities of a beautiful module

1.It provides business value2.Magento can be upgraded without breaking the module3.It is easy to understand and modify4.It has good test coverage5.It is free of bugs

7 The beautiful Magento Module November, 1st 2014

Principles and Patterns

Principles and Patterns

8 The beautiful Magento Module November, 1st 2014

Robert C. Martin (Uncle Bob)

Principles and Patterns

9 The beautiful Magento Module November, 1st 2014

Some principles and some of their fancy acronyms

•Single Responsibility Principle (SRP) •Open Closed Principle (OCP)•Liskov Substitution Principle (LSP)•Interface Segregation Principle (ISP)•Dependency Inversion Principle (DIP)

Principles and Patterns

10 The beautiful Magento Module November, 1st 2014

Some more principles and some more fancy acronyms

•Encapsulate what varies (ECV)•Strive for loosely coupled designs between objects that interact (LC)•Favor composition over inheritance (FCoI)•Only talk to friends (LoD)•Don't call us, we'll call you (IoC)

Principles and Patterns

11 The beautiful Magento Module November, 1st 2014

What have you done for me lately, principles?

Principles and Patterns

12 The beautiful Magento Module November, 1st 2014

Like with all good things in life,there can be too much.

13 The beautiful Magento Module November, 1st 2014

Open Closed Principle

14 The beautiful Magento Module November, 1st 2014

“Classes should be open for extension but closed for modification”

The Open Closed PrincipleUncle Bob

The Open Closed Principle

15 The beautiful Magento Module November, 1st 2014

Does Magento have it?

The Open Closed Principle

16 The beautiful Magento Module November, 1st 2014

Configuration XML merging

Often the cause of conflicts

The Open Closed Principle

17 The beautiful Magento Module November, 1st 2014

Lets look deeper

The Open Closed Principle

18 The beautiful Magento Module November, 1st 2014

Self-Documenting Code

Method visibility and naming

The Open Closed Principle

19 The beautiful Magento Module November, 1st 2014

public Methods

Are an open invitation to the world

The Open Closed Principle

20 The beautiful Magento Module November, 1st 2014

public Methods

Once published should never change their signature or functionality

The Open Closed Principle

21 The beautiful Magento Module November, 1st 2014

protected Methods

Communicate “override me!”

The Open Closed Principle

22 The beautiful Magento Module November, 1st 2014

protected Methods

Change in signature or functionality risks breaking subclasses

The Open Closed Principle

23 The beautiful Magento Module November, 1st 2014

private Methods

Safe to change

The Open Closed Principle

24 The beautiful Magento Module November, 1st 2014

How is method visibility used in Magento?

Only public and protected

A too open design!

The Open Closed Principle

25 The beautiful Magento Module November, 1st 2014

A good example ofmethod visibility documentinghow to extend a class.

26 The beautiful Magento Module November, 1st 2014

abstract class Mage_Core_Block_Abstract ...{ final public function toHtml() { // ...housekeeping $html = $this->_toHtml(); // ...more housekeeping

return $html; }

protected function _toHtml() { return ''; }

A good example from the core how method visibility helps

The Open Closed Principle

27 The beautiful Magento Module November, 1st 2014

Another good example of OCP

Event Observers

The Open Closed Principle

28 The beautiful Magento Module November, 1st 2014

How can we apply this principleto our modules?

By dispatching events

29 The beautiful Magento Module November, 1st 2014

Mage::dispatchEvent('events_example_import_prepare', ['importer' => $this]);

// ...

Mage::dispatchEvent( 'events_example_import_batch_start', ['importer' => $this, 'batch' => $batch]);

// ...

Mage::dispatchEvent( 'events_example_import_batch_end', ['importer' => $this, 'batch' => $batch]);

// ...

Mage::dispatchEvent('events_example_import_complete', ['importer' => $this]);

Choosing strategic places to dispatch events.

The Open Closed Principle

30 The beautiful Magento Module November, 1st 2014

Favor domain events overinstructional events

The Open Closed Principle

31 The beautiful Magento Module November, 1st 2014

Choose the right method visibility

Use private as the default

The Open Closed Principle

32 The beautiful Magento Module November, 1st 2014

Use the Magento Factory Methodsand Class Aliases

33 The beautiful Magento Module November, 1st 2014

Rewrites are applied during class name resolution.

Using a Factory Method with a PHP class nameis no better then using new.

$notLikeThis = new Mage_Catalog_Model_Product();

$badExample = Mage::getModel('Mage_Catalog_Model_Product');

34 The beautiful Magento Module November, 1st 2014

Rewrites are applied during class name resolution.

Using class aliases allows for rewrites.

$correctlyInstantiated = Mage::getModel('catalog/product');

gist of class name resolution steps: http://vin.ai/class-name-resolution

35 The beautiful Magento Module November, 1st 2014

$model = Mage::getModel('example_module/import_parser_xml');$resource = Mage::getResourceModel('example_module/search');$helper = Mage::helper('example_module');$block = Mage::app()->getLayout()->createBlock('example_module/list');

To keep our code open for extension, we should use class aliases for our classes.

36 The beautiful Magento Module November, 1st 2014

Encapsulate what varies

37 The beautiful Magento Module November, 1st 2014

“Encapsulate the Concept that Varies, i.e. a design is better when those parts that vary are encapsulated in a separate module”On the Criteria To Be Used inDecomposing Systems into ModulesDavid Parnas

Encapsulate what varies

38 The beautiful Magento Module November, 1st 2014

Keep changes local so they don't affect other parts of the system

Encapsulate what varies

39 The beautiful Magento Module November, 1st 2014

Magento, do you ECV?

Encapsulate what varies

40 The beautiful Magento Module November, 1st 2014

First some "missed opportunities"

Encapsulate what varies

41 The beautiful Magento Module November, 1st 2014

Configuration of theTax Calculation Algorithm

42 The beautiful Magento Module November, 1st 2014

// from Mage_Tax_Model_Sales_Quote_Tax::collect()

switch ($this->_config->getAlgorithm($this->_store)) { case Mage_Tax_Model_Calculation::CALC_UNIT_BASE: $this->_unitBaseCalculation($address, $request); break; case Mage_Tax_Model_Calculation::CALC_ROW_BASE: $this->_rowBaseCalculation($address, $request); break; case Mage_Tax_Model_Calculation::CALC_TOTAL_BASE: $this->_totalBaseCalculation($address, $request); break; default: break;}

Choosing the tax calculation algorithm based on the system configuration

Encapsulate what varies

43 The beautiful Magento Module November, 1st 2014

Order State Management

44 The beautiful Magento Module November, 1st 2014

public function canCancel(){ if (!$this->_canVoidOrder()) { return false; } if ($this->canUnhold()) { // $this->isPaymentReview() return false; } // ... more of the same + comments removed for brevity...

$state = $this->getState(); if ($this->isCanceled() || $state === self::STATE_COMPLETE || $state === self::STATE_CLOSED) { return false; }

if ($this->getActionFlag(self::ACTION_FLAG_CANCEL) === false) { return false; } return true;}

Example of sales/order state behavior management

45 The beautiful Magento Module November, 1st 2014

class Mage_Sales_Model_Order_State_Complete implements OrderState{ public function canInvoice() { return false; } public function canShip() { return false; } public function canReorder() { return true; }

// ...

Theoretical example of encapsulating the stateful behavior

Encapsulate what varies

46 The beautiful Magento Module November, 1st 2014

Where does the core adhere to the principle, at least in parts?

Encapsulate what varies

47 The beautiful Magento Module November, 1st 2014

Total Models

Total calculationPreparation of display data

Encapsulate what varies

48 The beautiful Magento Module November, 1st 2014

EAV Attribute Models

Backend,Source and Frontend models

Encapsulate what varies

49 The beautiful Magento Module November, 1st 2014

How can we apply this principlein our Modules?

Encapsulate what varies

50 The beautiful Magento Module November, 1st 2014

A simple example scenario

Add informationdepending on a the attribute setto the product detail page.

Encapsulate what varies

51 The beautiful Magento Module November, 1st 2014

A simple example scenario

Kitchen Attribute Set

Chair Attribute Set

Insurance Attribute Set

52 The beautiful Magento Module November, 1st 2014

private function getTemplateForAttributeSet(){ switch ($this->getAttributeSetId()) { case $this->kitchenAttributeSetId: return 'example/attributesetinfo/kitchen-info.phtml'; case $this->chairAttributeSetId: return 'example/attributesetinfo/chair-info.phtml'; case $this->insuranceAttributeSetId: return 'example/attributesetinfo/insurance-info.phtml'; }}

First try, not adhering to the principle

53 The beautiful Magento Module November, 1st 2014

private function getTemplateForAttributeSet(){ switch ($this->getAttributeSetId()) { case $this->kitchenAttributeSetId: return 'example/attributesetinfo/kitchen-info.phtml'; case $this->chairAttributeSetId: return 'example/attributesetinfo/chair-info.phtml'; case $this->insuranceAttributeSetId: return 'example/attributesetinfo/insurance-info.phtml'; }}

public function getChairCoverWashingInstructionsPDFUrl() {...}

public function getInsuranceTermsAndConditions() {...}

public function getKitchenDesignPdfUrl() {...}

public function getServicePartnerDirectoryUrl() {...}

The block also needs to provide all the methods called from the templates

Encapsulate what varies

54 The beautiful Magento Module November, 1st 2014

Decomposed classes

Kitchen Attribute Set Info Block

Chair Attribute Set Info Block

Insurance Attribute Set Info Block

Attribute Set Info Block Locator

55 The beautiful Magento Module November, 1st 2014

class Example_AttributeSetInfo_Block_InfoBlockLocator extends Mage_Core_Block_Text_List{ // ...}

The locator extends core/text_list

56 The beautiful Magento Module November, 1st 2014

protected function _prepareLayout(){ $infoBlockAlias = $this->_getInfoBlockClassAlias(); if (null !== $infoBlockAlias) { $this->insert($this->_createChildBlock($infoBlockAlias)); }}

private function _getInfoBlockClassAlias(){ switch ($this->getAttributeSetId()) { case $this->kitchenAttributeSetId: return 'example_attributesetinfo/info_kitchen'; case $this->chairAttributeSetId: return 'example_attributesetinfo/info_chair'; case $this->insuranceAttributeSetId: return 'example_attributesetinfo/info_insurance'; }}

Select and instantiate the delegate object

57 The beautiful Magento Module November, 1st 2014

class Example_AttributeSetInfo_Block_Info_Chair extends Mage_Core_Block_Template{ protected function _prepareLayout() { $this->setTemplate('example/attributesetinfo/chair-info.phtml'); }

public function getChairCoverWashingInstructionsPDFUrl() { return 'the url of the chair cover washing instructions pdf'; }}

The attribute set dependent differences are encapsulated

Encapsulate what varies

58 The beautiful Magento Module November, 1st 2014

What would be affected by change?

What would be affected by adding an attribute set?

What would be affected if the output for one attribute set needs to change?

59 The beautiful Magento Module November, 1st 2014

More Principles

60 The beautiful Magento Module November, 1st 2014

What else makes a module beautiful?

61 The beautiful Magento Module November, 1st 2014

Readable Code

Readable Code

62 The beautiful Magento Module November, 1st 2014

What makes code readable?

Coding Standard

63 The beautiful Magento Module November, 1st 2014

private function getInfoBlockClassAliasBadExample () { if ($this->getAttributeSetId()==$this->kitchenAttributeSetId) return 'example_attributesetinfo/info_kitchen'; if($this->chairAttributeSetId == $this->getAttributeSetId()) return 'example_attributesetinfo/info_chair'; else // insurance attribute set return 'example_attributesetinfo/info_insurance';}

private function getInfoBlockClassAliasGoodExample(){ switch ($this->getAttributeSetId()) { case $this->kitchenAttributeSetId: return 'example_attributesetinfo/info_kitchen'; case $this->chairAttributeSetId: return 'example_attributesetinfo/info_chair'; case $this->insuranceAttributeSetId: return 'example_attributesetinfo/info_insurance'; }}

Obviously

Readable Code

64 The beautiful Magento Module November, 1st 2014

What else makes code readable?

Descriptive method names

Readable Code

65 The beautiful Magento Module November, 1st 2014

How can we choose good method names?

A method should do only one thing.The name should state that thing.

Readable Code

66 The beautiful Magento Module November, 1st 2014

If naming a method is hard split it into smaller ones.

Readable Code

67 The beautiful Magento Module November, 1st 2014

First some examples of method names that could be improved

68 The beautiful Magento Module November, 1st 2014

protected function _construct(){ $this->_init('example_module/foo');}

One bad example straight out of the Magento ORM

69 The beautiful Magento Module November, 1st 2014

protected function _initializeCollection(){ $this->_setModelClassAlias('example_module/foo');}

I find this would be nicer to read

70 The beautiful Magento Module November, 1st 2014

public function isNewObject() {...}

public function hasChildren() {...}

Methods returning a boolean value should start with is or has

Readable Code

71 The beautiful Magento Module November, 1st 2014

$request->setDispatched(false)

Setters should start with set

Readable Code

Readable Code

72 The beautiful Magento Module November, 1st 2014

Some more good bad examples

73 The beautiful Magento Module November, 1st 2014

// from Mage_Catalog_Model_Category

public function getChildrenCategories() {...}public function getChildrenCategoriesWithInactive() {...}public function getChildren() {...}public function getAllChildren(...) {...}public function getCategories(...) {...}

Similar methods need very descriptive names to be self documenting

74 The beautiful Magento Module November, 1st 2014

// from Mage_Core_Model_Email

public function __construct(){ // TODO: move to config $this->setFromName('Magento'); $this->setFromEmail('magento@varien.com'); $this->setType('text');}

Dead code should be removed without mercy

75 The beautiful Magento Module November, 1st 2014

// from Mage_Shipping_Model_Carrier_Abstract

public function getTotalNumOfBoxes($weight){ // ... return $weight;}

WTF

76 The beautiful Magento Module November, 1st 2014

Wrap up

Wrap up

77 The beautiful Magento Module November, 1st 2014

What qualifies a Magento module as beautiful?

1.It provides business value2.Magento can be upgraded without breaking the module3.It is easy to understand and modify4.It has good test coverage5.It is free of bugs

78 The beautiful Magento Module November, 1st 2014

Further reading

Further reading

79 The beautiful Magento Module November, 1st 2014

Link to Amazon

Further reading

80 The beautiful Magento Module November, 1st 2014

Link to Amazon

Further reading

81 The beautiful Magento Module November, 1st 2014

Link to Amazon

Further reading

82 The beautiful Magento Module November, 1st 2014

Link to Amazon

83 The beautiful Magento Module November, 1st 2014

Thank you

84 The beautiful Magento Module November, 1st 2014

Questions | Comments

Tweet me @VinaiKopphttp://vinaikopp.com