Повторить неповторимое |
05.09.2016 11:26 |
Автор: Джонатан Кол (Jonatan Kohl) Оригинал статьи: http://www.kohl.ca/articles/unrepeatablebug.pdf Перевод: Ольга Алифанова Когда я только начинал работать в компании, разрабатывающей ПО, я столкнулся с крашем приложения. Попытавшись воспроизвести краш, повторив шаги, которые привели к нему в первый раз, я потерпел неудачу. Я сделал скриншот, сохранил лог ошибок и спросил коллег, известна ли им эта проблема. Они ответили, что это "невоспроизводимый баг", который всем им хорошо знаком – каждый хоть раз да сталкивался с ним. После обеда я трудился над этим багом несколько часов, и в конце концов вынужден был признать свое поражение – баг не воспроизводился. Команда прочитала мантру, часто используемую в таких ситуациях – "Не можем воспроизвести – не можем исправить". Без стабильных шагов воспроизведения мое сообщение о баге было гласом вопиющего в пустыне. Когда выяснилось, что этот плавающий невоспроизводимый баг вызывает проблемы у наших пользователей, команда решила разобраться в нем. Когда я поймал его повторно, я объединился с программистом и наблюдал за тем, как он пытается разъяснить проблему. Первое, что я заметил – его совершенно не интересовали шаги, которые привели к падению. Он рассматривал приложение в целом, представляя себе систему и взаимодействия внутри нее. Я попросил его рассказать, о чем он думает, показать, какая информация из трейсов привлекла его внимание, и что именно он сделал с кодом, чтобы собрать больше информации о баге, когда он появится вновь. В итоге мы наконец смогли найти стабильные шаги воспроизведения, но не посредством интерфейса. На уровне интерфейса баг воспроизводился не всегда, и на убеждение команды в том, что мы локализовали проблему, ушло некоторое время. Мы потратили его на поиск доказательств, мы слушали свою интуицию и проверяли различные теории. Когда мы почувствовали, что абсолютно уверены – мы презентовали нашу находку коллегам. Нам разрешили исправить баг, и позднее мы были очень рады узнать, что пользователи больше не сталкиваются с этой спорадической проблемой, которая мешает им жить. Так называемые "невоспроизводимые" баги всегда тревожили меня – особенно выражавшиеся в падениях, повреждении данных, и утечках памяти. Проблема, "плавающая" на тест-стенде, зачастую отлично воспроизводится у пользователя. Когда я только начинал свою карьеру в тестировании, я копался в невоспроизводимых багах в свободное от релизов время. Благодаря удаче и упрямству я выяснил, что зачастую они вполне воспроизводимы. С тех пор я оттачиваю свое мастерство, пытаясь найти шаги воспроизведения для "невоспроизводимых" серьезных багов. Поиск шагов воспроизведения Универсального способа воспроизвести невоспроизводимое не существует, эта задача требует комбинации разных подходов. Если вы нашли серьезный невоспроизводимый баг, продолжайте собирать информацию о нем, занимаясь другими задачами. Увидели баг – сохраните все то, что вы о нем знаете. Создайте специальную папку и складывайте туда трейсы, скриншоты, заметки и что угодно еще, что может иметь отношение к этой проблеме. Периодически просматривайте эту папку и хранящиеся в ней данные – тогда вся нужная информация будет у вас под рукой, когда вы подключите разработчиков к работе над этой категорией проблем. Зачастую они быстрее распознают закономерности и найдут зацепки, на которые вы бы не обратили внимания. Поищите похожие баги в трекере в свободное время. Как-то раз я заметил, что у нескольких плавающих багов в нашем трекере одинаковые трейсы. Расследование показало, что все баги были вызваны одной и той же проблемой. Не концентрируйтесь на деталях, ищите закономерности. Зачастую куда важнее посмотреть на картину в целом, а не на конкретные шаги, которые привели к проблеме. Ищите паттерны, сравнивайте различные случаи воспроизведения бага. Беседуя с коллегами, задавайте вопросы и ищите закономерности в ответах. Если вам пришла в голову мысль о возможной закономерности, спросите, не наблюдал ли кто чего-то подобного. Возможно, в баг-репорте нет какой-то информации, которая просто не показалась автору значимой. Как-то раз я обнаружил закономерность в нетипично долгой задержке между двумя действиями. Эта идея пришла мне в голову, когда я общался с другим тестировщиком, и я спросил его, сколько времени прошло между одним действием и другим. Он точно не помнил, и я решил проверить свою теорию, пройдя по шагам с секундомером в руке. В результате я обнаружил, что баг стабильно воспроизводился, если между двумя действиями прошло определенное время. В итоге мы получили стабильный паттерн, с которым уже можно было работать, и разработчики смогли воспроизвести баг и найти его первопричину. Помните о том, что не всегда разумно пытаться воспроизводить баги на уровне интерфейса. Множество невоспроизводимых багов вызваны условиями, закопанными глубоко в код, или работой сторонних приложений, которые используются вашей программой. Проблемное условие в коде срабатывает на бэкэнде, и пока вы развлекаетесь с GUI, оно тихо ждет своего часа. В ряде случаев баг можно стабильно воспроизвести при помощи интерфейса, отличного от пользовательского. К примеру, данные в веб-приложении меняются на уровне GUI, но не всегда обновляются в базе данных. Вы сходу не поймете, что что-то не так, а позднее кто-нибудь попытается взаимодействовать с неверно обновленными данными и вызовет "плавающий" краш. Если вы тестируете, не ограничиваясь GUI, вам будет намного легче понять, что на самом деле происходит с данными. Используйте инструменты автоматизации, они помогут вам отследить невоспроизводимые баги. Автотесты могут быстро симулировать условия, которые тяжело создать вручную. Быстрый запуск определенных проверок при помощи инструментов позволит чаще воспроизводить плавающую проблему - создайте специальный тест-скрипт для сценария, который, по всей видимости, вызывает баг чаще, чем прочие. Доверяйте своей интуиции Проверяйте свои идеи, мыслите креативно, пробуйте нетривиальные методы и способы. Джастин Домши, аналитик настройки веб-серверов, говорит, что научился пробовать все на свете в попытках исправить проблему, потому что иногда верными оказываются самые странно звучащие решения. Все мы сталкивались с падением веб-приложений, связанным с внешними драйверами баз данных и отказами стороннего ПО. Как-то раз проблему решило удаление совершенно не относящегося к делу приложения с сервера – ошибки веб-приложения прекратились. Переустановка выявила, что проблему вызывал определенный драйвер базы данных. Нашли шаги воспроизведения? Не удивляйтесь, если сходу вам никто не поверит. Такие баги плохо вписываются в традиционный цикл разработки, и люди могут непредсказуемо среагировать на них. Будьте дипломатичны и вежливы, и продолжайте собирать информацию. Расследуя баг, очень важно сотрудничать с коллегами – как минимум потому, что ваши помощники будут вашими союзниками в убеждении всех остальных, что шаги воспроизведения найдены. Разработчики помогут вам распознать закономерности и причины, их вызывающие, и подскажут другие интерфейсы, которые стоит проверить, чтобы воспроизвести баг. Создайте каталог багов и причин, их вызывающих – это поможет вам, если вы обнаружите похожую проблему. Изучите слабые места использующегося в вашей компании языка программирования. Я, к примеру, потратил много времени на исследование проблем с указателями в приложениях, написанных на С или С++. Выясните, какое стороннее ПО установлено в системе. Узнайте, на какие серверы, драйверы, API опирается ваше приложение. Зачастую невоспроизводимые баги вызваны именно сторонними инструментами. Неплохой идеей будет создание модели вашего приложения с целью выявить потенциальные слабые места. Будьте скромны, вежливы, уважайте чужие решения. Затраты на исправление мелких невоспроизводимых багов могут перевесить выгоду от их исчезновения. Но не отчаивайтесь, если вы убеждены, что команда отмахивается от критического бага в силу его невоспроизводимости. Помните, нет такого понятия, как невоспроизводимый баг. Стойте на своем и пробуйте подойти к этому багу иначе. |