Vinai Kopp - MM15NL

71
Meet-Magento NL, 28. May 2015 Vinai Kopp

Transcript of Vinai Kopp - MM15NL

Page 1: Vinai Kopp - MM15NL

Meet-Magento NL, 28. May 2015

Vinai Kopp

Page 2: Vinai Kopp - MM15NL

About Vinai

2 The beautiful Magento Module November, 1st 2014

„Coding and Magento are obviously important parts of my life. But there is more then that. When I am not diving into the code or giving trainings, I like to spend time with my family, to run, to swim and to tend to my bees.”

Page 3: Vinai Kopp - MM15NL

3 Modern Module Architecture Meet-Magento NL, 28. May 2015

Why Architecture?

Page 4: Vinai Kopp - MM15NL

Motivation

4 Modern Module Architecture Meet-Magento NL, 28. May 2015

„We want our applications to contain two attributes: 1. High Maintainability 2. Low Technical Debt”

Chris Fidao Author of Implementing Laravel

Page 5: Vinai Kopp - MM15NL

5 Modern Module Architecture Meet-Magento NL, 28. May 2015

The Story

A Startup Delivery Service

Page 6: Vinai Kopp - MM15NL

Headline Georgia 28. Introduction

6 Modern Module Architecture Meet-Magento NL, 28. May 2015

Copy Georgia 20. Hi. I’m Vinai. This talk is about Magento 1. I think it is important to understand as much as possible about Magento 1, as it is the basis for Magento 2, where the framework has received …

normale Seite Inhalt

Page 7: Vinai Kopp - MM15NL

Headline Georgia 28. Introduction

7 Modern Module Architecture Meet-Magento NL, 28. May 2015

Copy Georgia 20. Hi. I’m Vinai. This talk is about Magento 1. I think it is important to understand as much as possible about Magento 1, as it is the basis for Magento 2, where the framework has received …

normale Seite Inhalt

Page 8: Vinai Kopp - MM15NL

8 Modern Module Architecture Meet-Magento NL, 28. May 2015

Page 9: Vinai Kopp - MM15NL

Customer Groups

9 Modern Module Architecture

Guest (NOT LOGGED IN) + General:

Delivery only to specified postcodes

Meet-Magento NL, 28. May 2015

Wholesale:

Approved at registration, no postcode check

Page 10: Vinai Kopp - MM15NL

THINK BIG

10 Modern Module Architecture

Franchise

Meet-Magento NL, 28. May 2015

Countries

Page 11: Vinai Kopp - MM15NL

Postcode Filter Rules

11 Modern Module Architecture Meet-Magento NL, 28. May 2015

Rule  Field   Example  Rule  1  

Country   AT  

Customer  Groups   NOT  LOGGED  IN,  General  

Postcodes   1,  2,  13,  12  

Rule  Field   Example  Rule  2  

Country   NL  

Customer  Groups   NOT  LOGGED  IN,  General  

Postcodes   3500,  3521,  3527,  ...  

Page 12: Vinai Kopp - MM15NL

Wholesaler

12 Modern Module Architecture

No matching rule ===

delivery allowed

Meet-Magento NL, 28. May 2015

Page 13: Vinai Kopp - MM15NL

13 Modern Module Architecture Meet-Magento NL, 28. May 2015

Implementation #1

A Magento Module

Page 14: Vinai Kopp - MM15NL

Typical Magento Module

14 Modern Module Architecture

1.  Create app/code/local/FoodInJar/PostCodeFilter/

2.  Create postcodefilter_rule table with setup script

3.  Create Rule model, resource model and collection

4.  Create admin grid and form and controller

5.  Create Observer for checkout integration

6.  Create Ajax controller for additional frontend integration

Meet-Magento NL, 28. May 2015

Page 15: Vinai Kopp - MM15NL

Typical Magento Module

15 Modern Module Architecture

What does this code tell you?

Meet-Magento NL, 28. May 2015

„ I am a Magento Module.”

Page 16: Vinai Kopp - MM15NL

Typical Magento Module

16 Modern Module Architecture

How reusable is it?

Meet-Magento NL, 28. May 2015

„Well … not really.”

Page 17: Vinai Kopp - MM15NL

Typical Magento Module

17 Modern Module Architecture

Are there any tests?

Meet-Magento NL, 28. May 2015

„Why bother, it's boilerplate!”

Page 18: Vinai Kopp - MM15NL

Typical Magento Module

18 Modern Module Architecture

Does it work well with other extensions? Does it work with a new version of Magento 1.x? How fast can changes to the filter rules be implemented? How quickly can a new developer start to work on the code? How long to deployment after a bug was fixed? Can I use it in Magento 2?

Meet-Magento NL, 28. May 2015

Page 19: Vinai Kopp - MM15NL

Typical Magento Module

19 Modern Module Architecture Meet-Magento NL, 28. May 2015

„Okay, I admit it. Tests do add value.”

Page 20: Vinai Kopp - MM15NL

20 Modern Module Architecture Meet-Magento NL, 28. May 2015

Implementation #2

A Decoupled Architecture

Page 21: Vinai Kopp - MM15NL

Implementation #2

21 Modern Module Architecture Meet-Magento NL, 28. May 2015

A PHP Library

Page 22: Vinai Kopp - MM15NL

Decoupling

22 Modern Module Architecture Meet-Magento NL, 28. May 2015

My PostCodeFilter Code

Page 23: Vinai Kopp - MM15NL

Decoupling

23 Modern Module Architecture Meet-Magento NL, 28. May 2015

My PostCodeFilter Code 2

Page 24: Vinai Kopp - MM15NL

Decoupling

24 Modern Module Architecture Meet-Magento NL, 28. May 2015

My PostCodeFilter Code

Page 25: Vinai Kopp - MM15NL

Decoupling

25 Modern Module Architecture Meet-Magento NL, 28. May 2015

My PostCodeFilter Code

Page 26: Vinai Kopp - MM15NL

Flow of Information

26 Modern Module Architecture Meet-Magento NL, 28. May 2015

My PostCodeFilter Code

Storage  

Page 27: Vinai Kopp - MM15NL

User  Interface  

ApplicaHon  

Domain  

Infrastructure  

Implementation as a Library

27 Modern Module Architecture

Layered Architecture

Meet-Magento NL, 28. May 2015

Page 28: Vinai Kopp - MM15NL

User  Interface  (Delivery)  

ApplicaHon  (Use  Cases)  

Domain  (Problem  Space)  

Infrastructure  (DB)  

Implementation as a Library

28 Modern Module Architecture

Layered Architecture

Meet-Magento NL, 28. May 2015

Page 29: Vinai Kopp - MM15NL

Implementation as a Library

29 Modern Module Architecture

Ports & Adapters

Hexagonical Architecture

Meet-Magento NL, 28. May 2015

Alistair Cockburn

http://alistair.cockburn.us/Hexagonal+architecture

„ Allow an application to equally be driven by users, programs, automated test or batch scripts, and to be developed and tested in isolation from its eventual run-time devices and databases.”

Page 30: Vinai Kopp - MM15NL

Implementation as a Library

30 Modern Module Architecture Meet-Magento NL, 28. May 2015

UI

Storage

Application +

Domain

Page 31: Vinai Kopp - MM15NL

Implementation as a Library

31 Modern Module Architecture Meet-Magento NL, 28. May 2015

Web

Tests

Mock DB

CSV MySQL

SOAP API

Tests

Application +

Domain

Email

Page 32: Vinai Kopp - MM15NL

Implementation as a Library

32 Modern Module Architecture Meet-Magento NL, 28. May 2015

Postcode Filter Rules

Magento Admin Tests

Magento Frontend

Magento DB

Page 33: Vinai Kopp - MM15NL

Implementation as a Library

33 Modern Module Architecture

Well... where do I start…?

Meet-Magento NL, 28. May 2015

Page 34: Vinai Kopp - MM15NL

34 Modern Module Architecture

class CustomerSpecifiesShippingAddressTest extends \PHPUnit_Framework_TestCase { /** * @test */ public function itShouldReturnFalseIfTheCustomerMayNotOrder() { $this->assertFalse( $customerSpecifiesShippingAddress->isAllowedDestination( $customerGroupId, $country, $postCode ) ); } }

Test First

Meet-Magento NL, 28. May 2015

Page 35: Vinai Kopp - MM15NL

35 Modern Module Architecture

class CustomerSpecifiesShippingAddress { public function isAllowedDestination( $customerGroupId, $iso2country, $postCode ) { return false; } }

Test First

Meet-Magento NL, 28. May 2015

Page 36: Vinai Kopp - MM15NL

Implementation as a Library

36 Modern Module Architecture

Use Case Orientated Design

Meet-Magento NL, 28. May 2015

Page 37: Vinai Kopp - MM15NL

Implementation as a Library

37 Modern Module Architecture

Value Objects

Meet-Magento NL, 28. May 2015

Page 38: Vinai Kopp - MM15NL

Implementation as a Library

38 Modern Module Architecture

„ Architecture exposes usage”

Uncle Bob Martin

 

Meet-Magento NL, 28. May 2015

Page 39: Vinai Kopp - MM15NL

Plugging the Library into Magento

39 Modern Module Architecture Meet-Magento NL, 28. May 2015

My PostCodeFilter Code

Storage  

Page 40: Vinai Kopp - MM15NL

Plugging the Library into Magento

40 Modern Module Architecture Meet-Magento NL, 28. May 2015

My PostCodeFilter Code

Storage  

Page 41: Vinai Kopp - MM15NL

Using the Library in a Magento Module

41 Modern Module Architecture

Checking Customer Postcodes

Meet-Magento NL, 28. May 2015

My PostCodeFilter Code

Page 42: Vinai Kopp - MM15NL

42 Modern Module Architecture

use \Varien_Event_Observer as Event; use VinaiKopp\PostCodeFilter\CustomerSpecifiesShippingAddress; class VinaiKopp_PostCodeFilter_Model_Observer { // ... public function checkPostCodeIsAllowedIfNextStepIsShippingMethod( Event $event ) { /** @var Mage_Core_Controller_Response_Http $response */ $response = $event->getData('controller_action')->getResponse(); if ($this->isNextStepShippingMethod($response)) { $quote = $this->getCurrentCustomerQuote(); if (!$this->quoteMayBeOrdered($quote, $quote->getShippingAddress())) { $this->setErrorJsonResponse( $response, $quote->getShippingAddress() ); } } }

Query Postcode Filter Rules

Meet-Magento NL, 28. May 2015

Page 43: Vinai Kopp - MM15NL

43 Modern Module Architecture

use \Varien_Event_Observer as Event; use VinaiKopp\PostCodeFilter\CustomerSpecifiesShippingAddress; class VinaiKopp_PostCodeFilter_Model_Observer { // ... private function quoteMayBeOrdered( Mage_Sales_Model_Quote $quote, Mage_Sales_Model_Quote_Address $shippingAddress ) { $useCase = $this->getCustomerSpecifiesPostCodeUseCase(); return $useCase->isAllowedDestination( (int)$quote->getCustomerGroupId(), $shippingAddress->getCountry(), $shippingAddress->getPostcode() ); }

Query Postcode Filter Rules

Meet-Magento NL, 28. May 2015

Page 44: Vinai Kopp - MM15NL

Using the Library in a Magento Module

44 Modern Module Architecture

Storing Postcode Filter Rules in the Magento DB

Meet-Magento NL, 28. May 2015

Page 45: Vinai Kopp - MM15NL

Using the Library in a Magento Module

45 Modern Module Architecture Meet-Magento NL, 28. May 2015

My PostCodeFilter Code

Storage  

Page 46: Vinai Kopp - MM15NL

46 Modern Module Architecture

namespace VinaiKopp\PostCodeFilter; interface RuleStorage { public function findPostCodesByCountryAndGroupId( $iso2country, $customerGroupId ); public function findRulesByCountryAndGroupIds( $iso2country, array $customerGroupIds ); public function findAllRules(); public function create($iso2country, $customerGroupId, array $postCodes); public function delete($iso2country, $customerGroupId); public function beginTransaction(); public function commitTransaction(); public function rollbackTransaction(); }

Storage Interface (Library Side)

Meet-Magento NL, 28. May 2015

Page 47: Vinai Kopp - MM15NL

47 Modern Module Architecture

use VinaiKopp\PostCodeFilter\RuleStorage; class VinaiKopp_PostCodeFilter_Model_Resource_RuleStorage implements RuleStorage { public function findPostCodesByCountryAndGroupId( $iso2country, $customerGroupId ) { $query = $this->readConnection->select() ->from($this->tableName, 'post_codes') ->where('country=?', $iso2country) ->where('customer_group_id=?', $customerGroupId); $result = $this->readConnection->fetchOne($query); if (! $result) { return []; } return $this->splitPostCodes($result); // ... }

Storage Implementation (Magento Side)

Meet-Magento NL, 28. May 2015

Page 48: Vinai Kopp - MM15NL

Instantiation of Library Classes

48 Modern Module Architecture Meet-Magento NL, 28. May 2015

Creating Something from Nothing

Page 49: Vinai Kopp - MM15NL

49 Modern Module Architecture

use VinaiKopp\PostCodeFilter\CustomerSpecifiesShippingAddress; class VinaiKopp_PostCodeFilter_Helper_Factory extends Mage_Core_Helper_Abstract { // ... public function createCustomerChecksPostCodeUseCase() { $this->registerPostCodeFilterAutoloader(); $class = 'vinaikopp_postcodefilter/ruleStorage' $storage = Mage::getResourceModel($class); return new CustomerSpecifiesShippingAddress( new RuleRepositoryReader($storage) ); }

Instantiation of Library Classes

Meet-Magento NL, 28. May 2015

Page 50: Vinai Kopp - MM15NL

50 Modern Module Architecture

class VinaiKopp_PostCodeFilter_Helper_Factory extends Mage_Core_Helper_Abstract { private $autoloaderRegistered = false; private function registerPostCodeFilterAutoloader() { if ($this->autoloaderRegistered) { return; } $this->autoloaderRegistered = true; spl_autoload_register(function ($class) { $prefix = 'VinaiKopp\\PostCodeFilter\\'; if (strncmp($prefix, $class, strlen($prefix)) !== 0) { return; } $this->buildPathToFileAndIncludeIfFileExists(); }, false, true); }

Instantiation of Library Classes

Meet-Magento NL, 28. May 2015

Page 51: Vinai Kopp - MM15NL

Using the Library in a Magento Module

51 Modern Module Architecture

Grid uses Adapter Collection

Meet-Magento NL, 28. May 2015

Page 52: Vinai Kopp - MM15NL

52 Modern Module Architecture

use VinaiKopp\PostCodeFilter\Rule\Rule; use VinaiKopp\PostCodeFilter\AdminViewsRuleList; class VinaiKopp_PostCodeFilter_Model_RuleCollection extends Varien_Data_Collection_Db { // ... public function load($printQuery = false, $logQuery = false) { $rules = $this->getUseCase()->fetchRules(); $this->_items = array_map([$this, 'convertRuleToVarienObject'], $rules); $this->_setIsLoaded(true); return $this; }

Collection adapts Postcode Filter Rules

Meet-Magento NL, 28. May 2015

Page 53: Vinai Kopp - MM15NL

53 Modern Module Architecture

use VinaiKopp\PostCodeFilter\Rule\Rule; use VinaiKopp\PostCodeFilter\AdminViewsRuleList; class VinaiKopp_PostCodeFilter_Model_RuleCollection extends Varien_Data_Collection_Db { // ... private function convertRuleToVarienObject(Rule $rule) { return new Varien_Object([ 'country' => $rule->getCountryValue(), 'customer_groups' => $rule->getCustomerGroupIdValues(), 'post_codes' => $rule->getPostCodeValues() ]); }

Collection adapts the Postcode Filter Rules

Meet-Magento NL, 28. May 2015

(GoF Adapter Pattern: Convert the interface of a class into another interface the clients expect.)

Page 54: Vinai Kopp - MM15NL

Dependencies

54 Modern Module Architecture Meet-Magento NL, 28. May 2015

OOP means Managing Dependencies

Page 55: Vinai Kopp - MM15NL

Using the Library in a Magento Module

55 Modern Module Architecture Meet-Magento NL, 28. May 2015

Page 56: Vinai Kopp - MM15NL

Using the Library in a Magento Module

56 Modern Module Architecture Meet-Magento NL, 28. May 2015

Page 57: Vinai Kopp - MM15NL

Visualizing Code Dependencies

57 Modern Module Architecture Meet-Magento NL, 28. May 2015

https://github.com/mamuz/PhpDependencyAnalysis

PhpDependencyAnalysis

Page 58: Vinai Kopp - MM15NL

Visualizing Code Dependencies: Call, Usage and Inheritance Graphs

58 Modern Module Architecture Meet-Magento NL, 28. May 2015

https://github.com/mamuz/PhpDependencyAnalysis

Page 59: Vinai Kopp - MM15NL

Does the Postcode Filter comply with the DIP?

59 Modern Module Architecture

Dependency Inversion Principle

Meet-Magento NL, 28. May 2015

•  High-level modules should not depend on low-level modules. Both should depend on abstractions.

•  Abstractions should not depend on details.

•  Details should depend on abstractions.

Page 60: Vinai Kopp - MM15NL

Summary

60 Modern Module Architecture

Costs vs. Benefits

Meet-Magento NL, 28. May 2015

- More code (Library + Magento Adapter)

Complexity

Page 61: Vinai Kopp - MM15NL

Summary

61 Modern Module Architecture

Costs vs. Benefits

Meet-Magento NL, 28. May 2015

- Increased development cost (the first few times)

Complexity

Page 62: Vinai Kopp - MM15NL

Summary

62 Modern Module Architecture

Costs vs. Benefits

Meet-Magento NL, 28. May 2015

- Development has to be more thoughtful

Complexity

Page 63: Vinai Kopp - MM15NL

Summary

63 Modern Module Architecture

Costs vs. Benefits

Meet-Magento NL, 28. May 2015

Freedom

Page 64: Vinai Kopp - MM15NL

Summary

64 Modern Module Architecture

Costs vs. Benefits

Meet-Magento NL, 28. May 2015

+ Lower maintenance costs (Domain code independent of framework, test coverage)

Freedom

Page 65: Vinai Kopp - MM15NL

Summary

65 Modern Module Architecture

Costs vs. Benefits

Meet-Magento NL, 28. May 2015

+ Developers unfamiliar with Magento more productive

Freedom

Page 66: Vinai Kopp - MM15NL

Summary

66 Modern Module Architecture

Costs vs. Benefits

Meet-Magento NL, 28. May 2015

+ Real reusability (on component and class level)

Freedom

Page 67: Vinai Kopp - MM15NL

Summary

67 Modern Module Architecture

Costs vs. Benefits

Meet-Magento NL, 28. May 2015

+ Better upgradability (only one side of the adapter affected)

Freedom

Page 68: Vinai Kopp - MM15NL

Summary

68 Modern Module Architecture

Costs vs. Benefits

Meet-Magento NL, 28. May 2015

+ Easier to reason about domain

Freedom

Page 69: Vinai Kopp - MM15NL

Summary

69 Modern Module Architecture

Costs vs. Benefits

Meet-Magento NL, 28. May 2015

+ Usable with other platforms or frameworks (are you ready for Magento 2?)

Freedom

Page 70: Vinai Kopp - MM15NL

Summary

70 Modern Module Architecture

Costs vs. Benefits

Meet-Magento NL, 28. May 2015

+ Developer Satisfaction (able to choose testing, design, methodology, dicipline)

Freedom

Page 71: Vinai Kopp - MM15NL

Thank you!

71 Modern Module Architecture

Please, Ask questions Share thoughts Now :)

Meet-Magento NL, 28. May 2015

Vinai Kopp | @VinaiKopp | [email protected] https://github.com/Vinai/VinaiKopp_PostCodeFilter