How to work with legacy code PHPers Rzeszow #2

93
HOW TO WORK WITH LEGACY CODE PHPERS RZESZÓW #2

Transcript of How to work with legacy code PHPers Rzeszow #2

Page 1: How to work with legacy code PHPers Rzeszow #2

HOW TO WORK WITHLEGACY CODE

PHPERS RZESZÓW #2

Page 2: How to work with legacy code PHPers Rzeszow #2

MICHAŁ SZCZURPHP Developer since 2010

bass guitarist and trumpeter

michalszczur.plCreated by / Michał Szczur @partikus

Page 3: How to work with legacy code PHPers Rzeszow #2

AGENDAWhat is legacy codeWhen code can be called Legacy?How to start and not dieStep by step to heaven

Page 4: How to work with legacy code PHPers Rzeszow #2

WHAT IS LEGACY CODE?

Page 5: How to work with legacy code PHPers Rzeszow #2

CODE WRITTEN MANY YEARS AGOBY MYSELF OR OTHER NINJAS

Page 6: How to work with legacy code PHPers Rzeszow #2

LOW QUALITY CODE

Page 7: How to work with legacy code PHPers Rzeszow #2

(PRE)HISTORICAL CODE USES NONEXISTINGFRAMEWORKS/LIBRARIES

Page 8: How to work with legacy code PHPers Rzeszow #2

NO ENVIRONMENT SEPARATION

Page 9: How to work with legacy code PHPers Rzeszow #2

NO TESTS !!!

Page 10: How to work with legacy code PHPers Rzeszow #2

WHEN CODE CAN BE CALLED

LEGACY ???

Page 11: How to work with legacy code PHPers Rzeszow #2

WHEN IT IS

UNMANAGED

Page 12: How to work with legacy code PHPers Rzeszow #2

WHEN IT IS

TOO BUGGY

Page 13: How to work with legacy code PHPers Rzeszow #2

WHEN IT IS

TOO HARD TO UNDERSTAND

Page 14: How to work with legacy code PHPers Rzeszow #2

WHEN IT IS

NONUPGRADABLE

Page 15: How to work with legacy code PHPers Rzeszow #2

WHEN IT IS

UNDEBUGGABLE

Page 16: How to work with legacy code PHPers Rzeszow #2

WHEN IT IS

UNREADABLE

Page 17: How to work with legacy code PHPers Rzeszow #2

WHEN IT IS

TOO COUPLED TO FRAMEWORK

Page 18: How to work with legacy code PHPers Rzeszow #2

WHEN IT IS

TOO HARD TO ADD NEW FEATURE

Page 19: How to work with legacy code PHPers Rzeszow #2

WHAT IS NEXT?

Page 20: How to work with legacy code PHPers Rzeszow #2

FIGHT OR DIE

Page 21: How to work with legacy code PHPers Rzeszow #2

NO !!!WE'RE NINJA DEVS

WE LOVE CHALLENGES

Page 22: How to work with legacy code PHPers Rzeszow #2

LET'S DO IT!

Page 23: How to work with legacy code PHPers Rzeszow #2

TAKE NEW FRAMEWORK AND START FROM THE BEGINNING

Page 24: How to work with legacy code PHPers Rzeszow #2

:(MAYBE SOME DAY IN THE FUTURE

Page 25: How to work with legacy code PHPers Rzeszow #2

WHAT IS NEXT?

Page 26: How to work with legacy code PHPers Rzeszow #2

LET'S REFACTOR

Page 27: How to work with legacy code PHPers Rzeszow #2

BUT WHY ???

Page 28: How to work with legacy code PHPers Rzeszow #2

EXTENDED LEGACYCODE

WEB PHP APP

Page 29: How to work with legacy code PHPers Rzeszow #2

ASSUMPTIONSYOU DON'T KNOW BUSINESS LOGIC

MOSTLY PROCEDURAL CODE

NO SEPARATION, JUST A FEW LARGE FILES

YOU NEED TO CHANGE STH

Page 30: How to work with legacy code PHPers Rzeszow #2

HOW TO START?

Page 31: How to work with legacy code PHPers Rzeszow #2

ANALYZE

Page 32: How to work with legacy code PHPers Rzeszow #2

COVERIT MEANS WRITE TESTS

Page 33: How to work with legacy code PHPers Rzeszow #2

WHAT SHOULD WETEST?

Page 34: How to work with legacy code PHPers Rzeszow #2
Page 35: How to work with legacy code PHPers Rzeszow #2
Page 36: How to work with legacy code PHPers Rzeszow #2

WHY SHOULD WE WRITE TESTS?

Page 37: How to work with legacy code PHPers Rzeszow #2

LOW LEVEL DOCUMENTATIONFEATURES DESCRIBED BY SCENARIOS (E.G.

GHERKIN)CLEAN CODE

EASY TO CHANGE (LESS PAIN)EASY CONTINUOUS DEPLOYMENT

Page 38: How to work with legacy code PHPers Rzeszow #2

START REFACTORING

Page 39: How to work with legacy code PHPers Rzeszow #2

# Project structure /404.php /database.php /functions.php /index.php /page.php

Page 40: How to work with legacy code PHPers Rzeszow #2

PROCEDURAL CODEWRITTEN IN PHP

INLINE PHP FUNCTIONS MIXED WITH HTML,CSS,JS

Page 41: How to work with legacy code PHPers Rzeszow #2

#/functions.php function show_all() { $db = connect_to_db(); $sql = 'SELECT * FROM receivers'; $result = mysql_query($sql) or die(mysql_error()); while ($row = mysql_fetch_array($result)) { //echo 'ID: ' . $row['id'] . ', mail: ' . $row['mail']; echo ''.$row['mail'].''; echo '<form id="'.$row['id'].'" name="n_ID" method="POST" action=<input type="hidden" name="id" value="'.$row['id'].'" /> <input type="submit" name="delete" value="Delete" /> </form>'; } if (isset($_POST['delete'])) { $n_ID = $_POST['id']; $sql = "DELETE FROM receivers WHERE id = $n_ID"; mysql_query($sql) or die(mysql_error());

Page 42: How to work with legacy code PHPers Rzeszow #2

WRITE FUNCTIONALTEST

Page 43: How to work with legacy code PHPers Rzeszow #2

// show_all_receivers.jscasper.test.begin('List all receivers', 5, function suite(test) { casper.start("http://myapp.dev/mailsender.php", function() { test.assertHttpStatus(200); test.assertTitle("Homepage | Mail Sender", "Homepage title is expected" }); casper.thenClick('a#show-all', function() { test.assertHttpStatus(200); test.assertTitle( "Receivers list | Mail Sender", "Page title is correct" ); }); casper.run(function() { test.done(); }); });

Page 44: How to work with legacy code PHPers Rzeszow #2

PROCEDURAL CODE??

YOU NEED STH MORE

Page 45: How to work with legacy code PHPers Rzeszow #2

IOCINVERSION OF CONTROL

Page 46: How to work with legacy code PHPers Rzeszow #2

DEPENDENCYINJECTION

IOC IMPLEMENTATION

Page 47: How to work with legacy code PHPers Rzeszow #2

DON'T REINVENT THEWHEEL

Page 48: How to work with legacy code PHPers Rzeszow #2

PACKAGE MANAGERCOMPOSER

RUBYGEMS

MAVEN

Page 50: How to work with legacy code PHPers Rzeszow #2

WHY SYMFONYCOMPONENTS?

Page 51: How to work with legacy code PHPers Rzeszow #2

WELL TESTED

Page 52: How to work with legacy code PHPers Rzeszow #2

DECOUPLED

Page 53: How to work with legacy code PHPers Rzeszow #2

REUSABLE

Page 54: How to work with legacy code PHPers Rzeszow #2

WELL DOCUMENTEDAND KNOWN BY COMMUNITY

Page 55: How to work with legacy code PHPers Rzeszow #2

NEXT STEP IS...

Page 56: How to work with legacy code PHPers Rzeszow #2

MOVE APP TO /WEB/# new project structure / /web/404.php /web/database.php /web/functions.php /web/index.php /web/page.php

Page 57: How to work with legacy code PHPers Rzeszow #2

INSTALL COMPOSERphp -r "readfile('https://getcomposer.org/installer');" > composer-setup.phpphp -r "if (hash('SHA384', file_get_contents('composer-setup.php')) === php composer-setup.php php -r "unlink('composer-setup.php');"

Page 58: How to work with legacy code PHPers Rzeszow #2

INIT COMPOSER CONFIG IN THE ROOT DIRphp composer.phar init

Page 59: How to work with legacy code PHPers Rzeszow #2

PROJECT STRUCTUREls -l / /composer.json /web/

Page 60: How to work with legacy code PHPers Rzeszow #2

COMPOSER.JSON

{ "name": "michalszczur/legacy-demo", "authors": [ { "name": "Michal Szczur", "email": "[email protected]" } ], "require": {}, "autoload": { "psr-4": { "": "src/" } }, "description": "Legacy app demo", "type": "project", "license": "proprietary"

Page 61: How to work with legacy code PHPers Rzeszow #2

ADD DEPENDENCIESphp composer.phar require symfony/dependency-injection php composer.phar require symfony/config php composer.phar require symfony/yaml

Page 62: How to work with legacy code PHPers Rzeszow #2

<?php # /web/container.php use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;

require __DIR__.'/../vendor/autoload.php';

$container = new ContainerBuilder(); $loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/../app/config'$loader->load('services.yml');

$container->compile();

Page 63: How to work with legacy code PHPers Rzeszow #2

WHICH SERVICES DO WE REALLYNEED?

Page 64: How to work with legacy code PHPers Rzeszow #2

function show_all() { # Database connection needed $db = connect_to_db(); $sql = 'SELECT * FROM receivers'; $result = mysql_query($sql) or die(mysql_error()); //...

Page 65: How to work with legacy code PHPers Rzeszow #2

CREATE SEVICES.YML DEFINITION

Page 66: How to work with legacy code PHPers Rzeszow #2

SERVICES.YMLparameters: db_host: localhost db_port: 3306 db_name: legacyapp db_user: myuser db_pass: mypass

services: db: class: \PDO arguments: ['mysql:port=%db_port%;host=%db_host%;dbname=%db_name%' receiver_repository: class: PDOReceiverRepository arguments: ['@db']

Page 67: How to work with legacy code PHPers Rzeszow #2

USE CONTAINER AND REPOSITORY

Page 68: How to work with legacy code PHPers Rzeszow #2

#index.php ... require 'container.php'; ... function show_all() { # Database connection needed $receiverRepository = $container->get('receiver_repository'); $result = $receiverRepository->findAll(); ...

Page 69: How to work with legacy code PHPers Rzeszow #2

#index.php ... $result = $receiverRepository->findAll(); foreach ($result as $row) { echo ''.$row['mail'].''; echo '<form id="'.$row['id'].'" name="n_ID" method="POST" action="mail_sender.php?page=show_all"><input type="hidden" name="id" value="'.$row['id'].'" /> <input type="submit" name="delete" value="Usuń" /> </form>'; } ...

Page 70: How to work with legacy code PHPers Rzeszow #2

PHP ~ HTMLSTILL MIXED TOGETHER

Page 71: How to work with legacy code PHPers Rzeszow #2

TWIGTEMPLATE ENGINE FOR PHP

Page 72: How to work with legacy code PHPers Rzeszow #2

INSTALL TWIG USING COMPOSERphp composer.phar require twig/twig

Page 73: How to work with legacy code PHPers Rzeszow #2

SERVICES.YMLparameters: ... twig_paths: - app/Resources/views services: ... twig.loader: class: Twig_Loader_Filesystem arguments: ['%twig_paths%'] twig: class: Twig_Environment arguments: ['@twig.loader']

Page 74: How to work with legacy code PHPers Rzeszow #2

#index.php ... $twig = $container->get('@twig'); $result = $receiverRepository->findAll(); echo $twig->render( 'receiver_list.html.twig', ['receivers' => $result] ); ...

Page 75: How to work with legacy code PHPers Rzeszow #2

{% for receiver in receivers %} <form id="{{ receiver.id }}" name="n_ID" method="POST" action="mail_sender.php?page=show_all"<input type="hidden" name="id" value="{{ receiver.id }}" /> <input type="submit" name="delete" value="Delete" /> </form> {% endfor %}

Page 76: How to work with legacy code PHPers Rzeszow #2

BEFOREfunction show_all() { $db = connect_to_db(); $sql = 'SELECT * FROM mail_sender'; $result = mysql_query($sql) or die(mysql_error()); while ($row = mysql_fetch_array($result)) { //echo 'ID: ' . $row['id'] . ', mail: ' . $row['mail']; echo ''.$row['mail'].''; echo '<form id="'.$row['id'].'" name="n_ID" method="POST" action="mail_sender.php?page=show_all"><input type="hidden" name="id" value="'.$row['id'].'" /> <input type="submit" name="delete" value="Usuń" /> </form>'; } ... mysql_free_result($result); mysql_close($db); }

Page 77: How to work with legacy code PHPers Rzeszow #2

AFTERfunction show_all() { $receiverRepository = $container->get('receiver_repository'); $twig = $container->get('@twig'); $result = $receiverRepository->findAll(); echo $twig->render( 'receiver_list.html.twig', ['receivers' => $result] ... );

Page 78: How to work with legacy code PHPers Rzeszow #2

LET'S SUM UP

Page 79: How to work with legacy code PHPers Rzeszow #2

COMMUNICATION

Page 80: How to work with legacy code PHPers Rzeszow #2

ANALYZE

Page 81: How to work with legacy code PHPers Rzeszow #2

TESTS

Page 82: How to work with legacy code PHPers Rzeszow #2

SMALL STEPS

Page 83: How to work with legacy code PHPers Rzeszow #2

NOT EVERYTHING SIMUNTANOUSLY

Page 84: How to work with legacy code PHPers Rzeszow #2

PACKAGE MANAGER

Page 85: How to work with legacy code PHPers Rzeszow #2

DEPENDENCY INJECTION

Page 86: How to work with legacy code PHPers Rzeszow #2

THIRD PARTY LIBRARIES

Page 87: How to work with legacy code PHPers Rzeszow #2

DESIGN PATTERNS

Page 88: How to work with legacy code PHPers Rzeszow #2

SOLID

Page 89: How to work with legacy code PHPers Rzeszow #2

DECOUPLE

Page 90: How to work with legacy code PHPers Rzeszow #2

TESTS

Page 91: How to work with legacy code PHPers Rzeszow #2

THANKS!

Page 92: How to work with legacy code PHPers Rzeszow #2

QUESTIONS?SLIDES: SLIDESHARE.NET/MICHASZCZUR

TWITTER: @PARTIKUS

HOMEPAGE: MICHALSZCZUR.PL

Page 93: How to work with legacy code PHPers Rzeszow #2

LINKSCasperJSSymfony ComponentsWorking Effectively with Legacy Code by Michael FeathersPage Object Pattern (Martin Fowler)Page Object Pattern (Selenium Docs)Marek Matulka - Modernising the Legacy