SlideShare a Scribd company logo
РЕФАКТОРИНГ
И ВТОРОЕ РОЖДЕНИЕ ПРОЕКТА
    на примере Zend Framework 2.0




                   Докладчик: Алексей Пархоменко
                              alexey@iprojects.com.ua
Теория
Теория



Что такое рефакторинг?



           — изменение исходного кода
           программы без изменения его
           внешнего поведения.
Теория



          Проблемы рефакторинга

●   потребность вносить изменения в существующий код;
●   необходимость строго придерживаться поставленной
    задачи;
●   покрывать код проверочными тестами;
теория




Нужен ли Вам рефакторинг?
теория



   Нужен ли Вам рефакторинг?
Ваш программный продукт работает, но внесение новой
функциональности иногда затягивается на недели;
теория



   Нужен ли Вам рефакторинг?
Ваш программный продукт работает, но внесение новой
функциональности иногда затягивается на недели;

В определенных местах Ваш код работает совершенно
не так, как Вы того ожидали;
теория



   Нужен ли Вам рефакторинг?
Ваш программный продукт работает, но внесение новой
функциональности иногда затягивается на недели;

В определенных местах Ваш код работает совершенно
не так, как Вы того ожидали;

Вы часто ошибаетесь в сроках реализации поставленной
задачи;
теория



   Нужен ли Вам рефакторинг?
Ваш программный продукт работает, но внесение новой
функциональности иногда затягивается на недели;

В определенных местах Ваш код работает совершенно
не так, как Вы того ожидали;

Вы часто ошибаетесь в сроках реализации поставленной
задачи;

Вам приходится вносить однотипные изменения в разных
местах проекта;
теория




“... в реальном мире все иначе ...”
теория




“... в реальном мире все иначе ...”
теория




Рефакторинг всегда
подразумевает,
что вы производите его с какой-то целью и
опираетесь на какие-то данные строго преследуя
поставленные задачи.
теория




Например
теория




Например:
●   Улучшение читаемости кода;
теория




Например:
● Улучшение читаемости кода;
● Уменьшение зависимостей между


      определенными частями системы;
теория




Например:
● Улучшение читаемости кода;
● Уменьшение зависимостей между


      определенными частями системы;
● Оптимизация каких-либо компонентов системы


      вследствие замены архитектурных решений;
теория




Например:
● Улучшение читаемости кода;
● Уменьшение зависимостей между


      определенными частями системы;
● Оптимизация каких-либо компонентов системы


      вследствие замены архитектурных решений;
● и так далее;
теория



На каждом этапе вы должны
четко знать несколько вещей:

    ●   Зачем это нужно делать?
    ●   Какую проблему вы решаете?
    ●   Что на выходе вы должны получить?
теория



Какие есть методы рефакторинга?
●   Инкапсуляция поля (Encapsulate Field);
●   Выделение класса (Extract Class);
●   Выделение интерфейса (Extract Interface);
●   Выделение локальной переменной (Extract Local Variable);
●   Выделение метода (Extract Method);
●   Генерализация типа (Generalize Type);
●   Встраивание (Inline);
●   Введение фабрики (Introduce Factory);
●   Введение параметра (Introduce Parameter);
●   Подъём поля/метода (Pull Up);
●   Спуск поля/метода (Push Down);
●   Замена условного оператора полиморфизмом
                          (Replace Conditional with Polymorphism);
●   и так далее;
теория



Вспомним о тестах и их
   преимуществах:
теория



Вспомним о тестах и их
   преимуществах:
      Тесты предотвращают появление ошибок
      в новом коде
теория



Вспомним о тестах и их
   преимуществах:
      Тесты предотвращают появление ошибок
      в новом коде
      Тесты позволяют рефакторить код без
      риска его сломать
теория



Вспомним о тестах и их
   преимуществах:
      Тесты предотвращают появление ошибок
      в новом коде
      Тесты позволяют рефакторить код без
      риска его сломать
      Тесты могут использоваться в качестве
      документации
теория



Вспомним о тестах и их
   преимуществах:
      Тесты предотвращают появление ошибок
      в новом коде
      Тесты позволяют рефакторить код без
      риска его сломать
      Тесты могут использоваться в качестве
      документации
      Тесты улучшают дизайн кода
теория



Вспомним о тестах и их
   преимуществах:
      Тесты предотвращают появление ошибок
      в новом коде
      Тесты позволяют рефакторить код без
      риска его сломать
      Тесты могут использоваться в качестве
      документации
      Тесты улучшают дизайн кода
       Тесты способствуют повышению
       квалификации разработчиков
теория



Вспомним о тестах и их
   преимуществах:
      Тесты предотвращают появление ошибок
      в новом коде
      Тесты позволяют рефакторить код без
      риска его сломать
      Тесты могут использоваться в качестве
      документации
      Тесты улучшают дизайн кода
       Тесты способствуют повышению
       квалификации разработчиков

       Тесты ускоряют процесс разработки
теория



Вспомним о тестах и их
   преимуществах:
      Тесты предотвращают появление ошибок
      в новом коде
      Тесты позволяют рефакторить код без
      риска его сломать
      Тесты могут использоваться в качестве
      документации
      Тесты улучшают дизайн кода
       Тесты способствуют повышению
       квалификации разработчиков

       Тесты ускоряют процесс разработки
теория



              Мифы о тестах:
В нашем приложении внедрить тесты невозможно, у нас
слишком быстро все меняется;
теория



              Мифы о тестах:
В нашем приложении внедрить тесты невозможно, у нас
слишком быстро все меняется;

В нашем приложении такая архитектура, что нам
требуется много mock объектов;
теория



              Мифы о тестах:
В нашем приложении внедрить тесты невозможно, у нас
слишком быстро все меняется;

В нашем приложении такая архитектура, что нам
требуется много mock объектов;

Написание тестов отнимает слишком много времени;
теория



              Мифы о тестах:
В нашем приложении внедрить тесты невозможно, у нас
слишком быстро все меняется;

В нашем приложении такая архитектура, что нам
требуется много mock объектов;

Написание тестов отнимает слишком много времени;

Мы не делаем код для “академиков”, нам нужны
решения проще;
теория



              Мифы о тестах:
В нашем приложении внедрить тесты невозможно, у нас
слишком быстро все меняется;

В нашем приложении такая архитектура, что нам
требуется много mock объектов;

Написание тестов отнимает слишком много времени;

Мы не делаем код для “академиков”, нам нужны
решения проще;

Рефакторинг, как методика весьма дорогая для нашей
компании. Лучше тратить время программистов на создание
новой функциональности;
теория



  Рефакторинг не существует без:


                                    Сопутствующих
Тестов                               Инструментов



иначе это не рефакторинг и ваши действия никак не направлены
              на улучшение существующего кода.
История
история




                   Под прицелом:


Zend Framework                Zend Framework
1.11.11                  VS        2.0.0beta3
2011-09-29 релиз                    релиз 2012-03-02
история



 Для ZF2 были поставлены цели:

     “Zend Framework 2.0's focus
      in on improving consistency
            and perfomance”

(фреймворк сфокусирован на улучшении
согласованности и производительности)
история



          Основные проблемы ZF1:
●   Неудовлетворительная производительность;
история



          Основные проблемы ZF1:
●   Неудовлетворительная производительность;
●   Дублирование некоторой функциональности
       используемых загрузчиков плагинов (plugin loader);
история



          Основные проблемы ZF1:
●   Неудовлетворительная производительность;
●   Дублирование некоторой функциональности
       используемых загрузчиков плагинов (plugin loader);
●   Слишком много ответственности выдано View;
история



          Основные проблемы ZF1:
●   Неудовлетворительная производительность;
●   Дублирование некоторой функциональности
       используемых загрузчиков плагинов (plugin loader);
●   Слишком много ответственности выдано View;
●   Один тип исключения (Exception) на компоненту;
история



          Основные проблемы ZF1:
●   Неудовлетворительная производительность;
●   Дублирование некоторой функциональности
       используемых загрузчиков плагинов (plugin loader);
●   Слишком много ответственности выдано View;
●   Один тип исключения (Exception) на компоненту;
●   Слишком много путей для реализации одних и тех же задач;
история



          Основные проблемы ZF1:
●   Неудовлетворительная производительность;
●   Дублирование некоторой функциональности
       используемых загрузчиков плагинов (plugin loader);
●   Слишком много ответственности выдано View;
●   Один тип исключения (Exception) на компоненту;
●   Слишком много путей для реализации одних и тех же задач;
●   Очень тяжелая начальная загрузка (bootstrap) приложения;
●   Отдельные компоненты сложно оптимизировать из-за
       длинных цепочек вызова;
история



          Основные проблемы ZF1:
●   Неудовлетворительная производительность;
●   Дублирование некоторой функциональности
       используемых загрузчиков плагинов (plugin loader);
●   Слишком много ответственности выдано View;
●   Один тип исключения (Exception) на компоненту;
●   Слишком много путей для реализации одних и тех же задач;
●   Очень тяжелая начальная загрузка (bootstrap) приложения;
●   Отдельные компоненты сложно оптимизировать из-за
       длинных цепочек вызова;
●   Ресурсоемкие тесты и необходимость служебных классов
       «живущих» вместе с ними;
история



      Знаковые нововведения в ZF2:
●   ZendDi — использует популярный паттерн в мире Java
         Dependency Injection (внедрение зависимостей);
история



      Знаковые нововведения в ZF2:
●   ZendDi — использует популярный паттерн в мире Java
         Dependency Injection (внедрение зависимостей);
●   ZendEventManager — построен на замыканиях
         (лямбда-функиях);
история



      Знаковые нововведения в ZF2:
●   ZendDi — использует популярный паттерн в мире Java
         Dependency Injection (внедрение зависимостей);
●   ZendEventManager — построен на замыканиях
         (лямбда-функиях);
●   Иной взгляд на MVC;
история



      Знаковые нововведения в ZF2:
●   ZendDi — использует популярный паттерн в мире Java
         Dependency Injection (внедрение зависимостей);
●   ZendEventManager — построен на замыканиях
         (лямбда-функиях);
●   Иной взгляд на MVC;
●   Центральное хранилище модулей
         (http://modules.zendframework.com/) для повторного
         использования кода, по примеру bundles для symfony;
Но следует понимать, что
           PHP !== JAVA

JAVA имеет сильные стороны и большой
опыт реализации успешных интерфейсов.

Как это применимо для PHP?
Практика
практика




ZendEventManager
 Менеджер событий
практика


use ZendEventManagerStaticEventManager,
  ZendLogFactory as LogFactory;

$log       = LogFactory($someConfig);
$events    = StaticEventManager::getInstance();
$events->attach('Foo', 'bar', function ($e) use ($log) {
   $event = $e->getName();
   $target = get_class($e->getTarget());
   $params = json_encode($e->getParams());

      $log->info(sprintf(
          '%s called on %s, using params %s',
          $event,
          $target,
          $params
      ));
});
практика




// Later, instantiate Foo:
$foo = new Foo();

// And we can still trigger the above event:
$foo->bar('baz', 'bat');

// results in log message:
// bar called on Foo, using params
// {"baz" : "baz", "bat" : "bat"}"
практика




         ZendDi
Паттерн Dependency Injection
  Внедрение зависимости
практика



                 Цель

— выделить доступ к определенному
сервису / объекту в отдельный слой, дабы
стать менее зависимым от реализации самого
сервиса / объекта.
практика



    class SomeClass
    {
    }

    $di        = new ZendDiDi();
    $someClass = $di->get('SomeClass');


●   Делегируем создание объекта контейнеру;
практика


    class SomeClass
    {
        protected $_injectionClass;

           public function __construct(InjectionClass $injectionClass) {
                $this->_injectionClass = $injectionClass;
           }
    }

    $di     = new ZendDiDi();
    $someClass = $di->get('SomeClass');


●       В результате, в переменной $someClass будет новый инстанс
        объекта с инициализированным свойством injectionClass.
практика




    Откуда Di контейнер узнает
как необходимо инициализировать
       тот или иной объект?
практика


ZfcUser/config/module.config.php
 'di' => array(
     'instance' => array(
        'alias' => array(
            'zfcuser'               => 'ZfcUserControllerUserController',
            'zfcuser_user_service'        => 'ZfcUserServiceUser',
            'zfcuser_auth_service'        => 'ZendAuthenticationAuthenticationService',
            'zfcuser_uemail_validator'     => 'ZfcUserValidatorNoRecordExists',
            'zfcuser_uusername_validator'     => 'ZfcUserValidatorNoRecordExists',
            'zfcuser_captcha_element'       => 'ZendFormElementCaptcha',

               // Default ZendDb
               'zfcuser_zend_db_adapter' => 'ZendDbAdapterAdapter',
               'zfcuser_user_mapper' => 'ZfcUserModelUserMapper',
               'zfcuser_usermeta_mapper' => 'ZfcUserModelUserMetaMapper',
               'zfcuser_user_tg'    => 'ZendDbTableGatewayTableGateway',
               'zfcuser_usermeta_tg' => 'ZendDbTableGatewayTableGateway',
          ),

          /* …. */    ●   модуль обеспечивает очень простую и настраиваемую
      )
 );                       систему аутентификации и регистрации пользователя
практика




Конфигурационный файл только
  объектов маленького модуля
      занимает 159 строк.

Любая неточность == частично
 инициализированный объект
практика




Для реализации Di паттерна
ZF2 использует рефлексию
         (reflection)
практика



Проблемы:

●   Сложность отладки программы;
практика



Проблемы:

●   Сложность отладки программы;
●   Потеря производительности;
практика



Проблемы:

●   Сложность отладки программы;
●   Потеря производительности;
●   Приложение трудно читать из-за
    неочевидности какой объект отдает
    Di контейнер в данный момент;
практика



Di контейнер внутри ZF2

●   Используется в основе нового
    взгляда на парадигму MVC;
●   “Тяжелый Bootstrap” ZF1 переместился
    в Zend/Mvc/Bootstrap.php
практика

Zend/Mvc/Bootstrap.php
   $di = new Di;
   $di->instanceManager()->addTypePreference('ZendDiLocator', $di);

   // Default configuration for common MVC classes
   $diConfig = new DiConfiguration(array('definition' => array('class' => array(
      'ZendMvcRouterRouteStack' => array(
         'instantiator' => array(
            'ZendMvcRouterHttpTreeRouteStack',
            'factory'
         ),
      ),
      'ZendMvcRouterHttpTreeRouteStack' => array(
         'instantiator' => array(
            'ZendMvcRouterHttpTreeRouteStack',
            'factory'
         ),
      ),
      'ZendMvcViewDefaultRenderingStrategy' => array(
         'setLayoutTemplate' => array(
            'layoutTemplate' => array(
               'required' => false,
               'type' => false,
            ),
         ),
      )
практика



    Ваше приложение зависимо от Di
●   С ростом проекта вызовы Di расползаются
    по всему приложению и в какой-то степени
    он становиться схож с Singleton'ом;

●   Вы получаете узкое место и потенциально
    жесткую архитектуру, хоть и с возможностью
    подмены одного объекта другим.
практика




Cобрав все за и против –
       произведем
нагрузочное тестирование
Тестирование
тестирование


Команда ZF2 ставила для себя задачи
   улучшения согласованности и
  повышения производительности.
      А также заявляла о некоторых решениях:

●   Переход на Namespace (пространство имен);
●   Рефакторинг исключений;
●   Переход ZF исключительно на автозагрузку
    без использования require_once;
●   Совершенствование и стандартизация
    системы плагинов;
тестирование


    Замеры производительности
производились на железе следующей
          конфигурации:

Процессор:

CPU cores:    2
CPU family:   6
CPU MHz:      2999.748
Model Name:   Intel Core 2 Duo CPU E8400
Cache size:   6144 KB
тестирование



Оперативная память:         Операционная система:
RAM:       2011 MB          Debian:     6.0.5
                            Linux core: 2.6.32-5-amd64



ZF2 Приложение:               ZendSkeletonApplication
    (https://github.com/zendframework/ZendSkeletonApplication)

ZF1 Приложение:           Default Welcome Application
тестирование


Окружение:

Nginx:                 1.2.0
Php:                   5.4.0

  Php modules: Core, ctype, curl, date, dom, ereg, exif, fileinfo,
               filter, ftp, gd, hash, iconv, json, libxml, mbstring,
               mcrypt, mysql, mysqli, mysqlnd, pcre, PDO,
               pdo_mysql, pdo_sqlite, Phar, posix, Reflection,
               session, SimpleXML, soap, sockets, SPL, sqlite3,
               standard, tokenizer, xml, xmlreader, xmlwriter,
               zip, zlib
тестирование



  Тестирование через Apache jMeter
Задача

Протестировать отказоустойчивость фреймворка
при нагрузке 3000 пользователей в минуту на протяжении
10-ти минут в локальной сети.

Решение

2 ноутбука через wifi каждые 400 миллисекунд осуществляют
10 одновременных подключений к серверу;
тестирование




Тесты ZF1
тестирование
тестирование
тестирование
тестирование



Результаты ZF1:

В среднем ZF1 выдавал страницу за            26ms;
Может обслуживать клиентов в минуту     ~1200-1400;
Минимально клиент ждал                       19ms;
Максимально клиент ждал                     250ms;

Пиковая нагрузка на сервер составила:

RAM                                        ~10 MB;
CPU                                     ~38%-50%;
Load Average                                 0.39;
тестирование




Тесты ZF2
тестирование
тестирование
тестирование
тестирование



Результаты ZF2:

В среднем ZF2 выдавал страницу за           102ms;
Может обслуживать клиентов в минуту     ~1000-1200;
Минимально клиент ждал                       47ms;
Максимально клиент ждал                     341ms;

Пиковая нагрузка на сервер составила:

RAM                                         ~20MB;
CPU                                     ~92%-100%;
Load Average                                  3.98;
тестирование


                   Под прицелом:


Zend Framework                Zend Framework
1.11.11                  VS        2.0.0beta3
2011-09-29 релиз                       релиз 2012-03-02



            Из приведенных графиков видно,
           что ZF2 не только медленнее ZF1,
      но и весьма прожорлив по ресурсам сервера.
Профилирование
профилирование




Профайлер Xdebug
практика



Архитектура
ZF2 изнутри
профилирование



Основная проблема
производительности
      ZendDi
профилирование



Основная проблема
производительности
      ZendDi
●   слишком много обращений за один сеанс скрипта;
профилирование



Компромиссы, оптимизация?
В связи с текущей архитектурой, единственный выход,
который мне видится — выпустить Di контейнер в виде Си
расширения для PHP;
профилирование



Компромиссы, оптимизация?
В связи с текущей архитектурой единственный выход,
который мне видится — выпустить Di контейнер в виде Си
расширения для PHP;

Я реализовал пробный вариант решения, в котором учтены
еще далеко не все возможные инъекции, задуманные
разработчиками, и благодаря которому быстродействие
фреймворка уже увеличилось на 20%;
Выводы
выводы


●   ZF2 существенно медленнее ZF1;
выводы


●   ZF2 существенно медленнее ZF1;
●   Dependency injection в PHP сложно
    организуемый паттерн.
выводы


●   ZF2 существенно медленнее ZF1;
●   Dependency injection в PHP сложно
    организуемый паттерн.
●   PHP !== Java — эти границы следует очень
    четко понимать;
выводы


●   ZF2 существенно медленнее ZF1;
●   Dependency injection в PHP сложно
    организуемый паттерн.
●   PHP !== Java — эти границы следует очень
    четко понимать;
●   Тестирование решает многие проблемы
     выбора инструмента или методик;
выводы


●   ZF2 существенно медленнее ZF1;
●   Dependency injection в PHP сложно
    организуемый паттерн.
●   PHP !== Java — эти границы следует очень
    четко понимать;
●   Тестирование решает многие проблемы
     выбора инструмента или методик;
●   Любое заявление среди разработчиков,
    и мое в частности, должно быть перепроверено
    вами лично и сделаны собственные выводы;
Спасибо ;)

    Докладчик: Алексей Пархоменко
               alexey@iprojects.com.ua

More Related Content

PDF
Benefits of unit-testing and inversion of controll
PDF
Виталий Шибаев - Креативный менеджмент глазами разработчика: как выжить в agi...
PDF
Разработка через тестирование (TDD и BDD)
ODT
TAP
PDF
QAFest. Роль тестирования в Devops
PPTX
Андрей Кирпичев "Гибкая модульность инструментами АОП"
PPT
(Seleniumcamp) Selenium IDE как артефакт пикника на обочине
Benefits of unit-testing and inversion of controll
Виталий Шибаев - Креативный менеджмент глазами разработчика: как выжить в agi...
Разработка через тестирование (TDD и BDD)
TAP
QAFest. Роль тестирования в Devops
Андрей Кирпичев "Гибкая модульность инструментами АОП"
(Seleniumcamp) Selenium IDE как артефакт пикника на обочине

What's hot (20)

PPT
Как спроектировать хороший API и почему это так важно
PPT
Как сделать наши проекты немного более управляемыми с Agile
PDF
Как мы тестируем анализатор кода
PPTX
QA Fest 2016. Алексей Виноградов. Цель тестирования. А на самом деле?
PDF
Урок 7. Проблемы выявления 64-битных ошибок
PDF
DevOps guide for awesome quality assurance
PPTX
XP Days Ukraine 2014 - Refactoring legacy code
PPTX
QA Fest 2014. Алексей Лупан. Не тест-кейсы красят тестировщика, а...
PPT
Unit Testing
PPTX
Ошибки начинающих Tdd практиков, плюсы применения
PDF
CodeFest 2014. Павлов И. — Как делать прототипы в автоматизации тестирования
PDF
Специфика тестирования проектов с открытым исходным кодом
PDF
Автоматизация тестирования как сервис
PPTX
Лучшие практики на практике
PDF
Регулярное использование статического анализа кода в командной разработке
PPTX
TDD (Test-driven Development) как стиль разработки.
PDF
7 принципов эффективного тестирования
PPT
JavaTalks.Unit Testing.Part 1
PDF
РИФ 2016, Внедрение контроля качества в большом web-проекте на примере Badoo
PPT
Как принести пользу разработке и упростить себе жизнь?
Как спроектировать хороший API и почему это так важно
Как сделать наши проекты немного более управляемыми с Agile
Как мы тестируем анализатор кода
QA Fest 2016. Алексей Виноградов. Цель тестирования. А на самом деле?
Урок 7. Проблемы выявления 64-битных ошибок
DevOps guide for awesome quality assurance
XP Days Ukraine 2014 - Refactoring legacy code
QA Fest 2014. Алексей Лупан. Не тест-кейсы красят тестировщика, а...
Unit Testing
Ошибки начинающих Tdd практиков, плюсы применения
CodeFest 2014. Павлов И. — Как делать прототипы в автоматизации тестирования
Специфика тестирования проектов с открытым исходным кодом
Автоматизация тестирования как сервис
Лучшие практики на практике
Регулярное использование статического анализа кода в командной разработке
TDD (Test-driven Development) как стиль разработки.
7 принципов эффективного тестирования
JavaTalks.Unit Testing.Part 1
РИФ 2016, Внедрение контроля качества в большом web-проекте на примере Badoo
Как принести пользу разработке и упростить себе жизнь?
Ad

Viewers also liked (20)

PPT
3. эмоции в структуре личности и поведении (тема 3)+
PPTX
настоящий нейронет сталь
PDF
Негативные эмоции и их последствия
PDF
Журнал "Про e-learning" #4
PDF
Российский e-Wow сервис. Удобство! Сроки! Эмоции!
PPTX
психологический портрет личности
PPT
эмоции человека
PDF
Чтобы видеть эмоции
PPTX
эмоции человека
PDF
Управление людьми. Как эмоции влияют на характер? Вадим Нарейко
PPTX
окомистин др
PPT
Технологии продления молодости
PPT
Motcsii
PPTX
усикова полина
PPT
Базовые потребности и эмоции человека
PPT
чувства и эмоции в жизни человека
PDF
Проектирование услуг
PPT
эмоции радость
DOCX
теория.гвоздев.анализ эмоции страха среди учащихся. маоусош №45.
PPTX
Эмоции животных
3. эмоции в структуре личности и поведении (тема 3)+
настоящий нейронет сталь
Негативные эмоции и их последствия
Журнал "Про e-learning" #4
Российский e-Wow сервис. Удобство! Сроки! Эмоции!
психологический портрет личности
эмоции человека
Чтобы видеть эмоции
эмоции человека
Управление людьми. Как эмоции влияют на характер? Вадим Нарейко
окомистин др
Технологии продления молодости
Motcsii
усикова полина
Базовые потребности и эмоции человека
чувства и эмоции в жизни человека
Проектирование услуг
эмоции радость
теория.гвоздев.анализ эмоции страха среди учащихся. маоусош №45.
Эмоции животных
Ad

Similar to Рефакторинг и второе рождение проекта на примере Zend Framework 2.0 (20)

PDF
Работа с унаследованным кодом. Есть ли жизнь после коммита.
PPTX
Промышленная разработка ПО. Лекция 3. Особенности работы программиста. Часть...
PPTX
Тестирование для программистов
PPTX
«тестирование для программистов. или «есть ли жизнь без тестировщиков» ( рома...
PDF
Рефакторинг
ODP
Refactoring
PPTX
А.Калугин. Как казаки-тестировщики в менеджеры собирались
PPTX
Автотесты и образ мышления
PDF
Когда код «убивает», или зачем нам тестировать наши продукты
PPTX
AgileCamp’11 Новосибирск - Test Driven Development (TDD)
PDF
Максим Гуртовенко - The future is wild | HappyDev'12
PPTX
лекция типовые ошибки
PPTX
разработка бизнес приложений (8)
PPT
Testing
PPTX
Качественный менеджер
PPTX
AgileCamp'11.Code review & Pair programming
PPTX
Req Labs'2011. Коммуникация нефункциональных требований
PPTX
Переписать нельзя рефакторить
PDF
Борьба с багами: RailsClub на DevConf 2015
PPTX
Организация эффективной работы команды при разработке и поддержке сложной инф...
Работа с унаследованным кодом. Есть ли жизнь после коммита.
Промышленная разработка ПО. Лекция 3. Особенности работы программиста. Часть...
Тестирование для программистов
«тестирование для программистов. или «есть ли жизнь без тестировщиков» ( рома...
Рефакторинг
Refactoring
А.Калугин. Как казаки-тестировщики в менеджеры собирались
Автотесты и образ мышления
Когда код «убивает», или зачем нам тестировать наши продукты
AgileCamp’11 Новосибирск - Test Driven Development (TDD)
Максим Гуртовенко - The future is wild | HappyDev'12
лекция типовые ошибки
разработка бизнес приложений (8)
Testing
Качественный менеджер
AgileCamp'11.Code review & Pair programming
Req Labs'2011. Коммуникация нефункциональных требований
Переписать нельзя рефакторить
Борьба с багами: RailsClub на DevConf 2015
Организация эффективной работы команды при разработке и поддержке сложной инф...

Рефакторинг и второе рождение проекта на примере Zend Framework 2.0

  • 1. РЕФАКТОРИНГ И ВТОРОЕ РОЖДЕНИЕ ПРОЕКТА на примере Zend Framework 2.0 Докладчик: Алексей Пархоменко alexey@iprojects.com.ua
  • 3. Теория Что такое рефакторинг? — изменение исходного кода программы без изменения его внешнего поведения.
  • 4. Теория Проблемы рефакторинга ● потребность вносить изменения в существующий код; ● необходимость строго придерживаться поставленной задачи; ● покрывать код проверочными тестами;
  • 5. теория Нужен ли Вам рефакторинг?
  • 6. теория Нужен ли Вам рефакторинг? Ваш программный продукт работает, но внесение новой функциональности иногда затягивается на недели;
  • 7. теория Нужен ли Вам рефакторинг? Ваш программный продукт работает, но внесение новой функциональности иногда затягивается на недели; В определенных местах Ваш код работает совершенно не так, как Вы того ожидали;
  • 8. теория Нужен ли Вам рефакторинг? Ваш программный продукт работает, но внесение новой функциональности иногда затягивается на недели; В определенных местах Ваш код работает совершенно не так, как Вы того ожидали; Вы часто ошибаетесь в сроках реализации поставленной задачи;
  • 9. теория Нужен ли Вам рефакторинг? Ваш программный продукт работает, но внесение новой функциональности иногда затягивается на недели; В определенных местах Ваш код работает совершенно не так, как Вы того ожидали; Вы часто ошибаетесь в сроках реализации поставленной задачи; Вам приходится вносить однотипные изменения в разных местах проекта;
  • 10. теория “... в реальном мире все иначе ...”
  • 11. теория “... в реальном мире все иначе ...”
  • 12. теория Рефакторинг всегда подразумевает, что вы производите его с какой-то целью и опираетесь на какие-то данные строго преследуя поставленные задачи.
  • 14. теория Например: ● Улучшение читаемости кода;
  • 15. теория Например: ● Улучшение читаемости кода; ● Уменьшение зависимостей между определенными частями системы;
  • 16. теория Например: ● Улучшение читаемости кода; ● Уменьшение зависимостей между определенными частями системы; ● Оптимизация каких-либо компонентов системы вследствие замены архитектурных решений;
  • 17. теория Например: ● Улучшение читаемости кода; ● Уменьшение зависимостей между определенными частями системы; ● Оптимизация каких-либо компонентов системы вследствие замены архитектурных решений; ● и так далее;
  • 18. теория На каждом этапе вы должны четко знать несколько вещей: ● Зачем это нужно делать? ● Какую проблему вы решаете? ● Что на выходе вы должны получить?
  • 19. теория Какие есть методы рефакторинга? ● Инкапсуляция поля (Encapsulate Field); ● Выделение класса (Extract Class); ● Выделение интерфейса (Extract Interface); ● Выделение локальной переменной (Extract Local Variable); ● Выделение метода (Extract Method); ● Генерализация типа (Generalize Type); ● Встраивание (Inline); ● Введение фабрики (Introduce Factory); ● Введение параметра (Introduce Parameter); ● Подъём поля/метода (Pull Up); ● Спуск поля/метода (Push Down); ● Замена условного оператора полиморфизмом (Replace Conditional with Polymorphism); ● и так далее;
  • 20. теория Вспомним о тестах и их преимуществах:
  • 21. теория Вспомним о тестах и их преимуществах: Тесты предотвращают появление ошибок в новом коде
  • 22. теория Вспомним о тестах и их преимуществах: Тесты предотвращают появление ошибок в новом коде Тесты позволяют рефакторить код без риска его сломать
  • 23. теория Вспомним о тестах и их преимуществах: Тесты предотвращают появление ошибок в новом коде Тесты позволяют рефакторить код без риска его сломать Тесты могут использоваться в качестве документации
  • 24. теория Вспомним о тестах и их преимуществах: Тесты предотвращают появление ошибок в новом коде Тесты позволяют рефакторить код без риска его сломать Тесты могут использоваться в качестве документации Тесты улучшают дизайн кода
  • 25. теория Вспомним о тестах и их преимуществах: Тесты предотвращают появление ошибок в новом коде Тесты позволяют рефакторить код без риска его сломать Тесты могут использоваться в качестве документации Тесты улучшают дизайн кода Тесты способствуют повышению квалификации разработчиков
  • 26. теория Вспомним о тестах и их преимуществах: Тесты предотвращают появление ошибок в новом коде Тесты позволяют рефакторить код без риска его сломать Тесты могут использоваться в качестве документации Тесты улучшают дизайн кода Тесты способствуют повышению квалификации разработчиков Тесты ускоряют процесс разработки
  • 27. теория Вспомним о тестах и их преимуществах: Тесты предотвращают появление ошибок в новом коде Тесты позволяют рефакторить код без риска его сломать Тесты могут использоваться в качестве документации Тесты улучшают дизайн кода Тесты способствуют повышению квалификации разработчиков Тесты ускоряют процесс разработки
  • 28. теория Мифы о тестах: В нашем приложении внедрить тесты невозможно, у нас слишком быстро все меняется;
  • 29. теория Мифы о тестах: В нашем приложении внедрить тесты невозможно, у нас слишком быстро все меняется; В нашем приложении такая архитектура, что нам требуется много mock объектов;
  • 30. теория Мифы о тестах: В нашем приложении внедрить тесты невозможно, у нас слишком быстро все меняется; В нашем приложении такая архитектура, что нам требуется много mock объектов; Написание тестов отнимает слишком много времени;
  • 31. теория Мифы о тестах: В нашем приложении внедрить тесты невозможно, у нас слишком быстро все меняется; В нашем приложении такая архитектура, что нам требуется много mock объектов; Написание тестов отнимает слишком много времени; Мы не делаем код для “академиков”, нам нужны решения проще;
  • 32. теория Мифы о тестах: В нашем приложении внедрить тесты невозможно, у нас слишком быстро все меняется; В нашем приложении такая архитектура, что нам требуется много mock объектов; Написание тестов отнимает слишком много времени; Мы не делаем код для “академиков”, нам нужны решения проще; Рефакторинг, как методика весьма дорогая для нашей компании. Лучше тратить время программистов на создание новой функциональности;
  • 33. теория Рефакторинг не существует без: Сопутствующих Тестов Инструментов иначе это не рефакторинг и ваши действия никак не направлены на улучшение существующего кода.
  • 35. история Под прицелом: Zend Framework Zend Framework 1.11.11 VS 2.0.0beta3 2011-09-29 релиз релиз 2012-03-02
  • 36. история Для ZF2 были поставлены цели: “Zend Framework 2.0's focus in on improving consistency and perfomance” (фреймворк сфокусирован на улучшении согласованности и производительности)
  • 37. история Основные проблемы ZF1: ● Неудовлетворительная производительность;
  • 38. история Основные проблемы ZF1: ● Неудовлетворительная производительность; ● Дублирование некоторой функциональности используемых загрузчиков плагинов (plugin loader);
  • 39. история Основные проблемы ZF1: ● Неудовлетворительная производительность; ● Дублирование некоторой функциональности используемых загрузчиков плагинов (plugin loader); ● Слишком много ответственности выдано View;
  • 40. история Основные проблемы ZF1: ● Неудовлетворительная производительность; ● Дублирование некоторой функциональности используемых загрузчиков плагинов (plugin loader); ● Слишком много ответственности выдано View; ● Один тип исключения (Exception) на компоненту;
  • 41. история Основные проблемы ZF1: ● Неудовлетворительная производительность; ● Дублирование некоторой функциональности используемых загрузчиков плагинов (plugin loader); ● Слишком много ответственности выдано View; ● Один тип исключения (Exception) на компоненту; ● Слишком много путей для реализации одних и тех же задач;
  • 42. история Основные проблемы ZF1: ● Неудовлетворительная производительность; ● Дублирование некоторой функциональности используемых загрузчиков плагинов (plugin loader); ● Слишком много ответственности выдано View; ● Один тип исключения (Exception) на компоненту; ● Слишком много путей для реализации одних и тех же задач; ● Очень тяжелая начальная загрузка (bootstrap) приложения; ● Отдельные компоненты сложно оптимизировать из-за длинных цепочек вызова;
  • 43. история Основные проблемы ZF1: ● Неудовлетворительная производительность; ● Дублирование некоторой функциональности используемых загрузчиков плагинов (plugin loader); ● Слишком много ответственности выдано View; ● Один тип исключения (Exception) на компоненту; ● Слишком много путей для реализации одних и тех же задач; ● Очень тяжелая начальная загрузка (bootstrap) приложения; ● Отдельные компоненты сложно оптимизировать из-за длинных цепочек вызова; ● Ресурсоемкие тесты и необходимость служебных классов «живущих» вместе с ними;
  • 44. история Знаковые нововведения в ZF2: ● ZendDi — использует популярный паттерн в мире Java Dependency Injection (внедрение зависимостей);
  • 45. история Знаковые нововведения в ZF2: ● ZendDi — использует популярный паттерн в мире Java Dependency Injection (внедрение зависимостей); ● ZendEventManager — построен на замыканиях (лямбда-функиях);
  • 46. история Знаковые нововведения в ZF2: ● ZendDi — использует популярный паттерн в мире Java Dependency Injection (внедрение зависимостей); ● ZendEventManager — построен на замыканиях (лямбда-функиях); ● Иной взгляд на MVC;
  • 47. история Знаковые нововведения в ZF2: ● ZendDi — использует популярный паттерн в мире Java Dependency Injection (внедрение зависимостей); ● ZendEventManager — построен на замыканиях (лямбда-функиях); ● Иной взгляд на MVC; ● Центральное хранилище модулей (http://modules.zendframework.com/) для повторного использования кода, по примеру bundles для symfony;
  • 48. Но следует понимать, что PHP !== JAVA JAVA имеет сильные стороны и большой опыт реализации успешных интерфейсов. Как это применимо для PHP?
  • 51. практика use ZendEventManagerStaticEventManager, ZendLogFactory as LogFactory; $log = LogFactory($someConfig); $events = StaticEventManager::getInstance(); $events->attach('Foo', 'bar', function ($e) use ($log) { $event = $e->getName(); $target = get_class($e->getTarget()); $params = json_encode($e->getParams()); $log->info(sprintf( '%s called on %s, using params %s', $event, $target, $params )); });
  • 52. практика // Later, instantiate Foo: $foo = new Foo(); // And we can still trigger the above event: $foo->bar('baz', 'bat'); // results in log message: // bar called on Foo, using params // {"baz" : "baz", "bat" : "bat"}"
  • 53. практика ZendDi Паттерн Dependency Injection Внедрение зависимости
  • 54. практика Цель — выделить доступ к определенному сервису / объекту в отдельный слой, дабы стать менее зависимым от реализации самого сервиса / объекта.
  • 55. практика class SomeClass { } $di = new ZendDiDi(); $someClass = $di->get('SomeClass'); ● Делегируем создание объекта контейнеру;
  • 56. практика class SomeClass { protected $_injectionClass; public function __construct(InjectionClass $injectionClass) { $this->_injectionClass = $injectionClass; } } $di = new ZendDiDi(); $someClass = $di->get('SomeClass'); ● В результате, в переменной $someClass будет новый инстанс объекта с инициализированным свойством injectionClass.
  • 57. практика Откуда Di контейнер узнает как необходимо инициализировать тот или иной объект?
  • 58. практика ZfcUser/config/module.config.php 'di' => array( 'instance' => array( 'alias' => array( 'zfcuser' => 'ZfcUserControllerUserController', 'zfcuser_user_service' => 'ZfcUserServiceUser', 'zfcuser_auth_service' => 'ZendAuthenticationAuthenticationService', 'zfcuser_uemail_validator' => 'ZfcUserValidatorNoRecordExists', 'zfcuser_uusername_validator' => 'ZfcUserValidatorNoRecordExists', 'zfcuser_captcha_element' => 'ZendFormElementCaptcha', // Default ZendDb 'zfcuser_zend_db_adapter' => 'ZendDbAdapterAdapter', 'zfcuser_user_mapper' => 'ZfcUserModelUserMapper', 'zfcuser_usermeta_mapper' => 'ZfcUserModelUserMetaMapper', 'zfcuser_user_tg' => 'ZendDbTableGatewayTableGateway', 'zfcuser_usermeta_tg' => 'ZendDbTableGatewayTableGateway', ), /* …. */ ● модуль обеспечивает очень простую и настраиваемую ) ); систему аутентификации и регистрации пользователя
  • 59. практика Конфигурационный файл только объектов маленького модуля занимает 159 строк. Любая неточность == частично инициализированный объект
  • 60. практика Для реализации Di паттерна ZF2 использует рефлексию (reflection)
  • 61. практика Проблемы: ● Сложность отладки программы;
  • 62. практика Проблемы: ● Сложность отладки программы; ● Потеря производительности;
  • 63. практика Проблемы: ● Сложность отладки программы; ● Потеря производительности; ● Приложение трудно читать из-за неочевидности какой объект отдает Di контейнер в данный момент;
  • 64. практика Di контейнер внутри ZF2 ● Используется в основе нового взгляда на парадигму MVC; ● “Тяжелый Bootstrap” ZF1 переместился в Zend/Mvc/Bootstrap.php
  • 65. практика Zend/Mvc/Bootstrap.php $di = new Di; $di->instanceManager()->addTypePreference('ZendDiLocator', $di); // Default configuration for common MVC classes $diConfig = new DiConfiguration(array('definition' => array('class' => array( 'ZendMvcRouterRouteStack' => array( 'instantiator' => array( 'ZendMvcRouterHttpTreeRouteStack', 'factory' ), ), 'ZendMvcRouterHttpTreeRouteStack' => array( 'instantiator' => array( 'ZendMvcRouterHttpTreeRouteStack', 'factory' ), ), 'ZendMvcViewDefaultRenderingStrategy' => array( 'setLayoutTemplate' => array( 'layoutTemplate' => array( 'required' => false, 'type' => false, ), ), )
  • 66. практика Ваше приложение зависимо от Di ● С ростом проекта вызовы Di расползаются по всему приложению и в какой-то степени он становиться схож с Singleton'ом; ● Вы получаете узкое место и потенциально жесткую архитектуру, хоть и с возможностью подмены одного объекта другим.
  • 67. практика Cобрав все за и против – произведем нагрузочное тестирование
  • 69. тестирование Команда ZF2 ставила для себя задачи улучшения согласованности и повышения производительности. А также заявляла о некоторых решениях: ● Переход на Namespace (пространство имен); ● Рефакторинг исключений; ● Переход ZF исключительно на автозагрузку без использования require_once; ● Совершенствование и стандартизация системы плагинов;
  • 70. тестирование Замеры производительности производились на железе следующей конфигурации: Процессор: CPU cores: 2 CPU family: 6 CPU MHz: 2999.748 Model Name: Intel Core 2 Duo CPU E8400 Cache size: 6144 KB
  • 71. тестирование Оперативная память: Операционная система: RAM: 2011 MB Debian: 6.0.5 Linux core: 2.6.32-5-amd64 ZF2 Приложение: ZendSkeletonApplication (https://github.com/zendframework/ZendSkeletonApplication) ZF1 Приложение: Default Welcome Application
  • 72. тестирование Окружение: Nginx: 1.2.0 Php: 5.4.0 Php modules: Core, ctype, curl, date, dom, ereg, exif, fileinfo, filter, ftp, gd, hash, iconv, json, libxml, mbstring, mcrypt, mysql, mysqli, mysqlnd, pcre, PDO, pdo_mysql, pdo_sqlite, Phar, posix, Reflection, session, SimpleXML, soap, sockets, SPL, sqlite3, standard, tokenizer, xml, xmlreader, xmlwriter, zip, zlib
  • 73. тестирование Тестирование через Apache jMeter Задача Протестировать отказоустойчивость фреймворка при нагрузке 3000 пользователей в минуту на протяжении 10-ти минут в локальной сети. Решение 2 ноутбука через wifi каждые 400 миллисекунд осуществляют 10 одновременных подключений к серверу;
  • 78. тестирование Результаты ZF1: В среднем ZF1 выдавал страницу за 26ms; Может обслуживать клиентов в минуту ~1200-1400; Минимально клиент ждал 19ms; Максимально клиент ждал 250ms; Пиковая нагрузка на сервер составила: RAM ~10 MB; CPU ~38%-50%; Load Average 0.39;
  • 83. тестирование Результаты ZF2: В среднем ZF2 выдавал страницу за 102ms; Может обслуживать клиентов в минуту ~1000-1200; Минимально клиент ждал 47ms; Максимально клиент ждал 341ms; Пиковая нагрузка на сервер составила: RAM ~20MB; CPU ~92%-100%; Load Average 3.98;
  • 84. тестирование Под прицелом: Zend Framework Zend Framework 1.11.11 VS 2.0.0beta3 2011-09-29 релиз релиз 2012-03-02 Из приведенных графиков видно, что ZF2 не только медленнее ZF1, но и весьма прожорлив по ресурсам сервера.
  • 89. профилирование Основная проблема производительности ZendDi ● слишком много обращений за один сеанс скрипта;
  • 90. профилирование Компромиссы, оптимизация? В связи с текущей архитектурой, единственный выход, который мне видится — выпустить Di контейнер в виде Си расширения для PHP;
  • 91. профилирование Компромиссы, оптимизация? В связи с текущей архитектурой единственный выход, который мне видится — выпустить Di контейнер в виде Си расширения для PHP; Я реализовал пробный вариант решения, в котором учтены еще далеко не все возможные инъекции, задуманные разработчиками, и благодаря которому быстродействие фреймворка уже увеличилось на 20%;
  • 93. выводы ● ZF2 существенно медленнее ZF1;
  • 94. выводы ● ZF2 существенно медленнее ZF1; ● Dependency injection в PHP сложно организуемый паттерн.
  • 95. выводы ● ZF2 существенно медленнее ZF1; ● Dependency injection в PHP сложно организуемый паттерн. ● PHP !== Java — эти границы следует очень четко понимать;
  • 96. выводы ● ZF2 существенно медленнее ZF1; ● Dependency injection в PHP сложно организуемый паттерн. ● PHP !== Java — эти границы следует очень четко понимать; ● Тестирование решает многие проблемы выбора инструмента или методик;
  • 97. выводы ● ZF2 существенно медленнее ZF1; ● Dependency injection в PHP сложно организуемый паттерн. ● PHP !== Java — эти границы следует очень четко понимать; ● Тестирование решает многие проблемы выбора инструмента или методик; ● Любое заявление среди разработчиков, и мое в частности, должно быть перепроверено вами лично и сделаны собственные выводы;
  • 98. Спасибо ;) Докладчик: Алексей Пархоменко alexey@iprojects.com.ua