Исправляем баги с помощью рефакторинга
Василий Половнёв в советах рассказывает, как исправлять баги:
Сначала баг нужно повторить: найти последовательность действий, состояние или окружение, при котором баг повторяется. Без этого шага вы выкатите не исправление бага, а слепую догадку, которая вряд ли сработает, но точно
что-то сломает.Когда проблема гарантированно повторяется, можно приступать к изолированию: искать причину проблемы, генерируя и проверяя гипотезы, отрезая всё, не относящееся к проблеме.
Когда причина обнаружена, остаётся устранить баг и порефлексировать: что пошло не так, почему, как сделать так, чтобы в будущем таких багов не было.
Написано верно. Такому алгоритму и нужно следовать, исправляя баги. Но что делать, если баг воспроизвести нельзя? Я расскажу об одном таком баге, с которым пришлось бороться в CityAds.
Симптом
Бразильские вебмастеры жалуются, что при выводе заработанных денег не работает проверка
Попытка воспроизведения
Баг не повторяется ни на локальной копии сайта, ни на тестовых стендах, ни на российском сервере. Воспроизводится, только если напрямую зайти на бразильский сервер. Вышеприведенный алгоритм бессилен.
Изучение кода
К сожалению, в CityAds было много
$_SESSION['sms_codes'][$account_id]['code'] = $code;
$_SESSION['sms_codes'][$account_id]['time'] = time();
$_SESSION['sms_codes'][$account_id]['amount'] = $amount;
Работа с тремя элементами массива происходила несколько раз. Каждый раз три строчки копировались и немного изменялись. Например, при генерировании нового кода очищался один элемент, а не все три.
Говнокод плох тем, что он «одноразовый». Его просто написать, но сложно понимать и изменять.
Логирование
Когда баг нельзя воспроизвести локально, может помочь логирование. Чтобы понять, почему код работает не так, как ожидается, вы добавляете инстуркции для записи значений переменных в лог, например, в файл. Логировать полезно не все действия подряд, а только определенные, например, с вашего
Я залогировал значения переменных и увидел, что к моменту проверки кода в сессии было пусто, как будто код вообще не генерировался. Тем не менее, другие значения, не связанные с
Гипотеза
Мне было ясно, что причина бага связана с хранением данных в разделяемой памяти. Я предположил, что между генерированием и проверкой
Я решил не искать, кто именно портит данные в сессии, а с нуля переписать обработку
Рефакторинг
К этому времени мы подключили Symfony и писали новый код по принципам SOLID. Я написал сервис, в котором инкапсулировал логику работы с
Переписанный код сразу заработал как нужно. После выкладки оказалось, что проблема на бразильском сервере исчезла.
Ссылки по теме
- Подробности о переходе от императивного кода к объектному, SOLID, DTO, DI в скринкасте по рефакторингу с помощью PHP Storm
- Еще одна байка из CityAds на хабре: PHP, статические переменные внутри методов класса и история одного бага
Оставьте свой комментарий