Неуловимые баги: ошибки, ускользнувшие от всех тестов и проверок

082335e6c0614bd3b874370561e9a82c.jpg

Даже в относительно простых продуктах изредка встречаются баги, которые успешно скрываются от любых тестов и попадают в релиз. И чем сложнее приложение, тем выше вероятность появления таких багов. В продуктах, содержащих миллионы строк кода, вообще нереально выловить все ошибки, можно лишь максимально снизить их поголовье к выпуску очередной версии. И после релиза такие баги иногда дают о себе знать. О том, как мы охотимся за нинзя-багами и чем мы их лечим, нам рассказал Александр Гречишкин, project manager Parallels.

Баги-ниндзя


Для нас это чувствительный вопрос, потому что нашими продуктами пользуется более 5 млн человек. И когда выходит новая версия, основная масса пользователей переходит на неё в течение 1–2 недель. В это время часто всплывает какой-то баг, который не был обнаружен при тестированиях, но проявляется довольно часто у пользователей.

Недавно мы писали о том, как устроена наша система отчётов. Вкратце повторимся: когда падает наша программа, пользователю предлагается отправить отчёт. Причины могут быть разные, например, обращение к недоступной или защищённой памяти. Отчёт представляет собой набор файлов: логи, внутренняя информация о работе приложения, конфигурация компьютера, системное окружение. У нас работает отдельная система, которая собирает эти отчёты, обрабатывает, анализирует и формирует статистический отчёт, который обновляется практически в реальном времени.

В этом отчёте можно группировать регистрируемые случаи сбоев по разным признакам: по виду, по IP и так далее. Отчёт позволяет нам отслеживать текущую динамику сбоев и вовремя обнаруживать нехорошие тенденции. А заодно помогает подсчитывать одинаковые и вылавливать такие баги-ниндзя, которые ускользнули от всех тестов и проникли в production.

7aa4e305ae45431d8652bf1367f40ae3.jpg

Индивидуальное обслуживание


Когда падения происходят у 100 разных пользователей 1 раз — это плохо. Но если приложение упадёт 100 раз у одного — это для нас гораздо хуже, потому что с высокой вероятностью означает, что у человека проявился какой-то хитрый баг, а многочисленные падения не увеличивают доверие пользователя к нашему продукту. Поэтому мы стараемся отслеживать такие ситуации и как можно скорее на них реагировать.

Бывает так, что отчёты позволяют быстро найти причину уникального бага и придумать, как помочь человеку. Но очень быстро выпустить обновление продукта не получится, даже если какой-то разработчик приходит с готовым фиксом. Наша кодовая база содержит десятки миллионов строк кода, и такой продукт мы никогда не выпускаем на авось. Мы уже сталкивались с тем, что изменение всего лишь одной буквы в коде приводит к полностью неработоспособному продукту. Поэтому при пересборке с внедрением фикса нужно пройти все автотесты, и релизные чек-листы, что занимает у нас от 2-х дней до недели в зависимости от доступных ресурсов.

Как же тогда быстро помочь отдельным пользователям, у которых проявляются уникальные баги? Для этого в форме отправки отчёта о падении мы вставили поле для почтового ящика пользователя и галочку «Пришлите мне решение, когда оно будет доступно». Если можно пофиксить баг, даже не изменяя продукт, мы пишем письма с инструкциями тем пользователям, которые указали в отчёте свои почтовые ящики. Если же падение пофикшено в новом релизе, а пользователь все еще использует старый, то при обнаружении креша, мы высылаем письмо о том, что стоит обновиться. Зачастую пользователи просто отключают автоматическое обновление в продукте.

Например, был такой баг: у некоторых пользователей падала система отправки отчёта о падении. Смешная ситуация, но тем не менее. Причина была в избыточном количестве файлов в папке с логами. Решение было простое: написать пользователю, чтобы он зашёл в папку Logs и удалил все файлы. Этот баг мы сразу исправили в коде и массово распространили в следующем обновлении.

А представьте, как это выглядит с точки зрения самого пользователя. У него упала программа, он ругается, нажимает кнопку отправки отчёта, а через пару минут ему приходит уведомление о письме от Parallels: «Мы видим, у вас проблема, её можно решить так-то». Индивидуальный сервис практически в режиме реального времени! Нам даже благодарственные письма писали за то, что мы в течение минут предлагали решение проблемы, не дающей работать.

Произвол MacOS


Зачастую падения связаны не с багами в наших продуктах, а с системным окружением. Как ни странно, но до выхода Mac OS 10.11 главной причиной падений была сама Mac OS. В версии 10.9 появились так называемые silent updates — тихие обновления. Например, вы оставили компьютер, приходите на следующий день, а он говорит: «Я тут установил обновления, но не волнуйся, у меня есть функция resume». То есть все работавшие перед установкой обновления приложения снова запускаются. И вроде бы ничего не изменилось: те же сайты открыты в Safari, недописанное письмо в почте, переписка в мессенджере.

Из-за бага в Mac OS система убивала Windows Server раньше, чем она дожидалась завершения работы приложений. У нас приложение тяжелое и ему надо какое-то время чтобы засаспендить работающие виртуальные системы, но Mac OS решал, что оно очень медленно реагирует и срубал его при помощи kill -9. А у нас многопроцессная система, два драйвера ядра, обработчик виртуальной машины, графический интерфейс, интеграционные компоненты. В Windows в это время могло что-то скачиваться или устанавливаться. Например, ставились обновления, изменена масса записей в реестре, выключать ни в коем случае нельзя. А Mac OS или срубал Windows Server раньше того, кто им пользовался, или срубал Parallels Desktop по причине меделнного саспенда виртульных машин.

Естественно, начинали массово падать приложения, и сама Mac OS активно генерировала отчёты. Наши приложения проверяли системные логи, находили эти записи, и честно рапортовали пользователям, которые пересылали эти отчёты нам. А тут ещё нужно помнить, что, по нашей статистике, лишь каждый четвёртый нажимает на кнопку «Отправить отчёт». Так что для нас это было просто кошмаром. Даже пришлось вырезать crash-сигнатуру из системы отправки отчётов, чтобы не расстраивать пользователей сообщениями о падениях.

В конце концов, нам удалось убедить Apple исправить этот баг, и начиная с Mac OS 10.11 он нас больше не донимает.

a637602bef1c44a1877f77c0fec0d900.jpg

Не все драйверы одинаково полезны


Другой типичный пример влияния окружения на работу наших продуктов — падения чужих драйверов. В частности, у нас есть поддержка 3D в Linux — OpenGL, а в Windows — DirectX и OpenGL. И если драйверы nVidia работают достаточно стабильно, то для драйверов Intel характерно падать по любому чиху. А это приводит к самым плачевным последствиям, включая падения приложения, перезагрузку ОС и используемых программ. Естественно, с потерей данных.

Например, человек запустил ресурсоёмкую программу. Скажем, игру на Mac OS. Она начинает по максимуму использовать память, процессор, видеокарту. А что творится в 3D-драйверах, известно одним лишь авторам этих самых драйверов. Пользователь поиграл в игру, драйверы не освободили какой-нибудь буфер или поменяли какую-то настройку в системе. И после этого, или во время этого, человек запускает наш продукт, которому тоже нужны ресурсы от видеокарты, и немало — ведь это эмулятор компьютера. Он начинает активно использовать 3D графику, и в результате, из-за ошибок в маковских драйверах видеокарты — падает.

BSOD forever


Также нельзя забывать, что в самой Windows тоже есть ошибки, которые могут влиять на стабильность наших продуктов. Например, вы спокойно себе работаете, и вдруг Windows перезагрузилась. В чём дело? А там произошло то же самое падение, или исключение, или обращение к несуществующей памяти. Но наша программа не может молча перезагрузиться. Ей надо что-то сказать пользователю. Она и выдаёт ошибку. А мы потом эти ошибки собираем и анализируем.

dbc861126dd5431db7802913ffe903c7.png
89ddb5c075a04b15b729e8411f16c0f7.png

Большинство из них — одиночные, но мы их даже не рассматриваем, так как, по опыту, эти проблемы никак не связаны с нашей программой и починить мы их не сможем. Более того, такой ошибки больше у пользователя не случится. Мы в первую очередь обращаем внимание на самые часто повторяющиеся баги в отчёте.

На тестовых стендах мы никогда не смогли бы предусмотреть конкретную комбинацию факторов, ведь вариативность программного окружения у пользователей бесконечна. Основная трудность в том, что внутри наших продуктов запускаются чужие программы. К примеру, внутри Parallels Desktop выполняется Windows, внутри которой крутится ещё уйма приложений. И охватить тестами все комбинации просто невозможно.

А ведь и в Windows и сторонних программах также есть баги. При разборе таких проблем мы пытаемся сначала найти такую программу и запустить ее на реальном компьютере, чтобы проверить как она на самом деле работает. Но, к сожалению, у пользователей нашего продукта, зачастую, очень специфический и, скажем прямо, не бесплатный софт, что накладывает на нас некоторые ограничения.

Непредсказуемый Qt


Другой распространённый источник сбоев — фреймворк Qt. Мы используем его для разработки наших продуктов. Это сложилось исторически, так как у нас был Parallels Desktop под под Linux, Windows и Mac, — поэтому нам пришлось выбрать Qt в качестве фреймворка для разработки. По-хорошему, если что-то работает, то не надо это менять. Но мы всё-таки прогрессивная компания, нам нравится использовать прогрессивные технологии. Поэтому мы всегда обновляем наш Qt. У нас были версии 3.0, 3.2, 4.0, 4.2, 4.5, 4.8, 5.2, 5.5. Но дело в том, что у Qt изменение второй циферки — это, практически всегда, катастрофа. Если у всех программ это major update, а третья цифра — фикс, то у нашего фреймворка это иногда можно сравнить с первой цифрой изменений. То есть разница между 5.0 и 5.5 разительная. Авторы выкидывают целые классы, рефакторят огромное количество компонентов, переходят на новое API. Но новый код не бывает без ошибок. И мы регулярно сталкиваемся с тем, что наши продукты падают из-за Qt.

В какой-то момент наше терпение лопнуло. Мы выкачали к себе в репозиторий весь исходный код Qt и начали делать для него локальные патчи, не внося их в основной транк. У нас их набралось около 250, причём они решали достаточно серьёзные проблемы с неэффективностью или с некорректной работой кода. А с недавнего времени, перейдя на очередную версию, мы начали вносить патчи уже в транк Qt.

Простой пример того, как влияет код фреймворка. В каких-то ситуациях на пользовательских компьютерах наши приложения безбожно тормозили. У нас же всё работало прекрасно. Оказалось, что при сборке нашего продукта используется сетевой компонент Qt. Мы его не задействуем, но в библиотеке он есть. И это каким-то образом влияет на работу всего фреймворка. Стоило его выкинуть, как тормоза тут же исчезли.

Напоследок вспомнился забавный случай. Разбирая отчеты, мы заметили, что у одного пользователя постоянно падает наше приложение. А падает потому, что пиратское и криво сломанное. Написали письмо: «Извините, пожалуйста, мы из Parallels. Хотим помочь. У вас продукт не совсем честный, вот и падает!». Девушка извинилась, сказала, что приложение поставил её друг, и уже минут через 10 оплатила покупку. С тех пор от неё ни одного отчёта о проблемах.

Комментарии (1)

  • 12 декабря 2016 в 11:54

    0

    Не понял про совместимость Qt. Например у нас в конторе проекты без ошибок собираются и работают под Qt 4.7, 4.8, 5.2, 5.6, и более чем уверен что со всеми промежуточными версиями от 4.7 до 5.8 тоже будет все хорошо.
    Про 5.0: я бы воздержался его сравнивать вообще с чем-то. Т.к. это переходный период Qt. Смена компании и смена самой концепции в некоторых моментах не может проходит гладко и чисто.
    Очень напоминает высказывание «плохому танцору штаны мешают»

© Habrahabr.ru