Не так давно я описывал процесс рефакторинга одного проекта зашедшего в отдел, мы вместе посмеялись да поплакали, но ведать мораль оттуда не вынесли. И в этой истории мы не «белые и пушистые»…
История начиналась банально — проект загибается, заказчик ищет новую команду разработки и находит нас. Мы такие все из себя, на белом коне въезжаем в проект, а там ничего страшного, просто функциональный plain PHP код, т.е. классов нет, функций практически тоже (один файл functions.php, а в нем dbconnect(), userlogin() да функция-шаблонизатор, и что-то еще по мелочи). Смотрим — а проблема то в нагрузке — до 10 000 онлайн пользователей и в это время на сайт и зайти нельзя. Хорошо, задача ясна, садим в проект разработчика, который знаком с оптимизацией, ну и он начал работать. И да, после двух недель работы (а может и больше, уже не помню) сайт ожил, чуть-чуть индексов, чуть-чуть кеширования, еще немного оптимизации SQL запросов и нагрузка на сервера спала.
Заказчик доволен, и уже у него появляются «хотелки» на новый фичи, да немного еще старых багов подкидывает на фикс. В этот момент эффективность нашего разработчика сильно падает — он то любит заниматься оптимизацией, а вот эти CSS да JavaScript ну ой как туго идут…
Спустя некоторое время, мы заменяем разработчика в проекте, новому человеку больше по душе приходятся фичи и ченжи заказчика, и наша эффективность опять идет вверх, заказчик удовлетворен, мы считаем деньги. Все хорошо и ничто не предвещало случившегося.
В проекте всё меньше и меньше работы, задачи скатываются до уровня trivial, и мы принимаем решение посадить в него «зелёного» бойца, дабы опробовать его, да и заказчик дал на это добро. Старт был гладким, а потом начались проблемы, то вылезли за сроки, которые сами и оговорили, то на сервер залили не совсем рабочий код. И как итог — «Спасибо, что помогли, вы меня действительно выручили, но дальше я обойдусь без вас»
Начинаем разбор полётов, решаем, что новенького мы зря посадили в проект, но я к тому моменту залез в изучение кода по уши, и поэтому сейчас опишу то, чего я там не увидел.
Шаблонизатор
В системе был создан элементарный шаблонизатор с нативным синтаксисом (что скорее плюс), но в шаблонах постоянно встречались обращения к БД, и при изменении структуры приходилось перелапачивать не только код страниц, но и все шаблоны. Таким образом необходимо было разделить логику от представления раз и навсегда.
Если говорить о функции-шаблонизаторе, то вот элементарный пример:
/** * @param string * @param array */ function template($path, $vars = array()) { extract($vars); include $path; } template("templates/index.phtml", array( "foo" => "bar", "user" => $user ));
Остальное остается на совести разработчика, собственно даже в тот же Smarty можно впихнуть логику при должном желании.
Сущности
Процесс разработки так же затруднялся тем, что очень много копипаста было в проекте, и вносить изменения сразу и везде было проблематично (поиск и замена по папке это не тру). А необходимо было выделить сущности, и методы для работы с ними свести в один класс (или хотя бы файл). Таким образом мы бы смогли уменьшить повторение кода (и повторения ошибок).
Контроллеры
Тут просто напрашивался этот пункт, поэтому я его добавил, и хотел сказать следующее — если у вас в корне проекта лежит пару десятков файлов, то не стоит заморачиваться, и переписывать их все, чтобы у вас получилась папочка controllers и единая точка входа, ведь эти файлы с поставленной задачей вполне справляются. Как вывод — не стоит гнаться за идеальным кодом, такие вложения труда могут не окупиться.
Работа с БД
Как я описывал выше, SQL запросы встречались в проекте везде и всюду, и даже процесс экранирования входных данных в них был разный. Привести к единому стилю, создать нормальный врапер для БД, или хотя бы заменить использование расширения mysql на что-либо более современное.
Можно было бы написать простой врапер для врапера PDO за 20 минут, конечно он не будет универсален, но облегчит труд рефакторинга:
- легко логировать используя одну точку входа
- можно быстро добавить кеширование для всех запросов
Кеширование
Тут стоит упомянуть, кеширование прикрутили, НО лишь там где указал заказчик, а хотелось бы, чтобы был кеш везде где это имеет смысл, а не исходя из заключения «вроде тут», т.е. надо было в каждый файл заглянуть, логи проанализировать, да и время кеширования можно было потюнить в рейлтайме, но сдвиг часового пояса нам наверное сильно помешал, и никто не захотел ради этого из дома мониторить сервер, или хотя бы попросить об этом наших же админов (а мы такие услуги предоставляем ;).
Работа над ошибками
Тут все легко, если вы открываете PHP файл, а вам IDE подсказывает кричит о ошибках в коде, то уделите пять минут времени и исправьте их:
И еще — в обязательном порядке включите отображение ошибок, и запомните — «подавленный» Notice крадет время:
error_reporting(E_ALL); ini_set('display_errors', '1');
Тестирование
— Unit тестирование? О чем речь, у нас тут запара, надо выкатывать на лив!
Ну-ну…
Клиентская оптимизация
Этого пункта не коснулся ни один из разработчиков, участвовавших в проекте, и это действительно огорчает. Конечно, главная страничка проекта не слишком и тяжела — всего 300кб, но на них приходится 15 JS файлов, 18 картинок в CSS (спрайты спасут сервер), так же стоило потереть старые хуки для браузеров (IE5.5 и IE6), облегчить верстку, ведь 8,7kb это не так уж и мало (слишком много таблиц).
Собственно, сайт по оценке YSlow получает оценку C (70), что я считаю недопустимым, для сравнения мой блог с кучей картинок — A (90). Как улучшить эти показания очень хорошо рассказывает сайт webo.in, и я думаю ему стоит уделить место в закладках.
«Не наш» проект
Еще я бы хотел рассказать о том, что очень часто программисты не переживают и не живут проектом, а это очень негативно сказывается на взаимоотношения с заказчиком и на развитие проекта. Проект должен стать чем-то неотъемлемым от вас, если сайт загибается под наплывом пользователей — вам тоже должно быть не по себе, ведь это ваше творение страдает, и ему нужна ваша помощь. Вы как специалист должны советовать заказчику, как развивать проект, ведь именно вы знаете о всех ноу-хау в web-разработке, и не стоит ждать, что с предложением о улучшении выступит он, сделать первый шаг должны именно вы и именно сейчас. Не стоит в проекте жить одним днем, надо смотреть вперед и возможно рефакторинг проекта стоило начать еще вчера.
P.S
Если в вашем проект все идет гладко, то присмотритесь, возможно под столь сладким обликом притаился рак вашего безразличия к жизни проекта.
P.P.S
Если вы уже загорелись начать рефакторинг, то я вас еще чуть-чуть еще отвлеку — стоит рефакторинг правильно «продать» заказчику, который любит и умеет считать деньги, с ним стоит разговаривать именно в этом ключе. Удачи вам.
Вот про врапер очень ценное замечание. Дня три назад примчался друг и говорит нужно спасти проект, а то хостер отключит за залишнее использование БД.
В коде оказалась такая же функция dbconnect (Поповщина чтоли). Первым делом добавил в неё singleton введя статическую переменную.
А вот профайлинг запросов был не возможен, так как юзался голый mysql_query. Разве что создать функцию my_mysql_query и сделать рефакторинг с помощью новых фич netbeans 7, но по ftp это было геморно, а пиво уже грелось, заткнули временно full page cache, благо единая точка для фронт енда была.
Беда в том, что в PHP нельзя переопределять уже определенные функции…
вообще-то, можно. есть pecl расширение runkit, но проще создать свою функцию-врапер, и провести рефаторинг проекта. заменив стандартный вызов, на свой врапер.
Извеняюсь за прямоту, но аккордеон уёбищный, я себе чуть шею не сломал >_<
Уж лучше табы…
AmdY, начиная с mysql 5.0.37 есть встроенный арофайлер. Можно воспользоватсья им.
проблема в том, что подобный legacy code, как правильно находится на говнохостинге, даже slow query log не допросишься, они типа не ведут логирования. если сэкономили на программистах, что удивляться экономии на хостинге, всё сэкономленное всегда придётся отдавать за поддержку-доработку.
Вы знаете, вот абзац “‘не наш’ проект” поставил больше ясности в проблеме чем все вышесказанное. Когда-то ловил себя на мысли, что стоит поставить себя, как разработчика, на место заказчика и сразу все меняется и меняется подход к делу.. А там глядишь и заказчик уже совсем по другому с тобой начинает общаться, не просто как с разработчиком, а как с партнером по проекту..
“Это неправильные пчелы и онм делают неправильный мед” (С) Винни-Пух
А что – новичка никто не ревьювил?
вообще, все что делают новички нужно перепроверять. Прям досконально придираться. И смотреть их написанный код.
Длинная узкая лента комментариев при том, что больше половины страницы пустует – выглядит ужасно. Да и смотреть на правую сторону, а не по центру, тоже не радует
Отличная статья! Практически тоже самое рассказываю нашим новичкам. Лучше подумать о багах заранее и исправить/проверить лишний раз/отрефакторить/написать тесты, чем потом наблюдать, как в проекте отваливается то одно, то другое.