The de constructed. Magento module

Similar documents
James Cowie Software Engineer Session

Software Engineering

Magento Technical Guidelines

GRASP Design Patterns A.A. 2018/2019

Object-Oriented Design

Welcome to Design Patterns! For syllabus, course specifics, assignments, etc., please see Canvas

CSC207H: Software Design SOLID. CSC207 Winter 2018

Object-Oriented Design I

Lessons Learned. Johnny Bigert, Ph.D., Skype/Microsoft October 26, 2011

OUT OF STOCK NOTIFICATION FOR MAGENTO 2

ROBOT OOP. Learning the basics of Object Oriented Programming using robots from popular culture

Build Testable Client and Service Applications

SOLID Principles. Equuleus Technologies. Optional Subheading October 19, 2016

Classes and Objects. Object Orientated Analysis and Design. Benjamin Kenwright

Introduction to Testing and Maintainable code

Chapter 8: Class and Method Design

Lecture: Modular Design

CAS 703 Software Design

Software Development Project. Kazi Masudul Alam

Eliminate enterprise software design instability - protect variations! Nickolay Kofanov

Riccardo Tempesta. MageSpecialist

Index. Index. More information. block statements 66 y 107 Boolean 107 break 55, 68 built-in types 107

Dependency Inversion, Dependency Injection and Inversion of Control. Dependency Inversion Principle by Robert Martin of Agile Fame

Ingegneria del Software Corso di Laurea in Informatica per il Management. Software quality and Object Oriented Principles

Object design. François Schwarzentruber ENS Cachan Antenne de Bretagne

Architecting ios Project. Massimo Oliviero

Object design. François Schwarzentruber ENS Cachan Antenne de Bretagne

1 Software Architecture

Application Architectures, Design Patterns

Test, Code, Design: Inverting the Waterfall

8 Designing classes. Main concepts to be covered. Software changes. Change or die. The Zuul Classes. World of Zuul

Clean Architecture Patterns, Practices, and #DevSum17

Silex and Twig. Jon Ginn

Chapter 10 Object-Oriented Design Principles

Object interconnections

Single Responsibility Principle

The S.O.L.I.D. Principles. of Object Oriented Programming

Paul Boisvert. Director Product Management, Magento

ADVANCED SOFTWARE DESIGN LECTURE 7 GRASP

Principles of Object-Oriented Design

Developer Experience

02291: System Integration

Modellistica Medica. Maria Grazia Pia, INFN Genova. Scuola di Specializzazione in Fisica Sanitaria Genova Anno Accademico

Object-Oriented Design II - GRASP

Influence of Design Patterns Application on Quality of IT Solutions

5. Application Layer. Introduction

Clean Architecture Patterns, Practices, and #sddconf

Object-Oriented Design I - SOLID

Refactoring Tested Code: Has Mocking. RefTest. Managing Refactoring in a Test. Driven World. Gone Wrong? Ben Stopford Royal Bank of Scotland

+ + a journey to zero-downtime

SMS Plugin for Magento Manual

CHAPTER 5 GENERAL OOP CONCEPTS

Advanced Object Oriented PHP

The Principled Developer. Gerardo

Dependency Injection (ESaaS 11.6)! 2013 Armando Fox & David Patterson, all rights reserved

Plan. Design principles: laughing in the face of change. What kind of change? What are we trying to achieve?

Object-Oriented Design

Abstraction. Design fundamentals in OO Systems. Fundamental Software Development Principles

Index. Note: Boldface numbers indicate code and illustrations; an italic t indicates a table.

Lesson 19 Software engineering aspects

INTERNAL ASSESSMENT TEST III Answer Schema

Philosophy of Unit Testing

Chapter 1: Principles of Programming and Software Engineering

Avancier Methods. Very basic design patterns. It is illegal to copy, share or show this document

OO Class Design Principles

Intro to: Design Principles

C++ Modern and Lucid C++ for Professional Programmers

Inheritance (Chapter 7)

Dependency Injection & Design Principles Recap Reid Holmes

Setting the stage... Key Design Issues. Main purpose - Manage software system complexity by improving software quality factors

Object-Oriented Design

(p t y) lt d. 1995/04149/07. Course List 2018

Open Closed Principle (OCP)

09. Component-Level Design

HIDE PRODUCT PRICE. User Guide. User Guide Page 1

Object interconnections גרא וייס המחלקה למדעי המחשב אוניברסיטת בן-גוריון

Patterns. Giovanni Sakti. in Software Engineering. Starqle

Inheritance. EEC 521: Software Engineering. Dealing with Change. Polymorphism. Software Design. Changing requirements Code needs to be flexible

Object Relationships

CSE 70 Final Exam Fall 2009

DreamFactory Security Guide

Magento 2 Code Customizations

Component-Level Design. Slides copyright 1996, 2001, 2005, 2009 by Roger S. Pressman. For non-profit educational use only

Design Process Overview. At Each Level of Abstraction. Design Phases. Design Phases James M. Bieman

Bruno Bossola SOLID Design Principles

Expanding Our Horizons. CSCI 4448/5448: Object-Oriented Analysis & Design Lecture 9 09/25/2011

Microservices Beyond the Hype. SATURN San Diego May 3, 2016 Paulo Merson

SOLID DESIGN PATTERNS FOR MERE MORTALS

Pattern: Model-View-Controller (MVC) Beat Generator Example. Model-View-Controller. Model-View-Controller

Clean Code Why Clean Code matters

Single Responsibility Principle (SRP)

The Design Patterns Matrix From Analysis to Implementation

Object-Oriented Design

Interface (API) Design

Today's Agenda. References. Open Closed Principle. CS 247: Software Engineering Principles. Object-Oriented Design Principles

CS342: Software Design. November 21, 2017

Design and Information Hiding

Nick Terkay CSCI 7818 Web Services 11/16/2006

PRINCIPLES OF SOFTWARE DESIGN

Refactoring Practice: How it is and How it Should be Supported

Transcription:

The de constructed Magento module

James Cowie Technical Team Lead Inviqa t/@jcowie gh/jamescowie 2016 Magento Master mover

deconstruct... verb de con struct \ˌdē-kən-ˈstrəkt\ To take apart or examine in order to reveal the basis or composition of?often with the intention of exposing biases, flaws, or inconsistencies Wayne Karlin

deconstruction in software

The Law of Demeter (LoD) Or principle of least knowledge is a design guideline for developing software, particularly objectoriented programs. In its general form, the LoD is a specific case of loose coupling. 1 1 Robert C. Martin

What is decoupled code?

Tight coupling Tight coupling is when a group of classes are highly dependent on one another. This scenario arises when a class assumes too many responsibilities, or when one concern is spread over many classes rather than having its own class. 10 10 https://en.wikipedia.org/wiki/coupling(computerprogramming)

Loose coupling Loosely coupled code is where each of a systems modules has, or makes use of, little or no knowledge of the definitions of other separate modules 11 11 https://en.wikipedia.org/wiki/loose_coupling

High Cohesion Modules with high cohesion tend to be preferable, because high cohesion is associated with several desirable traits of software including robustness, reliability, reusability, and understandability. 3 3 https://en.wikipedia.org/wiki/cohesion(computerscience)

Low Cohesion In contrast, low cohesion is associated with undesirable traits such as being difficult to maintain, test, reuse, or even understand. 13 13 https://en.wikipedia.org/wiki/cohesion(computerscience)

Don't Repeat Yourself Cut: Command - x, Copy: Command - c, Paste: Command - v

Traits

Composition

Interfaces

Code Time Create an out of stock command that emails store admin using Mandrill because that never changes does it :)

<?php namespace MageTitans\Emailer\Commands; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Command\Command; class EmailCommand extends Command { protected function configure() { $this->setname('magetitans:email'); $this->setdescription('send all email out to people about how much stock is remaining'); parent::configure(); } protected function execute(inputinterface $input, OutputInterface $output) { $emailer = new Mandrill('SOMEAPIKEY'); $message = array( 'subject' => 'Out of stock email', 'from_email' => 'you@yourdomain.com', 'html' => '<p>you are being notified about product stock information!.</p>', 'to' => array(array('email' => 'recipient1@domain.com', 'name' => 'Recipient 1')), 'merge_vars' => array(array( 'rcpt' => 'recipient1@domain.com', 'vars' => array( array( 'name' => 'FIRSTNAME', 'content' => 'Recipient 1 first name'), array( 'name' => 'LASTNAME', 'content' => 'Last name') )))); $template_name = 'Products'; // load all products $objectmanager = \Magento\Framework\App\ObjectManager::getInstance(); $productcollection = $objectmanager->create('magento\catalog\model\resourcemodel\product\collectionfactory'); $collection = $productcollection->create() ->addattributetoselect('*') ->addattributetofilter('stock_status', 0) ->load(); $producthtml = ''; foreach ($collection as $product) { $producthtml.= '<p>'. $product->getname(). '</p>'; } $template_content = array( array( 'name' => 'main', 'content' => 'Hi * FIRSTNAME * * LASTNAME *, thanks for signing up.'), array( 'name' => 'footer', 'content' => 'Copyright 2016.') ); $emailer->messages->sendtemplate($template_name, $template_content, $message); } } $output->writeln("email is sent for out of stock products");

class EmailCommand extends Command { protected function configure() {.. } } protected function execute(inputinterface $input, OutputInterface $output) {... }

... $emailer = new Mandrill('SOMEAPIKEY'); $message = array( 'subject' => 'Out of stock email', 'from_email' => 'you@yourdomain.com', 'html' => '<p>you are being notified about product stock information!.</p>', 'to' => array(array('email' => 'recipient1@domain.com', 'name' => 'Recipient 1')), 'merge_vars' => array(array( 'rcpt' => 'recipient1@domain.com', 'vars' => array( array( 'name' => 'FIRSTNAME', 'content' => 'Recipient 1 first name'), array( 'name' => 'LASTNAME', 'content' => 'Last name') )))); $template_name = 'Products';...

... $objectmanager = \Magento\Framework\App\ObjectManager::getInstance(); $productcollection = $objectmanager->create( 'Magento\Catalog\Model\ResourceModel\Product\CollectionFactory' ); $collection = $productcollection->create() ->addattributetoselect('*') ->addattributetofilter('stock_status', 0) ->load(); $producthtml = ''; foreach ($collection as $product) { $producthtml.= '<p>'. $product->getname(). '</p>'; }...

... $template_content = array( array( 'name' => 'main', 'content' => 'Hi * FIRSTNAME * * LASTNAME *.'), array( 'name' => 'footer', 'content' => 'Copyright 2016.') ); $emailer->messages->sendtemplate( $template_name, $template_content, $message ); $output->writeln("email is sent for out of stock products");

Attempt 1 All logic enclosed in a single method No reuse Hard to understand Hard to change

Issues with the class Fragility Cost of change Technical debt

Fragility No tests Mixed business logic and framework

Cost of change Email may be used throughout the app Hard to understand Becomes "That class"

Technical debt Cost of code over time Impact on speed of change

What is our method actually doing? Building vars for email sending Getting all products that are out of stock Sending the email

EmailCommand.php Becomes Model/Emailer.php Model/OutOfStockProducts.php Commands/EmailCommand.php

Model for Emailer namespace MageTitans\BetterEmailer\Model; class Emailer { public function settemplate(array $templatedata) {... } } public function sendemail($apikey, $templatename, $templatecontent, $message) {... }

Model for OOS products namespace MageTitans\BetterEmailer\Model; class OutOfStockProducts { public function getoutofstockproducts() {... } }

Emailer Command <?php namespace MageTitans\BetterEmailer\Commands;... class EmailCommand extends Command { protected function configure() {... } protected function execute(inputinterface $input, OutputInterface $output) { $products = new \MageTitans\BetterEmailer\Model\OutOfStockProducts(); $emailer = new \MageTitans\BetterEmailer\Model\Emailer(); $emailtemplate = $emailer->settemplate(['name' => 'james', 'lastname' => 'cowie', ]); $emailer->sendemail( 'KEY','products',$emailTemplate, $products->getoutofstockproducts() ); } } $output->writeln("email has been sent");

Getting better Separate class and methods Easier to test Easier to understand Extracted from the framework

Attempt 3 Interfaces Dependency Injection

Interfaces AKA Service Contracts <?php interface Emailer { public function send($templatename, $templatecontent, $message); public function setvariables(array $templatedata); }

Why are interfaces important? Contract for other developers to follow Aid in testing Backwards Compatibility breaks Type safe checking

SOLID 1 S Single-responsiblity principle O Open-closed principle L Liskov substitution principle I Interface segregation principle D Dependency Inversion Principle 1 Robert C. Martin

SOLID O Open-closed principle This simply means that a class should be easily extendable without modifying the class itself

Implement our Interfaces "Model/Emailers/Mandrill.php" <?php namespace MageTitans\ImprovedEmailer\Model\Emailers; use MageTitans\ImprovedEmailer\Api\EmailerInterface; class Mandrill implements EmailerInterface { public function setvariables(array $templatedata) {... } } public function send($templatename, $templatecontent, $message) {... }

Back to our command /** @var \MageTitans\ImprovedEmailer\Api\EmailerInterface */ protected $emailer; /** @var OutOfStockProducts */ protected $outofstockproducts; public function construct( \MageTitans\ImprovedEmailer\Api\EmailerInterface $emailer, OutOfStockProducts $ofstockproducts ) { $this->emailer = $emailer; $this->outofstockproducts = $ofstockproducts; parent:: construct('improvedemail'); }

Injecting an interface? Trust me just go with it :)

Executing our command protected function execute(inputinterface $input, OutputInterface $output) { $templatevars = $this->emailer->setvariables(['name', 'james']); $this->emailer->send( 'Products', $templatevars, $this->outofstockproducts->getoutofstockproducts() ); }

Welcome di.xml <config> <preference for="magetitans\improvedemailer\api\emailerinterface" type="magetitans\improvedemailer\model\emailers\mandrill" /> </config>

SOLID D - Dependency Inversion principle Entities must depend on abstractions not on concretions. It states that the high level module must not depend on the low level module, but they should depend on abstractions.

Mandrill changes its pricing and we want to change implementation quick? Create a new Emailer client Update di.xml

PHPClient <?php namespace MageTitans\ImprovedEmailer\Model\Emailers; use MageTitans\ImprovedEmailer\Api\EmailerInterface; class PHPClient implements EmailerInterface { public function send($templatename, $templatecontent, $message) { return mail($templatecontent['email'], $templatecontent['subject'], $message); } } public function setvariables(array $templatedata) { return [ 'name' => $templatedata['name'], 'email' => $templatedata['email'], 'subject' => $templatedata['subject'] ]; }

Update di.xml </config> <preference for="magetitans\improvedemailer\api\emailerinterface" type="magetitans\improvedemailer\model\emailers\phpclient" /> </config>

Why would we do this? Each class now does a single thing well Each class is easier to test Interfaces enforce a common public Api DI allows dependencies to be mocked and made visible

Where else can we see this? Magento 2 Core Hexagonal Architecture DDD ( Domain Driven Design )

Disclaimer Not all Magento 2 core implements service contracts yet

Customer interface CustomerInterface { public function getid(); public function setid($id); public function getgroupid(); public function setgroupid($groupid);... }

Customer di.xml <config>... <preference for="magento\customer\api\data\customerinterface" type="magento\customer\model\data\customer" />... </config>

So to use Customer protected $customer; public function construct( \Magento\Customer\Api\Data\CustomerInterface $customer ) { $this->customer = $customer; } public function dosomething() { echo $customer->getname(); }

Recap on Interfaces Should never change between major versions They are still WIP in Magento 2 If there is a interface use it!!

Recap on Dependency Injection Inject interfaces where available Use DI over ObjectManager Generate DI in production mode

Source Code https://github.com/jamescowie/magetitansminiexample

Thank you Any questions? t/@jcowie Email/james@mage.school