РЕФАКТОРИНГ
И ВТОРОЕ РОЖДЕНИЕ ПРОЕКТА
    на примере 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

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

  • 1.
    РЕФАКТОРИНГ И ВТОРОЕ РОЖДЕНИЕПРОЕКТА на примере Zend Framework 2.0 Докладчик: Алексей Пархоменко alexey@iprojects.com.ua
  • 2.
  • 3.
    Теория Что такое рефакторинг? — изменение исходного кода программы без изменения его внешнего поведения.
  • 4.
    Теория Проблемы рефакторинга ● потребность вносить изменения в существующий код; ● необходимость строго придерживаться поставленной задачи; ● покрывать код проверочными тестами;
  • 5.
    теория Нужен ли Вамрефакторинг?
  • 6.
    теория Нужен ли Вам рефакторинг? Ваш программный продукт работает, но внесение новой функциональности иногда затягивается на недели;
  • 7.
    теория Нужен ли Вам рефакторинг? Ваш программный продукт работает, но внесение новой функциональности иногда затягивается на недели; В определенных местах Ваш код работает совершенно не так, как Вы того ожидали;
  • 8.
    теория Нужен ли Вам рефакторинг? Ваш программный продукт работает, но внесение новой функциональности иногда затягивается на недели; В определенных местах Ваш код работает совершенно не так, как Вы того ожидали; Вы часто ошибаетесь в сроках реализации поставленной задачи;
  • 9.
    теория Нужен ли Вам рефакторинг? Ваш программный продукт работает, но внесение новой функциональности иногда затягивается на недели; В определенных местах Ваш код работает совершенно не так, как Вы того ожидали; Вы часто ошибаетесь в сроках реализации поставленной задачи; Вам приходится вносить однотипные изменения в разных местах проекта;
  • 10.
    теория “... в реальноммире все иначе ...”
  • 11.
    теория “... в реальноммире все иначе ...”
  • 12.
    теория Рефакторинг всегда подразумевает, что выпроизводите его с какой-то целью и опираетесь на какие-то данные строго преследуя поставленные задачи.
  • 13.
  • 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.
    теория Рефакторингне существует без: Сопутствующих Тестов Инструментов иначе это не рефакторинг и ваши действия никак не направлены на улучшение существующего кода.
  • 34.
  • 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?
  • 49.
  • 50.
  • 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, instantiateFoo: $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обрав все заи против – произведем нагрузочное тестирование
  • 68.
  • 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 одновременных подключений к серверу;
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
    тестирование Результаты ZF1: В среднемZF1 выдавал страницу за 26ms; Может обслуживать клиентов в минуту ~1200-1400; Минимально клиент ждал 19ms; Максимально клиент ждал 250ms; Пиковая нагрузка на сервер составила: RAM ~10 MB; CPU ~38%-50%; Load Average 0.39;
  • 79.
  • 80.
  • 81.
  • 82.
  • 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, но и весьма прожорлив по ресурсам сервера.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
    профилирование Основная проблема производительности ZendDi ● слишком много обращений за один сеанс скрипта;
  • 90.
    профилирование Компромиссы, оптимизация? В связис текущей архитектурой, единственный выход, который мне видится — выпустить Di контейнер в виде Си расширения для PHP;
  • 91.
    профилирование Компромиссы, оптимизация? В связис текущей архитектурой единственный выход, который мне видится — выпустить Di контейнер в виде Си расширения для PHP; Я реализовал пробный вариант решения, в котором учтены еще далеко не все возможные инъекции, задуманные разработчиками, и благодаря которому быстродействие фреймворка уже увеличилось на 20%;
  • 92.
  • 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