the beautiful magento module - magetitans 2014

84
Manchester, November 1st 2014 Vinai Kopp

Upload: vinaikopp

Post on 20-Aug-2015

1.764 views

Category:

Software


1 download

TRANSCRIPT

Page 1: The beautiful Magento module - MageTitans 2014

Manchester, November 1st 2014

Vinai Kopp

Page 2: The beautiful Magento module - MageTitans 2014

Introduction

2 The beautiful Magento Module November, 1st 2014

Magento 1.x

Page 3: The beautiful Magento module - MageTitans 2014

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 :)

Page 4: The beautiful Magento module - MageTitans 2014

Introduction

4 The beautiful Magento Module November, 1st 2014

This is not an introduction into Magento development.

Page 5: The beautiful Magento module - MageTitans 2014

Introduction

5 The beautiful Magento Module November, 1st 2014

How cana Magento modulebe "beautiful"?

Page 6: The beautiful Magento module - MageTitans 2014

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

Page 7: The beautiful Magento module - MageTitans 2014

7 The beautiful Magento Module November, 1st 2014

Principles and Patterns

Page 8: The beautiful Magento module - MageTitans 2014

Principles and Patterns

8 The beautiful Magento Module November, 1st 2014

Robert C. Martin (Uncle Bob)

Page 9: The beautiful Magento module - MageTitans 2014

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)

Page 10: The beautiful Magento module - MageTitans 2014

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)

Page 11: The beautiful Magento module - MageTitans 2014

Principles and Patterns

11 The beautiful Magento Module November, 1st 2014

What have you done for me lately, principles?

Page 12: The beautiful Magento module - MageTitans 2014

Principles and Patterns

12 The beautiful Magento Module November, 1st 2014

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

Page 13: The beautiful Magento module - MageTitans 2014

13 The beautiful Magento Module November, 1st 2014

Open Closed Principle

Page 14: The beautiful Magento module - MageTitans 2014

14 The beautiful Magento Module November, 1st 2014

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

The Open Closed PrincipleUncle Bob

Page 15: The beautiful Magento module - MageTitans 2014

The Open Closed Principle

15 The beautiful Magento Module November, 1st 2014

Does Magento have it?

Page 16: The beautiful Magento module - MageTitans 2014

The Open Closed Principle

16 The beautiful Magento Module November, 1st 2014

Configuration XML merging

Often the cause of conflicts

Page 17: The beautiful Magento module - MageTitans 2014

The Open Closed Principle

17 The beautiful Magento Module November, 1st 2014

Lets look deeper

Page 18: The beautiful Magento module - MageTitans 2014

The Open Closed Principle

18 The beautiful Magento Module November, 1st 2014

Self-Documenting Code

Method visibility and naming

Page 19: The beautiful Magento module - MageTitans 2014

The Open Closed Principle

19 The beautiful Magento Module November, 1st 2014

public Methods

Are an open invitation to the world

Page 20: The beautiful Magento module - MageTitans 2014

The Open Closed Principle

20 The beautiful Magento Module November, 1st 2014

public Methods

Once published should never change their signature or functionality

Page 21: The beautiful Magento module - MageTitans 2014

The Open Closed Principle

21 The beautiful Magento Module November, 1st 2014

protected Methods

Communicate “override me!”

Page 22: The beautiful Magento module - MageTitans 2014

The Open Closed Principle

22 The beautiful Magento Module November, 1st 2014

protected Methods

Change in signature or functionality risks breaking subclasses

Page 23: The beautiful Magento module - MageTitans 2014

The Open Closed Principle

23 The beautiful Magento Module November, 1st 2014

private Methods

Safe to change

Page 24: The beautiful Magento module - MageTitans 2014

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!

Page 25: The beautiful Magento module - MageTitans 2014

The Open Closed Principle

25 The beautiful Magento Module November, 1st 2014

A good example ofmethod visibility documentinghow to extend a class.

Page 26: The beautiful Magento module - MageTitans 2014

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

Page 27: The beautiful Magento module - MageTitans 2014

The Open Closed Principle

27 The beautiful Magento Module November, 1st 2014

Another good example of OCP

Event Observers

Page 28: The beautiful Magento module - MageTitans 2014

The Open Closed Principle

28 The beautiful Magento Module November, 1st 2014

How can we apply this principleto our modules?

By dispatching events

Page 29: The beautiful Magento module - MageTitans 2014

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.

Page 30: The beautiful Magento module - MageTitans 2014

The Open Closed Principle

30 The beautiful Magento Module November, 1st 2014

Favor domain events overinstructional events

Page 31: The beautiful Magento module - MageTitans 2014

The Open Closed Principle

31 The beautiful Magento Module November, 1st 2014

Choose the right method visibility

Use private as the default

Page 32: The beautiful Magento module - MageTitans 2014

The Open Closed Principle

32 The beautiful Magento Module November, 1st 2014

Use the Magento Factory Methodsand Class Aliases

Page 33: The beautiful Magento module - MageTitans 2014

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');

Page 34: The beautiful Magento module - MageTitans 2014

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

Page 35: The beautiful Magento module - MageTitans 2014

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.

Page 36: The beautiful Magento module - MageTitans 2014

36 The beautiful Magento Module November, 1st 2014

Encapsulate what varies

Page 37: The beautiful Magento module - MageTitans 2014

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

Page 38: The beautiful Magento module - MageTitans 2014

Encapsulate what varies

38 The beautiful Magento Module November, 1st 2014

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

Page 39: The beautiful Magento module - MageTitans 2014

Encapsulate what varies

39 The beautiful Magento Module November, 1st 2014

Magento, do you ECV?

Page 40: The beautiful Magento module - MageTitans 2014

Encapsulate what varies

40 The beautiful Magento Module November, 1st 2014

First some "missed opportunities"

Page 41: The beautiful Magento module - MageTitans 2014

Encapsulate what varies

41 The beautiful Magento Module November, 1st 2014

Configuration of theTax Calculation Algorithm

Page 42: The beautiful Magento module - MageTitans 2014

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

Page 43: The beautiful Magento module - MageTitans 2014

Encapsulate what varies

43 The beautiful Magento Module November, 1st 2014

Order State Management

Page 44: The beautiful Magento module - MageTitans 2014

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

Page 45: The beautiful Magento module - MageTitans 2014

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

Page 46: The beautiful Magento module - MageTitans 2014

Encapsulate what varies

46 The beautiful Magento Module November, 1st 2014

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

Page 47: The beautiful Magento module - MageTitans 2014

Encapsulate what varies

47 The beautiful Magento Module November, 1st 2014

Total Models

Total calculationPreparation of display data

Page 48: The beautiful Magento module - MageTitans 2014

Encapsulate what varies

48 The beautiful Magento Module November, 1st 2014

EAV Attribute Models

Backend,Source and Frontend models

Page 49: The beautiful Magento module - MageTitans 2014

Encapsulate what varies

49 The beautiful Magento Module November, 1st 2014

How can we apply this principlein our Modules?

Page 50: The beautiful Magento module - MageTitans 2014

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.

Page 51: The beautiful Magento module - MageTitans 2014

Encapsulate what varies

51 The beautiful Magento Module November, 1st 2014

A simple example scenario

Kitchen Attribute Set

Chair Attribute Set

Insurance Attribute Set

Page 52: The beautiful Magento module - MageTitans 2014

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

Page 53: The beautiful Magento module - MageTitans 2014

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

Page 54: The beautiful Magento module - MageTitans 2014

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

Page 55: The beautiful Magento module - MageTitans 2014

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

Page 56: The beautiful Magento module - MageTitans 2014

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

Page 57: The beautiful Magento module - MageTitans 2014

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

Page 58: The beautiful Magento module - MageTitans 2014

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?

Page 59: The beautiful Magento module - MageTitans 2014

59 The beautiful Magento Module November, 1st 2014

More Principles

Page 60: The beautiful Magento module - MageTitans 2014

60 The beautiful Magento Module November, 1st 2014

What else makes a module beautiful?

Page 61: The beautiful Magento module - MageTitans 2014

61 The beautiful Magento Module November, 1st 2014

Readable Code

Page 62: The beautiful Magento module - MageTitans 2014

Readable Code

62 The beautiful Magento Module November, 1st 2014

What makes code readable?

Coding Standard

Page 63: The beautiful Magento module - MageTitans 2014

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

Page 64: The beautiful Magento module - MageTitans 2014

Readable Code

64 The beautiful Magento Module November, 1st 2014

What else makes code readable?

Descriptive method names

Page 65: The beautiful Magento module - MageTitans 2014

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.

Page 66: The beautiful Magento module - MageTitans 2014

Readable Code

66 The beautiful Magento Module November, 1st 2014

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

Page 67: The beautiful Magento module - MageTitans 2014

Readable Code

67 The beautiful Magento Module November, 1st 2014

First some examples of method names that could be improved

Page 68: The beautiful Magento module - MageTitans 2014

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

Page 69: The beautiful Magento module - MageTitans 2014

69 The beautiful Magento Module November, 1st 2014

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

I find this would be nicer to read

Page 70: The beautiful Magento module - MageTitans 2014

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

Page 71: The beautiful Magento module - MageTitans 2014

71 The beautiful Magento Module November, 1st 2014

$request->setDispatched(false)

Setters should start with set

Readable Code

Page 72: The beautiful Magento module - MageTitans 2014

Readable Code

72 The beautiful Magento Module November, 1st 2014

Some more good bad examples

Page 73: The beautiful Magento module - MageTitans 2014

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

Page 74: The beautiful Magento module - MageTitans 2014

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('[email protected]'); $this->setType('text');}

Dead code should be removed without mercy

Page 75: The beautiful Magento module - MageTitans 2014

75 The beautiful Magento Module November, 1st 2014

// from Mage_Shipping_Model_Carrier_Abstract

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

WTF

Page 76: The beautiful Magento module - MageTitans 2014

76 The beautiful Magento Module November, 1st 2014

Wrap up

Page 77: The beautiful Magento module - MageTitans 2014

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

Page 78: The beautiful Magento module - MageTitans 2014

78 The beautiful Magento Module November, 1st 2014

Further reading

Page 79: The beautiful Magento module - MageTitans 2014

Further reading

79 The beautiful Magento Module November, 1st 2014

Link to Amazon

Page 80: The beautiful Magento module - MageTitans 2014

Further reading

80 The beautiful Magento Module November, 1st 2014

Link to Amazon

Page 81: The beautiful Magento module - MageTitans 2014

Further reading

81 The beautiful Magento Module November, 1st 2014

Link to Amazon

Page 82: The beautiful Magento module - MageTitans 2014

Further reading

82 The beautiful Magento Module November, 1st 2014

Link to Amazon

Page 83: The beautiful Magento module - MageTitans 2014

83 The beautiful Magento Module November, 1st 2014

Thank you

Page 84: The beautiful Magento module - MageTitans 2014

84 The beautiful Magento Module November, 1st 2014

Questions | Comments

Tweet me @VinaiKopphttp://vinaikopp.com