Enter: legacy code

32

Transcript of Enter: legacy code

Page 1: Enter: legacy code
Page 2: Enter: legacy code

Боль №3: Legacy Code

Page 3: Enter: legacy code

The only valid measurement of code quality: WTF/minute

Page 4: Enter: legacy code
Page 5: Enter: legacy code
Page 6: Enter: legacy code
Page 7: Enter: legacy code

Почему не проще?

• Код, в принципе, решает свои задачи

• На него потрачено немало человеко-часов

• Ресурсы ограничены и много текущих задач

• Есть другой подход - evolution

Page 8: Enter: legacy code

Как будем улучшать?• Будем использовать composer

• Придерживаться стандартов PSR

• Поэтапно рефакторить

• Отлаживать только с Xdebug

• Профилировать код на бою

Page 9: Enter: legacy code

Наследство• проект живет с 17 июля 2011

• построен на Zend 1 (Zend 2 уже больше двух лет*)

• My_Super_Awesome_Class (пространству имен уже два года*)

• отсутствие единого стандарта (до PSR еще долгих два года*)

• отсутствие цельной архитектуры (толстые контроллеры; мешанина из php и sql; массивы адской структуры)

• сторонние библиотеки в library (composer только на подходе*)

• код опирается на PHP 5.2 (PHP 5.3 уже два года*)

* на момент старта разработки

Page 10: Enter: legacy code

Используйте Composer

Page 11: Enter: legacy code

• Проще управлять зависимостями

• Проще обновлять сторонние библиотеки

• Очень гибкий инструмент:

• version: ~x.y, > x.z; x.y.z; x.*

• private: Satis или Toran Proxy

• non-composer: директива repositories

• Автозагрузка PSR-0, PSR-4 и не только

• Разработчики не лезут в исходный код сторонних библиотек!

Какие преимущества?

Page 12: Enter: legacy code

однажды добавил zend

однажды его обновил

и криво удалил

Как было: жизненный цикл Zend в проекте

Page 13: Enter: legacy code

Как сейчас{ "name": "enter/core", "require": { "php": ">=5.5", …, "misterion/pinba-phpdoc": "1.0.*@dev", "zendframework/zendframework1": "~1.12" }, "require-dev": { "phpunit/phpunit": "~4", "squizlabs/php_codesniffer": "~1.0" }, "autoload": { "classmap": ["library/"], "psr-0": { … }, "psr-4": { "Enter\\": "src/Enter" } }, "config": { "bin-dir": "bin" } }

смело используем новые возможности языка -

Enter: code style -

а новый положим рядом -старый код нужно поддерживать -

остались правки в исходном коде сторонних библиотек -

Page 14: Enter: legacy code

Составьте roadmap по рефакторингу

• Придерживайтесь стандарту PSR-4 для улучшения структуры проекта

• Пишите unit-тесты

• Покрывайте критичный функционал приемочными тестами

• Придерживайтесь принципов SOLID, DRY, KISS и YAGNI

• Анализируйте логи

Page 15: Enter: legacy code

Анализ логов для рефакторинга

• Настроили rsyslog и logrotate для сбора логов со всех боевых машин

• cat %project%-pool-ro.log | grep -Eo "PHP.*[0-9]" | sort | uniq -c

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

Page 16: Enter: legacy code

52 PHP Fatal error: Call to a member function getId() on a non-object in %file% on line 1233

1871 PHP Fatal error: Call to a member function setPrice() on a non-object in %file% on line 125

217392 PHP Warning: array_key_exists() expects parameter 2 to be array, null given in %file% on line 826

29676 PHP Strict Standards: Only variables should be passed by reference in %file% on line 1269

217392 PHP Warning: array_key_exists() expects parameter 2 to be array, null given in %file% on line 826

147344 PHP Warning: Invalid argument supplied for foreach() in %file% on line 2522

и еще сотни строк

* количество записей в день

Что получили в начале

Page 17: Enter: legacy code

7 PHP Warning: array_key_exists() expects parameter 2 to be array, null given in %file% on line 333

75 PHP Warning: array_key_exists() expects parameter 2 to be array, null given in %file% on line 336

60 PHP Warning: Creating default object from empty value in %file% on line 60

1 PHP Warning: Invalid argument supplied for foreach() in %file% on line 215

86 PHP Warning: Invalid argument supplied for foreach() in %file% on line 2198

64 PHP Warning: Invalid argument supplied for foreach() in %file% on line 407

75 PHP Warning: Invalid argument supplied for foreach() in %file% on line 55

Что имеем сейчас

Page 18: Enter: legacy code

Что дальшеСобираем slowlog с помощью fabric

@task(default=True)def alalyze_slow_logs():   execute(get_slow_log_ro)   execute(agregate_slow_log_ro)   execute(alalyze_slow_log_ro)

@task@parallel@roles('dbro')def get_slow_log_ro():   get(       env.log_remote_path + 'slow.log',       env.log_local_path + 'slow_ro.%s.log' % (env.host)   )

@taskdef agregate_slow_log_ro():   local('cat %s/slow_ro.*.log > %s/slow_ro.log' % (       env.log_local_path,       env.log_local_path   ))

@taskdef alalyze_slow_log_ro():   local('mysqldumpslow %s/slow_ro.log > %s/total_slow_ro.log' % (       env.log_local_path,       env.log_local_path   ))

- просто `$ fab` для старта

- параллельно собираем slow.log со всех тачек

- собираем в один файл для обработки

- прогоняем его через mysqldumpslow

Page 19: Enter: legacy code
Page 20: Enter: legacy code

Улучшайте процесс отладки кода

Page 21: Enter: legacy code

Logger::getLogger(…)->debug(‘Загружаем информацию о дереве категорий');

зачем это повсюду в коде?

Page 22: Enter: legacy code
Page 23: Enter: legacy code

Почему сразу не использовать Xdebug?!

• Сложно настроить удаленную отладку

• ssh -R 9191:127.0.0.1:9000 sandbox

• Сложно настроить отладку через шлюз

• ProxyCommand или ssh -L 9191:sandbox:9191 -R 9191:127.0.0.1:9000 gateway

• var_dump(…); die(); быстрее

• на самом деле это наиболее затратный по времени способ отладки

Page 24: Enter: legacy code

Xdebug - это просто!

ssh -R 9191:127.0.0.1:9000 sandbox

zend_extension = xdebug.so xdebug.remote_enable = 1 xdebug.remote_autostart = 1 xdebug.remote_host = 127.0.0.1 xdebug.remote_port = 9191 xdebug.idekey = PHPSTORM

1

2

3

4

Page 25: Enter: legacy code

Пользуйтесь профилировщиком для поиска узких мест

• В качестве профилировщика взяли Pinba

• В качестве «клиента» взяли Intaro Pinboard

• Для включения профилировщика используем подход Progressive Enhancement (подробно тут http://kamil.samigullin.info/github/GracefulDegradation)

Page 26: Enter: legacy code

Полезные ссылки• https://en.wikipedia.org/wiki/SOLID_(object-oriented_design)

• https://en.wikipedia.org/wiki/Don%27t_repeat_yourself

• https://en.wikipedia.org/wiki/KISS_principle

• https://en.wikipedia.org/wiki/You_aren%27t_gonna_need_it

• http://kamil.samigullin.info/github/GracefulDegradation

• http://pinba.org

• http://intaro.github.io/pinboard/

• http://xdebug.org

Page 27: Enter: legacy code
Page 28: Enter: legacy code
Page 29: Enter: legacy code

эволюционируй

Page 30: Enter: legacy code

Спасибо за внимание!

Есть вопросы?

Камиль Самигуллин какой-то разработчик

[email protected] @ikamilsk github.com/kamilsk

Page 31: Enter: legacy code
Page 32: Enter: legacy code

Присматриваюсь к Blackfire, подробности в следующих докладах

• https://blackfire.io/