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

Modern Module Architecture

Embed Size (px)

Citation preview

Meet-Magento NL, 28. May 2015

Vinai Kopp

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.”

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

Why Architecture?

Motivation

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

„We want our applications to contain two attributes:

1.High Maintainability2.Low Technical Debt”

Chris FidaoAuthor of Implementing Laravel

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

The Story

A Startup Delivery Service

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 SeiteInhalt

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 SeiteInhalt

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

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

THINK BIG

10 Modern Module Architecture

Franchise

Meet-Magento NL, 28. May 2015

Countries

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, ...

Wholesaler

12 Modern Module Architecture

No matching rule===

delivery allowed

Meet-Magento NL, 28. May 2015

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

Implementation #1

A Magento Module

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

Typical Magento Module

15 Modern Module Architecture

What does this code tell you?

Meet-Magento NL, 28. May 2015

„ I am a Magento Module.”

Typical Magento Module

16 Modern Module Architecture

How reusable is it?

Meet-Magento NL, 28. May 2015

„Well … not really.”

Typical Magento Module

17 Modern Module Architecture

Are there any tests?

Meet-Magento NL, 28. May 2015

„Why bother, it's boilerplate!”

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

Typical Magento Module

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

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

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

Implementation #2

A Decoupled Architecture

Implementation #2

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

A PHP Library

Decoupling

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

MyPostCodeFilter Code

Decoupling

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

MyPostCodeFilter Code

2

Decoupling

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

MyPostCodeFilter Code

Decoupling

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

MyPostCodeFilter Code

Flow of Information

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

MyPostCodeFilter Code

Storage

Implementation as a Library

27 Modern Module Architecture

Layered Architecture

Meet-Magento NL, 28. May 2015

Implementation as a Library

28 Modern Module Architecture

Layered Architecture

Meet-Magento NL, 28. May 2015

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.”

Implementation as a Library

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

UI

Storage

Application+

Domain

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

Implementation as a Library

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

PostcodeFilterRules

MagentoAdmin

Tests

MagentoFrontend

MagentoDB

Implementation as a Library

33 Modern Module Architecture

Well... where do I start…?

Meet-Magento NL, 28. May 2015

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

35 Modern Module Architecture

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

Test First

Meet-Magento NL, 28. May 2015

Implementation as a Library

36 Modern Module Architecture

Use Case Orientated Design

Meet-Magento NL, 28. May 2015

Implementation as a Library

37 Modern Module Architecture

Value Objects

Meet-Magento NL, 28. May 2015

Implementation as a Library

38 Modern Module Architecture

„ Architecture exposes usage”

Uncle Bob Martin

Meet-Magento NL, 28. May 2015

Plugging the Library into Magento

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

MyPostCodeFilter Code

Plugging the Library into Magento

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

Storage

Using the Library in a Magento Module

41 Modern Module Architecture

Checking Customer Postcodes

Meet-Magento NL, 28. May 2015

MyPostCodeFilter Code

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

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

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

Using the Library in a Magento Module

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

MyPostCodeFilter Code

Storage

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

Interface

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

Implem

entation

Instantiation of Library Classes

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

Creating Somethingfrom Nothing

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

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

Using the Library in a Magento Module

51 Modern Module Architecture

Grid uses Adapter Collection

Meet-Magento NL, 28. May 2015

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

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

Dependencies

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

OOP meansManaging Dependencies

Using the Library in a Magento Module

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

Using the Library in a Magento Module

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

Visualizing Code Dependencies

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

https://github.com/mamuz/PhpDependencyAnalysis

PhpDependencyAnalysis

Visualizing Code Dependencies:Call, Usage and Inheritance Graphs

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

https://github.com/mamuz/PhpDependencyAnalysis

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.

Summary

60 Modern Module Architecture

Costs vs. Benefits

Meet-Magento NL, 28. May 2015

- More code (Library + Magento Adapter)

Complexity

Summary

61 Modern Module Architecture

Costs vs. Benefits

Meet-Magento NL, 28. May 2015

- Increased development cost(the first few times)

Complexity

Summary

62 Modern Module Architecture

Costs vs. Benefits

Meet-Magento NL, 28. May 2015

- Development has to be more thoughtful

Complexity

Summary

63 Modern Module Architecture

Costs vs. Benefits

Meet-Magento NL, 28. May 2015

Freedom

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

Summary

65 Modern Module Architecture

Costs vs. Benefits

Meet-Magento NL, 28. May 2015

+ Developers unfamiliar with Magento more productive

Freedom

Summary

66 Modern Module Architecture

Costs vs. Benefits

Meet-Magento NL, 28. May 2015

+ Real reusability(on component and class level)

Freedom

Summary

67 Modern Module Architecture

Costs vs. Benefits

Meet-Magento NL, 28. May 2015

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

Freedom

Summary

68 Modern Module Architecture

Costs vs. Benefits

Meet-Magento NL, 28. May 2015

+ Easier to reason about domain

Freedom

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

Summary

70 Modern Module Architecture

Costs vs. Benefits

Meet-Magento NL, 28. May 2015

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

dicipline)

Freedom

Thank you!

71 Modern Module Architecture

Please,Ask questionsShare thoughtsNow :)

Meet-Magento NL, 28. May 2015

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