Что такое плавающая ошибка

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

Рассказываем, что это за ошибки, откуда они берутся и что с ними делать.

Что такое плавающая ошибка

Плавающая ошибка — это такая ошибка, которая:

  • не выявляется стандартными тестами;
  • проявляется время от времени и всегда непредсказуемым образом;
  • не повторяется, если второй раз сделать всё то же самое.

В англоязычной среде такие ошибки называют «гейзенбагами» (heisenbug). Эта игра слов происходит от принципа неопределённости Гейзенберга (или Хайзенберга) из квантовой механики, когда ошибка как бы есть, но её как бы нет.

Откуда берутся плавающие ошибки

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

Из-за влажности воздуха какие-то контакты в штекерах могут то пропускать, то не пропускать сигналы.

Могут влиять временные файлы программы — как на диске, так и в оперативной памяти. Иногда бывает так, что при создании временных файлов могут использоваться области, с которыми уже работают другие переменные или функции.

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

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

Как найти такую ошибку

Для обнаружения плавающих ошибок нужны особые методы тестирования и отладки, например:

  • использовать дополнительные инструменты мониторинга, 
  • создавать сложные сценарии тестирования, 
  • искусственно создавать нестабильную среду,
  • собирать логи каждого шага работы программы

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

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

Как описать плавающую ошибку

Чем лучше описана ошибка, тем проще тестировщикам её найти. Это значит, что как только плавающая ошибка проявилась, нужно собрать как можно больше данных о ней, например:

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

Чем больше данных — тем проще тестировщикам понять, что происходит, и исправить это.

Могут выяснить, что ошибка возникает после какого-то раза запуска программы; в какие-то дни недели; в какие-то числа месяца; когда программой пользуется определённый человек или на определённом компьютере. Вариантов бесконечно много. 

Ошибка при работе с плавающей точкой — это оно?

Нет. 

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

Ошибки при работе с плавающей точкой обычно связаны с неправильным округлением чисел, а не с тем, что эта ошибка проявляется время от времени.

Вёрстка:

Кирилл Климентьев

Ловить ошибки – основная задача тестировщика, но бывают ситуации, когда ошибка зафиксирована, а повторить ее не получается. Загадочное поведение программы, которое невозможно воспроизвести или зафиксировать – одно из самых сложных явлений в работе инженеров по QA.

Обнаружить, поймать и превратить в обычный – схема охоты на плавающий баг. Говорят, будто плавающие баги есть в любой программе, просто некоторые из них еще ни разу не проявились.

Что такое плавающий баг?

Нежелательное поведение программы, которое возникает спонтанно и непредсказуемо, называют плавающим багом или гейзенбагом с отсылкой к немецкому физику Вернеру Карлу Гейзенбергу – автору принципа неопределенности из квантовой физики.

Вернер Гейзенберг говорил, что «чем более пристально вы глядите на один предмет, тем меньше внимания вы уделяете чему-то еще».

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

Самые интересные случаи из практики тестировщиков чаще всего связаны именно с этим типом багов, т.е. с загадочными проблемами, которыми не станут заниматься разработчики, пока не будут понятны шаги воспроизведения. Определить, где они «живут» – задача специалистов по QA. В тоже время не всякое неустойчивое поведение равно плавающему багу. Например, неопределенность результатов при броске игральных костей не несет в себе угрозы и не является гейзенбагом.

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

🐛 Что такое гейзенбаг и как с ним бороться?

Как работать с плавающими багами?

Для избавления от плавающих багов используется традиционный принцип «повторить и разобрать», но с некоторыми оговорками:

  1. Как проверить, что перед вами плавающий баг, а не обычный? Во втором случае вы понимаете, откуда взялась проблема, а в первом – нет. Именно поэтому внимательность и способность ничего не упускать – одно из главных достоинств тестировщика. Самое смешное, неисправленный плавающий и исправленный обычный баги очень похожи – они не воспроизводятся, но плавающий баг может в любой момент вернуться.
  2. Чем выше тестируемость продукта, тем легче найти в нем плавающий баг.
  3. Любая произошедшая по непонятным причинам ошибка может вернуться. «Прошло само» не работает. Код – это четкая структура, поэтому умение локализовать баги важно развивать. Этот навык пригодится, когда ошибка будет воспроизведена, но как – непонятно.
  4. Плавающие баги могут легко воспроизводиться в продуктивной среде и плохо проявляться или вовсе не проявляться в тестовой. Это важно учитывать и соотносить с процессом релиза системы.
  5. В появлении плавающих ошибок может быть виноват целый комплекс причин, поэтому при тестировании используйте таблицы со множеством вариантов. Иногда простой перебор сочетаний различных условий приводит к успеху.
  6. Никогда не пытайтесь скрыть плавающий баг от заказчиков и пользователей. В будущем это может привести к еще большим проблемам.

Яркий пример того, как попытка Intel скрыть ошибку привела к убыткам:

В выпускавшихся Intel в 1994 году процессорах Pentium была проблема с некорректным делением чисел с плавающей запятой. В компании посчитали, что дефект может повлиять на работу очень узкого круга пользователей, и решили его скрыть. Возникший в обществе резонанс заставил Intel изменить позицию и принес убытков на $475 млн.

Как локализовать ошибку, если первичный анализ ничего не дал?

  • Обратите внимание на межфункциональные и межсистемные блоки. Ошибки часто живут на границах.
  • Изучайте логи и трассировки.
  • Создавайте аналогичных тестовых пользователей с одинаковыми правами и полномочиями, проверяйте работу программы на них.
  • Попробуйте тест на других машинах с аналогичными и отличающимися характеристиками.
  • Исследуйте от частного к общему всю среду, в которой работает программа, и наоборот, попробуйте пойти от ошибки. Какие условия могут быть важны для ее проявления?

🐛 Что такое гейзенбаг и как с ним бороться?

Почему возникают плавающие баги?

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

Вот примерный список причин, который поможет в случае, если вдохновение вас покинуло:

  1. Переполнение. Какое-либо поле или контейнер могут переполняться и провоцировать сбой при корректной работе связанных с ним функций. В эпоху больших запасов памяти тестировщики часто упускают это из вида. Например, внутри системы могут считаться огромные суммарные значения, и она окажется не способна переварить такое количество символов.
  2. Проблема кода, которую также называют «Проблемой ТЗ». Зачастую плавающий баг связан с тем, как написан код (мы не рассматриваем сейчас некачественную работу, только непредсказуемую). Например, составителю технического задания на разработку очевидно, что при выборке данных нужно взять некий уникальный объект, но разработчик этого знать не может и прописывает свободный выбор. Бывает, что код написан верно, но какое-то сочетание условий приводит не к поломке, а к подмене функций. В этом месте не будет ошибки, но будет неверная работа программы в целом.
  3. Проблемы ввода. Например, в поле свободного ввода пользователь внес непредусмотренные алгоритмом данные, либо ошибочный символ (запятую вместо точки и т.д.). Сюда же относятся ошибки, связанные с использованием клавиатуры вместо мыши или ошибки призрачного ввода, когда данные вносит машина (особенно где-то в середине расчетов). В таких случаях проблему можно обнаружить, проставляя контрольные «стопы» и проверяя работу кода по частям. Еще один вариант – дефектный ввод, когда данные клиент-серверных приложений повреждены или переданы с ошибкой.
  4. Проблемы оборудования возникают, когда ошибки связаны с физическими факторами. Например, из-за перебоев с электропитанием, высоких температур в серверной, физических повреждений компьютера и т.д.
  5. Случайности. Некая комбинация условий может сработать корректно, но впоследствии привести к ошибке.
  6. Deus Ex Machina. Эти проблемы возникают, когда одновременно с вами кто-то еще использует приложение: разработчик, хакер или другой тестировщик.
  7. Неочевидные моменты. При анализе специалисты часто отбрасывают ненужное, чтобы сосредоточиться на важном, а оказывается, что проблема возникает из-за отброшенных ранее вариантов.
  8. Неизвестное. Невозможно учесть все. Например, в системе может быть функция, о которой тестировщику неизвестно, или некие источники искажений. Внутри приложения могут создаваться незадокументированные переменные и т.д. и т.п.

Еще несколько советов по работе с плавающими багами:

  • Всегда проверяйте базу. Характеристики компьютера, что тестируете, исходные данные в документах и по факту.
  • Всегда проверяйте информацию со стороны. Не задавайте вопросы в чате пользователю или коллеге, лучше сходите и посмотрите сами.
  • Если кажется, что все уже проверено от и до, причем несколько раз, попросите коллег посмотреть. Без вас и ваших рассказов, с минимумом вводных.
  • Поищите похожие кейсы и посмотрите, как решались такие вопросы раньше.
  • Сохраняйте все логи. Возможно вам придется сравнивать не только исходный и последний, а еще и промежуточные.
  • Проверяйте то, что на первый взгляд не имеет значения. Даже если вам кажется, что это вообще не относится к вопросу. Часто именно оно оказывается искомым.
  • Проверяйте конфликты на границах разных модулей и систем, особенно если интеграция происходит между продуктами разных разработчиков.
  • Если используете сторонние компоненты, обратитесь в техподдержку разработчика.
  • Если нет никакой информации, ничего не помогает, а ошибка по прежнему не найдена, дайте проблеме отстояться. Вернитесь к ней завтра, а сегодня переключите внимание на другие задачи.
  • Не отчаивайтесь. Ищите инструменты, которые помогут решить вопрос – однажды вы обязательно их найдете.
  • Соотнесите пользу от устранения бага и потраченные на это усилия. Иногда достаточно знать о наличии проблемы: это не баг, это фича.

***

Невыявленные ошибки могут приводить к опасным последствиям. В 1962 году космический аппарат Mariner должен был направиться к Венере, но сломалась антенна и он перешел на автопилот, полетев не туда. В итоге аппарат пришлось взорвать над Атлантическим океаном, а произошло это из-за пропущенного при программировании системы навигации в одной из формул символа. Большинство багов не настолько фатальны, да и системы поиска ошибок стали надежнее, но стремительный рост информационных технологий приводит и к росту сложности систем. Найти в них даже обычные ошибки становится все труднее, а количество плавающих багов увеличивается. Их устранение – уже не начальный уровень в работе тестировщика, но тем интереснее решать подобные задачи. Удачи вам в обучении!

«Плавающие» ошибки в проектах. Как поставить задачу так, чтобы их избежать и не прослыть придирой и формалистом

Время на прочтение
5 мин

Количество просмотров 2K

В данной статье рассматривается ситуация, типичная для проектов, в которых странным образом возникают одни и те же ошибки. И никто не понимает как так получается. Или делает вид, что не понимает…

Это плавающие ошибки

Это плавающие ошибки

Если ты владелец IT-продукта и болеешь за свое дело, то без качественных технических заданий не обойтись. В больших нетиповых проектах постановка и формирование ТЗ становится нетривиальной. Нужно описать много условий, ветвлений и прочих сложных логических конструкций, которые «с наскоку» не реализовать, ведь на бумаге это выглядит лишь как набор абстракций. А так уж устроен наш мозг, что ему нужна конкретика и образы, а не полотна с текстом!

Взять, например, разработку фриланс-портала. У проекта обычно несколько статусов. Всякий статус доступен для пользователей с разными ролями, у каждой роли есть набор атрибутов и свойств, характерных только для этого статуса и этой роли. А еще есть дополнительные, вроде бы, автономные сущности такие как «Переписка», «Оплата», «Отзывы». Они вроде бы самостоятельные, но, так или иначе, перекликаются со статусами и ролями. Все это при пересечении дает очень большой набор вариантов, который нужно запрограммировать.

Возникает вопрос, как подать информацию специалисту, чтобы она была действительно понятна и непротиворечива, и, желательно, наглядна?

Есть всего два возможных базовых варианта. Остальное — их комбинации.

Вариант 1. Подумать и сформулировать набор правил для каждой сущности. Например, берем сущность «Переписка» и формулируем правила по ее доступности. Это может выглядеть следующим образом: 

Если между специалистом и заказчиком была переписка, то она блокируется при следующих условиях:

a.      Проект получает статус «Заблокирован»

b.      Проект получает признак «Снят с публикации»

c.       Проект получает статус «Закрыт» (полное закрытие)

d.      Специалист отказался от выполнения проекта на этапе поиска исполнителя

На данном этапе важно, чтобы правилом покрывались все возможные варианты событий. Если этого не произойдет, а программист не подумает самостоятельно (или не задаст вам вопросы), то вы можете получить достаточно неприятные сюрпризы на этапе приемки проекта. 

Кстати, как вы думаете, какой сюрприз (явно ненужный нам) можно получить по этому правилу? Напишите в комментариях, если заметите!

Когда вы формулируете такие правила важно донести до специалистов необходимость в их критичном восприятии! Если на этапе реализации они смогут увидеть несовершенства в формулировках, то должны дать вам немедленную обратную связь, чтобы уточнить правило.

Лайфхак: это лучше зафиксировать в проектной документации в качестве принципа работы!

Таким образом, ваше ТЗ будет состоять из описаний наборов правил, реализовав которые вы должны получить красиво-работающий продукт.

Но что, если вы не смогли чего-то учесть?

Тут на помощь приходит второй вариант постановки задачи…

Вариант 2. Рассмотреть все частные случаи разрабатываемого процесса, разложив его на максимально подробные составляющие. Здесь проблема состоит в том, что процесс в сложных системах может быть настолько большим, что представить его полным набором мелких составляющих, мягко говоря, затруднительно. А, порой, и вовсе невозможно. 

Вот вам абстрактный пример. У нас есть:

  • 3 состояния проекта S = (S1, S2, S3)

  • 3 роли R = (R1, R2, R3)

  • и три атрибута А = (А1, А2, А3), которые зависят от того, как пересекаются S и R.

По каким-то причинам нам трудно сформулировать общие правила, по которым мы должны запрограммировать систему. Поэтому мы просто должны описать все возможные пересечения этих комбинаций. 

Например, мы подумали, и у нас получилось так: 

S1 + R1 = А1

S1 + R2 = А2

S1 + R3 = А3

S2 + R1 = А1

S2 + R2 = А2

S2 + R3 = А3

S3 + R1 = А1

S3 + R2 = А2

S3 + R3 = А3 

Таким образом, пересечение двух небольших множеств, состоящих всего из трех объектов дало нам выборку из 9 вариантов! 

А если множество статусов S получит еще статус S4? Сколько будет вариантов? Уже 12!

А если размеры обоих множеств станут равны 4-м? Тогда вариантов будет 16!

Это я еще не привел пример, когда нам нужно пересечь 3 множества или больше!

К чему это я? К тому, что очень легко при таком подходе запутаться. А уж как сильно демотивируют программистов такие простыни описаний и как сильно взлетает стоимость проектов от этого – я скромно умалчиваю.

Неполная карта частных случаев из одного фриланс-проекта

Неполная карта частных случаев из одного фриланс-проекта

Применимость на практике и «плавающие» ошибки?

Мы рассмотрели два способа подачи информации для ТЗ в сложных проектах. Я считаю, что у обоих способов есть свои преимущества и недостатки.

Способ постановки задачи обобщенными правилами приближен к тому, как закладывают логику в свои решения программисты, но требует от нас предварительно проделать достаточно большой объем аналитической работы. Если эта работа проделана должным образом, то второй способ может и не понадобится.

Кстати, бывают случаи, когда правило видоизменяется по ходу проекта, например, если мы что-то не учли изначально или в проекте появляются новые вводные. Такое бывает по невнимательности или по Agile:)

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

Этот способ позволяет зафиксировать уже работающие варианты решения, а также неработающие (или содержащие ошибки). Это особенно полезно, если возникают так называемые «плавающие» ошибки. Плавающая ошибка очень неприятна тем, что как бы исправив ее в одном частном случае, ошибка вылезает в другом частном случае.

Другими словами это, когда:

  • после проверки было: S1 + R1 = А2 (неправильно), а S1 + R2 = А2 (правильно)

  • после исправления стало: S1 + R1 = А1 (правильно), а S1 + R2 = А1 (неправильно)

Таким образом, наша ошибка уплыла из случая S1 + R1, но приплыла в случай S1 + R2.

У некоторых программистов плавающие ошибки порождают иллюзию, что руководитель проекта придирается к реализации и «придумывает на ходу» новые вводные. В то время как виной всему на самом деле неправильно заданные правила, вызывающие миграцию багов из одного частного случая в другой.

Для руководителя проекта такие ошибки — страшный сон, ведь по мере столкновения с ними, возникает перспектива повторного тестирования всего проекта! В то же время программист просто меняет условие в коде и ждет реакции.

Мой совет руководителям: фиксируйте состояние системы в частных случаях, чтобы показать, что где-то в коде заданы неверные логические условия, которые заставляют нашу ошибку переплывать с места на место.

При таком подходе снять с себя ответственность уже не получится, а это уже прямое указание на чью-то возможную некомпетентность или лень!

Понимаю, что вам, как руководителю, конечно, очень муторно описывать эти случаи и следить за ними. Частично или полностью эту задачу можно (и нужно!) поручить тестировщикам, но т.к. ответственность за проект несете вы — возможно именно вам придется в этом разобраться.

К сожалению квалификация некоторых тестировщиков или масштабы ветвлений все равно не позволят нам описать все частные случаи, которые могут встретиться на практике. Так что здесь целесообразен только реальный пилотный запуск с постоянным мониторингом обратной связи от пользователей и латание дыр «на живую». Иначе проект вы рискуете так никогда и не запустить.

Буду рад, если вы поделитесь в комментариях своим опытом борьбы с плавающими ошибками! Как решали подобные ситуации? Были ли конфликты на этой почве?


Автор и ведущий персонального блога «ПРО-продукт» https://t.me/productmaster

Петя вспоминает, что как-то уже встречал эту ошибку, но она ни разу не повторилась. Он, разумеется, сразу же перепроверяет все кейсы, связанные с сообщениями пользователей, но у него всё точно по ТЗ и никаких ошибок.

Так Петя встретил свой первый плавающий баг.

Давайте подробнее рассмотрим, что же это за баги такие и где они плавают.
Для начала нужно узнать, что такое плавающий баг.

ПЛАВАЮЩИЙ БАГ – это ошибка, которая в одних и тех же условиях то воспроизводится, то нет.

Однако важно понимать, что любая ошибка, даже плавающая, имеет причины появления. И поиск причины – самое сложное в охоте на плавающий баг.

Основные ошибки при охоте

Какие ошибки может допустить Петя при охоте на свой первый плавающий баг?

1. Ринуться с головой в выяснение причин.
Так делать не стоит. Важно сразу понять, насколько ошибка критична, и, уже отталкиваясь от этого, действовать или…

Или оставить всё как есть. Потому что поиск плавающих багов – это всегда большие затраты времени не только QA отдела, но и отдела разработки.

Также не стоит паниковать: баги не вызваны злыми духами и в каждом проекте их в избытке. Просто большинство себя либо не проявило, либо не было замечено.

Также важно удостовериться, что баг действительно плавающий. Будет весьма глупо потратить много часов своей (и вдобавок чужой) работы на отлов ошибки, фикс которой вы пропустили.

Также стоит убедиться, что ошибка является так называемым тестировщиками “лотерейным” багом, то есть багом, всплывающим из-за выпадения какого-то рандома в проверяемом ПО.

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

Как охотиться?

А дальше есть множество способов работы, которые можно применять и каждый из них по-своему хорош:

1) Подключите к процессу стороннего человека, а лучше нескольких. Свежий взгляд часто замечает то, что вашему замыленному взгляду кажется несущественным.

2) Ищите инструменты, которые помогут вам точнее отслеживать проблему. Например, логи проекта (технические сообщения от программы, падающие в консоль или её аналог) позволят вам не ломать голову над тем, как же воспроизвести только что сломанное ПО. А вместо этого сразу отдать разработчику то, что укажет, что именно сломалось под капотом программы.

3) Налаживайте коммуникацию с пользователями. Спрашивайте детали у тех, кому не повезло столкнуться с плавающей ошибкой. Возможно, именно их помощь будет ключевой. Но не будьте излишне уверены в чужих словах.

4) Поищите в списке багов похожие проблемы. Иногда информация о похожих багах помогает в исправлении.

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

6) Провести стресс-тесты. Возможно, ошибка случилась из-за чрезмерной нагрузки.

7) Поговорите с разработчиками о том, чтобы поставить “ловушку” (функцию в программе, сообщающую о том, что что-то не так), которая даст необходимую информацию.

8) Если ничего не помогает, то дайте проблеме отлежаться. Может, она решится сама собой, а может, вы найдете необходимую информацию.

_______
Пост написан совместно с одним из наших преподавателей (Андрей Высоцкий).
В следующем посте рассмотрим, как на практике происходит поиск плавающих багов и поговорим про ошибке, которые допускаются при их поиске.

Сложный код, плавающие баги и инсайт

// 7 февраля, 2011 // Doctrine, PHP, Веб-разработка

Мы три дня ловили баг. Есть такая противная категория ошибок — плавающие баги.  Гейзенбаг (англ. Heisenbug) — термин, используемый в программировании для описания программной ошибки, которая исчезает или меняет свои свойства при попытке её обнаружения. Это слово, в отличие от слова «баг», в русском языке практически не используется. Не полностью идентичный, но достаточно близкий по значению русскоязычный термин — «плавающая ошибка». Примером могут являться ошибки, которые проявляются в окончательном варианте программы (релизе), однако не видны в режиме отладки, или ошибки синхронизации в многопоточном приложении.

Обычно при отладке такого бага, очень трудно его локализовать, т.е. повторить, добиться его стабильного возникновения. Он то появляется, то исчезает. Программист проверяет код, и думая, что он уже отлажен делает коммит на продакшен сервер (ну или на тест-сервер). А потом тестировщик (привет Денис:) обнаруживает его, и возвращает программисту. Тикет по этому багу гуляет из «test» в «new» и обратно по многу раз. Это утомляет всех.
Как правило, при анализе ошибок такого типа, приходится полностью перебирать движок, предлагаются самые неимоверные варианты, по дороге находится и исправляется куча других багов, но этот восстает аки Феникс. Тогда для меня становится делом чести прищучить его. Люблю сложные задачки 🙂

Эта ошибка состояла в том, что периодически на одной странице веб-приложения отключался автозагрузчик классов. До этого он работал, везде он работал, а на одной странице брал и отрубался. Через раз. Иногда мог по 6 раз работать, а потом выключиться. Мы начали грешить на кэширование — отключили. Опкод кэшер — тоже выключили. Потом при ручном отключении конкретных подсистем кэша, всё было нормально, начали включать по одной, всё работало. Включили все — работает. А не должно бы. Тикет пошел в «test», но потом вернулся обратно. «Опять !@#$!@$ глючит» — сказал нам тестировщик. Мы долго думали.

Были сделаны самые невероятные предположения — операционная система, броузер, броузер и операционная система, время суток, погода, дайте нам хоть что-то, за что можно зацепиться! Но нет. Вечер пятницы, а ошибка, так и не исправлена. Посудив, что утро вечера мудренее, мы отправились отдыхать. Благо в субботу у нас намечался корпоратив, во время которого мы славно отдохнули, проветрив мозги.

Иногда бывает так, что ты усиленно думаешь над проблемой, а она не решается. Магии в PHP нет. Есть логика. Как говорил один мой преподаватель — «машина она железная, чего ей скажешь — то она и делает». Так что надо искать условия, проверять, думать.

У меня есть «правило Ч«, которому научила военка. Например, я всегда жду людей строго определённое время (которое конечно зависит от отстоятельств). Это избавляет от терзаний вида, «ну подожду ещё 5 минуточек, может придёт». Время вышло, я ущёл. Тоже и с кодингом, нельзя биться головой в стену, есть определённое время на решение проблемы, если оно истекло — значит что-то не так, значит неправильно действуешь.

Когда бьешься долго над такими типами ошибок, пытаешься представить себя машиной, интерпретатором, пропуская через свой разум код программы, вспоминаешь связи между кусками кода, модулями и классами, моделями и видами, контроллерами и действиями. Ты загружаешь программу в своё сознание. Не задумывались об этом? Ошибка не решается, вы идёте гулять/курить/в магазин/гости/бассейн/проветриться и перестаете думать над этой проблемой. Она вытесняется из фокуса сознания. И тут вступает в игру подсознание. Ты вроде бы не думаешь о проблеме, но иногда на тебя словно спускается озарение, инсайт, идея, которую тут же хочется проверить, попробовать, а вдруг — это решение!

Сейчас был именно этот момент. А ведь в тексте ошибки, которую показывал PHP в путях были пути, которые выставляет утилита, а не сам движок. Тут надо сказать, что кроме большого движка веб-приложения, у нас есть несколько утилит, которые делают какую-нибудь полезную работу, они маленькие быстрые (потому что не загружают Zend Framework) и поэтому мы используем их для ряда служебных задач. НО, они совсем ничего не знают о моделях, контроллерах, видах и т.д. Они не умеют грузить модели, у них свой автозагрузчик классов. Стоп! Свой автозагрузчик. А может быть где-то в коде движка инклудятся утилита, которая грузит автозагрузчик, а он затирает пути set_include_path() к классам, которые можно грузить автоматически. Да, это оказалось так. Эврика, инсайт! За это я и люблю свою работу!

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

Что же после всего хочется сказать?

1. Не делайте ваш код сложным. Поменьше магии, нам в работе итак её хватает. Эй, помееьше магии в прямом смысле! Например, в Doctrine есть магические функции вида $model->findByUserIdOrSessionId($user_id, $session_id).  Красиво? Да, но такой функции нет. Что происходит, когда она вызывается. Происходит вызов служебной функции __call(), затем вызов класаа, поиск по массиву (практически парсинг названия функции), составление DQL-запроса, его выполнение и возврат. Сколько лишних операций, зато красиво. Что надо вам? С головой подходите к работе, делайте ваш код понятным, но не перебарщивайте с магией.
2. Просчитывайте варианты. Пытайтесь думать, как машина, смотрите по каким ветвям может пройти программа.
3. Не делайте код сложным. Упрощайте! Делайте функции с говорящими именами, длинные методы разбивайте на маленькие, используйте принцип DRY в своей работе!
4. Отдыхайте! Нашим мозгам тоже нужен отдых, отвлечься от работы очень часто бывает гораздо полезнее, чем сидеть всю ночь над кодом!

Литература

http://trenings.ru/OnLine_treningi/PsihoTrening/PsihoTrening_5-e_zanyatie._Fokus_vnimaniya.html

Спасибо!

Если вам помогла статья, или вы хотите поддержать мои исследования и блог — вот лучший способ сделать это:

Автор: Джеймс Бах (James Bach)

Оригинал статьи: http://www.satisfice.com/blog/archives/34

Перевод: Ольга Алифанова

Способность уверенно исследовать плавающие баги – одна из характеристик отличного тестировщика. Самые захватывающие истории, которые я слышал от тестировщиков, были про охоту на «белых китов» в океане сложного кода.

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

Вообще-то плавающие баги не должны вас удивлять. Все программирование, можно сказать, крутится вокруг контроля неустойчивого поведения. Итак, о чем речь?

Нас не беспокоит неустойчивое поведение, если оно а) так и задумано б) не несет в себе тайны, даже если оно не вполне предсказуемо. Например, результат подброшенной монеты или шанс выбить 777 в игровом автомате – вполне себе неустойчивое поведение. Даже загадочное неустойчивое поведение не волнует нас, если мы уверены, что оно не вызовет проблем. Когда я тестирую, я не думаю о магнитных полях или мелких скачках напряжения, хотя они влияют на мою работу постоянно.

Многие плавающие баги никем не обнаружены просто потому, что они еще ни разу не проявились (или проявились, но никто их не заметил). Все, что мы можем сделать – это позаботиться о создании наилучшего тестового покрытия и придерживаться этого подхода. Нет в мире алгоритмов для автоматического определения или предотвращения всех плавающих багов.

Итак, то, что обычно называется плавающим багом – это загадочное, нежелательное поведение системы, которое наблюдалось как минимум единожды, и которое мы не можем спровоцировать повторно.

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

Принципы работы с плавающими багами

  • Успокойтесь, они, скорее всего, не вызваны злыми духами.
  • Если это случилось один раз – скорее всего, это произойдет снова.
  • Если баг не был исправлен, вряд ли он самоликвидировался навсегда.
  • С осторожностью относитесь к исправлениям плавающих багов. Исправленный баг и неисправленный плавающий баг неотличимы друг от друга по определению в течение какого-то времени и/или при определенных условиях.
  • Любое состояние системы, переход в которое занимает длительное время в обычных обстоятельствах, может быть мгновенно достижимым в непредсказуемых ситуациях.
  • Сложное и запутанное поведение обычно спровоцировано чем-то довольно простым.
  • Сложное и запутанное поведение иногда спровоцировано целым комплексом причин.
  • Плавающие баги зачастую могут рассказать вам много интересного про ваш продукт.
  • Очень легко поддаться уверенности, что ваше предположение об источнике проблемы разумно, остроумно и имеет смысл – оно просто неверное.
  • Ключ к разгадке может находиться в руках другого человека.
  • Возможно, что баг, «плавающий» на тест-стенде, легко воспроизведется на проде.
  • Принцип Pentium 1994: плавающая техническая проблема может привести к систематическим и очень дорогостоящим проблемам бизнеса.
  • Проблема может быть плавающей, но риск, связанный с ней, стабилен.
  • Чем выше тестируемость продукта, тем легче исследовать плавающие баги.
  • Когда вы исключили все невозможное, то то, что осталось, каким бы невероятным оно ни было, уже нанесло существенный урон! Поэтому не ждите момента, когда вы полностью раскусите этот орешек, заводите плавающие баги как можно раньше!
  • Если вы не успеваете ущучить плавающий баг до релиза, сделайте все, что в ваших силах, чтобы все-таки выловить его и исправить. Получайте удовольствие от процесса, так сказать.

Общие советы по исследованию плавающих проблем

  • Перепроверьте свои базовые предположения: используете ли вы именно тот компьютер? Тестируете ли вы именно то, что нужно? Верны ли ваши наблюдения?
  • Свидетельства очевидцев могут оставить за бортом важную информацию, поэтому слушайте, но не нужно излишней уверенности в чужих словах.
  • Пригласите других наблюдателей, подключите к процессу большее количество людей.
  • Мотивируйте людей сообщать о плавающих проблемах.
  • Если вам сказали, что причина проблемы ТОЧНО не в этом, обратите на ЭТО особое внимание.
  • Проверьте сайты технической поддержки каждого из сторонних компонентов, который используется в вашем приложении. Возможно, ваша проблема там указана.
  • Ищите инструменты, которые помогут вам наблюдать за поведением системы и контролировать его.
  • Налаживайте коммуникацию с наблюдателями (особенно с реальными пользователями).
  • Соберите все загадочные баги в одном месте, чтобы легче было отслеживать закономерности.
  • Просмотрите список багов, поищите в нем похожие на плавающий баг проблемы.
  • Точнее зафиксируйте свои наблюдения, пользуйтесь инструментами.
  • Улучшите тестируемость вашего продукта, добавьте логирование и интерфейсы с поддержкой сценариев.
  • Точнее контролируйте данные, которые вы вводите (включая их последовательность, время, типы, размеры, источники, итерации, комбинации).
  • Систематически покрывайте тестами данные ввода и состояния системы.
  • Сохраняйте абсолютно все логи. Возможно, позже вам понадобится сравнить новые логи со старыми.
  • Если проблема чаще возникает в одних ситуациях и реже – в других, проведите статистический анализ разницы между закономерностями в этих ситуациях.
  • Попробуйте контролировать то, что, с вашей точки зрения, не имеет значения.
  • Упрощайте все. Попытайтесь менять одну переменную за раз, попробуйте разбить систему на части (помогает понять и изолировать проблему).
  • Усложняйте. Попытайтесь изменить несколько переменных за раз, устройте в системе бардак (помогает выловить «лотерейные» баги).
  • Добавьте элемент случайности в состояния системы и обрабатываемые данные (возможно, при помощи менее жесткого контроля), чтобы добиться состояний, которые, возможно, не вписываются в ваш обычный шаблон использования.
  • Создайте искусственный стресс (высокая нагрузка, большие объемы данных).
  • Поставьте ловушку, чтобы при возникновении проблемы в следующий раз вам удалось изучить ее получше.
  • Подумайте насчет код-ревью.
  • Поищите конфликты между компонентами, созданными разными компаниями.
  • Собирайте и храните рассказы о локализации плавающих багов.
  • Систематически размышляйте о причинах плавающих багов (см. ниже).
  • Опасайтесь потратить кучу времени на мелкий баг, всегда спрашивайте себя, стоит ли он того.
  • Если ничего не помогает, дайте проблеме отлежаться, поработайте над чем-нибудь другим и последите, не появится ли она снова.

Возможные причины плавающих багов

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

Вероятная причина номер 1: Система ведет себя точно так же, как и вела. Кажущийся сбой поведения – артефакт, относящийся к вашему восприятию.

  • Плохие наблюдения. Наблюдатель мог быть невнимательным — например, подвергнуться «Слепоте невнимания» – феномену, когда мозг занят чем-то еще, и человек не видит того, что находится у него прямо перед носом. Если показать ему то же самое еще раз, он увидит нечто новое для себя и предположит, что раньше такого не происходило. К тому же так работает ряд оптических иллюзий, демонстрируя кажущееся иным поведение при том, что ровным счетом ничего не изменилось.
  • Наблюдения, не относящиеся к делу. Наблюдатель обращает внимание на различия, которые не имеют значения. То, что важно, остается стабильным. Это случается, когда наблюдатель чересчур пристально бдит за мелочами.
  • Плохая память. Возможно, наблюдатель плохо запомнил свои впечатления, или записи, фиксирующие проблему, повреждены. Когда вы наблюдаете за чем-то, ваш мозг обрабатывает кучу данных! Он немедленно упаковывает их и пытается связать их с другими данными, при этом важная информация может потеряться. К тому же в процессе разработки и тестирования мы повторяем одно и то же довольно часто, и можем запутаться в деталях каждого отдельного наблюдения.
  • Ложная атрибуция. Наблюдатель приписывает свое наблюдение не тому, чему нужно. К примеру, «Microsoft Word упал» может означать, что упала Windows, и причина падения не имеет к Word ни малейшего отношения. Word вообще ничего не делал. Этот феномен еще называют «ложной корреляцией» и часто встречается, когда одно событие следует сразу же после другого, и кажется, что это причина и следствие. Благодаря ложной корреляции плавающие баги зачастую считаются обычными багами, появившимися из-за крайне сложного и маловероятного комплекса причин.
  • Искажение фактов. Наблюдатель, возможно, неверно передает информацию. Причин может быть множество – например, вполне невинная: он настолько уверен в своих предположениях, что передает свои наблюдения определенным образом. Как-то раз я спросил сына, подключена ли его нерабочая Playstation к сети. «Конечно», огрызнулся он. Попробовав решить проблему так и сяк, я решил, что блок питания умер. После чего посмотрел на него и обнаружил, что штекер не включен в розетку.
  • Ненадежный оракул. Мнение наблюдателя насчет того, что является проблемой, а что нет, постоянно меняется. У нас может создаться впечатление, что проблема плавающая, только потому, что некоторые люди – иногда – не считают это поведение проблемой, даже если оно вполне предсказуемое. Другие люди могут отнестись к вопросу иначе, и даже один и тот же человек может поменять свое мнение.
  • Ненадежная коммуникация. Коммуникация с наблюдателем может быть неполной. У нас создается ощущение, что мы нашли плавающий баг, потому что сообщения о нем не всегда до нас доходят, даже если проблема вполне предсказуема. Фраза «Мне кажется, проблема больше не проявляется» может означать, что люди просто перестали о ней сообщать.

Вероятная причина номер 2: Система ведет себя иначе, потому что это другая система.

  • Deus ex machina. Разработчик мог специально что-то поменять, а потом вернул все назад. Это часто случается, когда над разными частями платформы одновременно работает несколько разработчиков или команд, не координируя свои действия друг с другом. Другой вариант – злонамеренные модификации приложения хакерами.
  • Случайное изменение. Разработчик мог внести правки случайно. Возможно, незапланированные побочные эффекты и приводят к возникновению плавающих проблем. К тому же разработчик может ошибиться и выкатить правки на прод вместо тест-стенда.
  • Другая платформа. Один из компонентов платформы мог быть заменен или переконфигурирован. Администратор или пользователь могли специально или случайно изменить что-то в компоненте, от которого зависит продукт. Частый источник таких проблем – автоматические обновления Windows, изменения в конфигурации памяти и дискового пространства.
  • Проблемы железа. Может, какой-то физический компонент системы сбоит время от времени. Перебои могут быть вызваны естественными вариациями в его работе, магнитными полями, излишне высокой температурой, низким зарядом батареи, плохим обслуживанием или физическим шоком.
  • Чужая система. В работу вашего приложения может вмешаться какое-нибудь еще. Например, в веб-тестировании я могу иногда получать неверные результаты из-за прокси-сервера провайдера, который загружает кэшированную версию страницы в неподходящий момент. Другие примеры такого вмешательства – это сканирование на вирусы, обновления системы, другие программы или та же самая программа, запущенная повторно.
  • Проблемы кода. Может, проблема кроется в том, как написан код. Один из худших багов, созданных моими руками (худших в смысле тяжести поиска причины) возникал из-за кода в игре, который иногда перезаписывал данные в совершенно другой части программы. Из-за природы этих данных игра не падала — зато поврежденная функция передавала управление функции, которая следовала сразу за ней в памяти приложения. Мне понадобилось несколько дней (и эмулятор чипа), чтобы это понять.
  • Раздвоение личности. То, что вы понимаете под системой, может на самом деле состоять из нескольких систем, мимикрирующих под единую. К примеру, я могу получать разные результаты от Google в зависимости от того, на какой сервер Гугла я попадаю. Или разные компьютеры тест-команды имеют разные версии ключевого компонента, или я опечатался в URL и случайно начал тестировать на другом сервере.
  • Человеческий фактор. Возможно, за запуск части системы отвечает человек, и этот человек ведет себя по-разному.

Вероятная причина номер 3. Система ведет себя иначе, потому что находится в другом состоянии.

  • Замершее условие. Решение, которое должно основываться на статусе условия, могло перестать проверять это условие, застряв в состоянии «всегда да» или «всегда нет».
  • Неверная инициализация. Одна или несколько переменных не инициализируются. В результате стартовое состояние расчетов становится зависимым от предыдущих расчетов той же или иной функции.
  • Отказ в ресурсах. Критически важный файл, поток или другая переменная недоступны для системы. Это может произойти, потому что они не существуют, повреждены или заблокированы другим процессом.
  • Прогрессивное повреждение данных. Система могла превратиться в бардак постепенно из-за накапливающихся мелких ошибок. Например, это может проявляться как рассинхрон временных циклов, или ошибка округления при сложных или рефлексивных расчетах.
  • Прогрессивная дестабилизация. Классический пример многоэтапного отказа. Первая часть бага создает нестабильность – например, указатель массива ведет в никуда при определенных условиях, однако внешне баг никак не проявляет себя. Из-за этого невидимого сбоя система переходит ко второму этапу – к видимому сбою, который происходит позднее в комбинации с какими-то другими условиями. Увязать эти события между собой очень трудно из-за задержки между первопричиной и последствиями.
  • Переполнение. Какой-либо контейнер может переполниться, провоцируя сбой или обработку исключений. В эпоху больших объемов памяти о возможности переполнения часто забывают. Даже если исключение корректно обрабатывается, сам процесс обработки, взаимодействуя с другими функциями системы, может вызвать плавающую проблему.
  • Редко встречающиеся функции. Некоторые функции системы используются настолько редко, что мы про них забываем. Это обработка исключений, внутренняя сборка мусора, автосохранение, функции обслуживания. Когда они срабатывают, они могут неожиданно вступить в конфликт с другими функциями или условиями. Обращайте особое внимание на скрытые и автоматические функции.
  • Другой режим или настройки. Система может работать при разнообразных режимах, и пользователь установил какой-то другой. Отличия могут быть незаметны с первого взгляда.

Вероятная причина номер 4. Система ведет себя иначе, потому что получила другие вводные данные.

  • Случайный ввод. Пользвоатель мог ввести что-то или изменить ввод таким образом, что это не должно было ни на что повлиять – но все же повлияло. Это можно назвать синдромом Умного Ганса – лошади, которая периодически умудрялась решать математические задачи. В результате Оскар Пфунгст обнаружил, что лошадь реагировала на непроизвольные микродвижения своего хозяина. В своей области я как-то раз столкнулся с плавающим багом, который возникал, когда солнце проникало через мое окно и падало на оптический сенсор моей мыши. Погодные условия никак не должны были повлиять на ввод данных в приложение – однако влияли. Более распространенный пример странного поведения – баги, возникающие, когда вы используете клавиатуру, а не мышь, чтобы отдать какую-либо команду. Случайный ввод может быть невидимым глазу без специальных инструментов и рекордеров. Например, два идентичных текста в RFT-формате, один из которых сохранен через Word, а другой через Wordpad, выглядят очень похоже, но совсем не идентичны.
  • Секретные границы и условия. Программа может вести себя иначе из-за скрытых границ или областей падения, которые никем не задокументированы и которых вы не ожидаете, выстраивая свою ментальную модель продукта. Как-то раз я тестировал поиск, который вел себя совершенно иначе, если количество найденных записей равнялось тысяче или пятидесяти тысячам. Я обнаружил эти скрытые границы совершенно случайно.
  • Другой профиль использования. Использование приложений некоторыми пользователями может чем-то специфически отличаться. Их предположения насчет ввода ведут к другим результатам вывода. Пользователи с определенным опытом – например, программисты – могут систематически замечать (или не замечать) определенные типы поведения приложения.
  • Призрачный ввод. Источником ввода может быть не пользователь, а машина. Такой ввод часто незаметен пользователю, и включает вариации из-за разных файлов, различные сигналы от периферийных устройств, или данные, поступающие по сети.
  • Deus Ex Machina. Кто-то еще взаимодействует с продуктом в то же самое время, что и пользователь – другой тестировщик, другой пользователь, хакер.
  • Дефектный ввод. Данные могли быть повреждены или перехвачены на пути к системе. Особенно это касается клиент-серверных приложений.
  • Время в качестве вводных данных. Плавающие баги могут зависеть и от времени как такового. Время всегда меняется вне зависимости от того, удалось ли вам проконтролировать и зафиксировать все остальное. Когда время и дата, или временные интервалы, используются в качестве данных, баги могут проявляться только в определенное время.
  • Временная лотерея. Вариации ввода, которые обычно не имеют значения, могут внезапно стать критическими в определенное время или при определенной нагрузке. От этой проблемы страдал Mars Rover – окно уязвимости в три миллисекунды, когда операция записи могла писать в защищенную часть памяти.
  • Комбинационная лотерея. Вариации ввода, которые обычно не имеют значения, могут вызвать проблему, если они скомбинированы определенным образом.

Вероятная причина номер 5. Прочие причины связаны с тем, что ваша ментальная модель системы и того, что на нее влияет, неверна или неполна.

  • Вы можете не знать о всех переменных, влияющих на систему.
  • Вы можете не знать об источниках искажений, влияющих на ваши наблюдения.
  • Вы можете не знать об инструментах, которые помогли бы вам понять систему или наблюдать за ней.
  • Вы можете не знать всех границ системы и характеристик этих границ.
  • В системе может вообще не быть функции, которую вы в ней предполагаете, или в нее включены дополнительные функции.
  • Сложный алгоритм может периодически вести себя неожиданно – например, математический хаос, который выглядит, как отклонение от нормы.

Обсудить в форуме

Неуловимые, раздражающие, заставляющие сомневаться – это все про плавающие баги. Попробуем разобраться, что это такое и с чем его едят.
Ловить ошибки – основная задача тестировщика, но бывают ситуации, когда ошибка зафиксирована, а повторить ее не получается. Загадочное поведение программы, которое невозможно воспроизвести или зафиксировать – одно из самых сложных явлений в работе инженеров по QA.
Обнаружить, поймать и превратить в обычный – схема охоты на плавающий баг. Говорят, будто плавающие баги есть в любой программе, просто некоторые из них еще ни разу не проявились.

Что такое плавающий баг?​

Нежелательное поведение программы, которое возникает спонтанно и непредсказуемо, называют плавающим багом или гейзенбагом с отсылкой к немецкому физику Вернеру Карлу Гейзенбергу – автору принципа неопределенности из квантовой физики.

Вернер Гейзенберг говорил, что «чем более пристально вы глядите на один предмет, тем меньше внимания вы уделяете чему-то еще».

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

Самые интересные случаи из практики тестировщиков чаще всего связаны именно с этим типом багов, т.е. с загадочными проблемами, которыми не станут заниматься разработчики, пока не будут понятны шаги воспроизведения. Определить, где они «живут» – задача специалистов по QA. В тоже время не всякое неустойчивое поведение равно плавающему багу. Например, неопределенность результатов при броске игральных костей не несет в себе угрозы и не является гейзенбагом.
Алгоритмов автоматического определения плавающих багов пока не придумали, поэтому инженерам по QA приходится создавать лучшие тестовые покрытия из возможных и учиться локализовать проблемы.

31596e84cf63d2db3cfaa1412bfeca62.jpg

Как работать с плавающими багами?​

Для избавления от плавающих багов используется традиционный принцип «повторить и разобрать», но с некоторыми оговорками:

  1. Как проверить, что перед вами плавающий баг, а не обычный? Во втором случае вы понимаете, откуда взялась проблема, а в первом – нет. Именно поэтому внимательность и способность ничего не упускать – одно из главных достоинств тестировщика. Самое смешное, неисправленный плавающий и исправленный обычный баги очень похожи – они не воспроизводятся, но плавающий баг может в любой момент вернуться.
  2. Чем выше тестируемость продукта, тем легче найти в нем плавающий баг.
  3. Любая произошедшая по непонятным причинам ошибка может вернуться. «Прошло само» не работает. Код – это четкая структура, поэтому умение локализовать баги важно развивать. Этот навык пригодится, когда ошибка будет воспроизведена, но как – непонятно.
  4. Плавающие баги могут легко воспроизводиться в продуктивной среде и плохо проявляться или вовсе не проявляться в тестовой. Это важно учитывать и соотносить с процессом релиза системы.
  5. В появлении плавающих ошибок может быть виноват целый комплекс причин, поэтому при тестировании используйте таблицы со множеством вариантов. Иногда простой перебор сочетаний различных условий приводит к успеху.
  6. Никогда не пытайтесь скрыть плавающий баг от заказчиков и пользователей. В будущем это может привести к еще большим проблемам.

Яркий пример того, как попытка Intel скрыть ошибку привела к убыткам:
В выпускавшихся Intel в 1994 году процессорах Pentium была проблема с некорректным делением чисел с плавающей запятой. В компании посчитали, что дефект может повлиять на работу очень узкого круга пользователей, и решили его скрыть. Возникший в обществе резонанс заставил Intel изменить позицию и принес убытков на $475 млн.

Как локализовать ошибку, если первичный анализ ничего не дал?​

  • Обратите внимание на межфункциональные и межсистемные блоки. Ошибки часто живут на границах.
  • Изучайте логи и трассировки.
  • Создавайте аналогичных тестовых пользователей с одинаковыми правами и полномочиями, проверяйте работу программы на них.
  • Попробуйте тест на других машинах с аналогичными и отличающимися характеристиками.
  • Исследуйте от частного к общему всю среду, в которой работает программа, и наоборот, попробуйте пойти от ошибки. Какие условия могут быть важны для ее проявления?

5521f17c0dc7950036a8e945f7805594.jpg

Почему возникают плавающие баги?​

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

  1. Переполнение. Какое-либо поле или контейнер могут переполняться и провоцировать сбой при корректной работе связанных с ним функций. В эпоху больших запасов памяти тестировщики часто упускают это из вида. Например, внутри системы могут считаться огромные суммарные значения, и она окажется не способна переварить такое количество символов.
  2. Проблема кода, которую также называют «Проблемой ТЗ». Зачастую плавающий баг связан с тем, как написан код (мы не рассматриваем сейчас некачественную работу, только непредсказуемую). Например, составителю технического задания на разработку очевидно, что при выборке данных нужно взять некий уникальный объект, но разработчик этого знать не может и прописывает свободный выбор. Бывает, что код написан верно, но какое-то сочетание условий приводит не к поломке, а к подмене функций. В этом месте не будет ошибки, но будет неверная работа программы в целом.
  3. Проблемы ввода. Например, в поле свободного ввода пользователь внес непредусмотренные алгоритмом данные, либо ошибочный символ (запятую вместо точки и т.д.). Сюда же относятся ошибки, связанные с использованием клавиатуры вместо мыши или ошибки призрачного ввода, когда данные вносит машина (особенно где-то в середине расчетов). В таких случаях проблему можно обнаружить, проставляя контрольные «стопы» и проверяя работу кода по частям. Еще один вариант – дефектный ввод, когда данные клиент-серверных приложений повреждены или переданы с ошибкой.
  4. Проблемы оборудования возникают, когда ошибки связаны с физическими факторами. Например, из-за перебоев с электропитанием, высоких температур в серверной, физических повреждений компьютера и т.д.
  5. Случайности. Некая комбинация условий может сработать корректно, но впоследствии привести к ошибке.
  6. Deus Ex Machina. Эти проблемы возникают, когда одновременно с вами кто-то еще использует приложение: разработчик, хакер или другой тестировщик.
  7. Неочевидные моменты. При анализе специалисты часто отбрасывают ненужное, чтобы сосредоточиться на важном, а оказывается, что проблема возникает из-за отброшенных ранее вариантов.
  8. Неизвестное. Невозможно учесть все. Например, в системе может быть функция, о которой тестировщику неизвестно, или некие источники искажений. Внутри приложения могут создаваться незадокументированные переменные и т.д. и т.п.

Еще несколько советов по работе с плавающими багами:​

  • Всегда проверяйте базу. Характеристики компьютера, что тестируете, исходные данные в документах и по факту.
  • Всегда проверяйте информацию со стороны. Не задавайте вопросы в чате пользователю или коллеге, лучше сходите и посмотрите сами.
  • Если кажется, что все уже проверено от и до, причем несколько раз, попросите коллег посмотреть. Без вас и ваших рассказов, с минимумом вводных.
  • Поищите похожие кейсы и посмотрите, как решались такие вопросы раньше.
  • Сохраняйте все логи. Возможно вам придется сравнивать не только исходный и последний, а еще и промежуточные.
  • Проверяйте то, что на первый взгляд не имеет значения. Даже если вам кажется, что это вообще не относится к вопросу. Часто именно оно оказывается искомым.
  • Проверяйте конфликты на границах разных модулей и систем, особенно если интеграция происходит между продуктами разных разработчиков.
  • Если используете сторонние компоненты, обратитесь в техподдержку разработчика.
  • Если нет никакой информации, ничего не помогает, а ошибка по прежнему не найдена, дайте проблеме отстояться. Вернитесь к ней завтра, а сегодня переключите внимание на другие задачи.
  • Не отчаивайтесь. Ищите инструменты, которые помогут решить вопрос – однажды вы обязательно их найдете.
  • Соотнесите пользу от устранения бага и потраченные на это усилия. Иногда достаточно знать о наличии проблемы: это не баг, это фича.

***
Невыявленные ошибки могут приводить к опасным последствиям. В 1962 году космический аппарат Mariner должен был направиться к Венере, но сломалась антенна и он перешел на автопилот, полетев не туда. В итоге аппарат пришлось взорвать над Атлантическим океаном, а произошло это из-за пропущенного при программировании системы навигации в одной из формул символа. Большинство багов не настолько фатальны, да и системы поиска ошибок стали надежнее, но стремительный рост информационных технологий приводит и к росту сложности систем. Найти в них даже обычные ошибки становится все труднее, а количество плавающих багов увеличивается. Их устранение – уже не начальный уровень в работе тестировщика, но тем интереснее решать подобные задачи. Удачи вам в обучении!

Источник статьи: https://proglib.io/p/chto-takoe-geyzenbag-i-kak-s-nim-borotsya-2021-02-28

Регистрация на курс

Плавающий баг?

Ох уж эти мистические «плавающие ошибки». Сколько вокруг них мифов! Но, когда причина найдена, всегда оказывается, что нет плавающих багов, а есть недолокализованные.

Поэтому мы будем учиться локализовывать баги, которые «не воспроизводятся». Учиться искать причину проблемы без помощи разработчика. Учиться смотреть в код и искать причину снаружи. Делить бисекционно и читать логи. В общем, всё, что нужно для воспроизведения!

Воспроизведение ошибки

Если вы не можете вопроизвести ошибку, то:

  1. Прочитайте логи — если есть доступ к логам, всегда в первую очередь смотрим туда! Если у нас веб-приложение, проверьте, что ушло с клиента на сервер.
  2. Проверьте граничные значения — баги часто тусят на границах.
  3. Попробуйте пойти «от обратного» — подумать, как получить саму проблему. Этот метод хорошо работает для багов с кэшом
  4. Составьте таблицу отличий — у вас то все работает. Что отличает ваш кейс от падающего?

Что записывать в таблицу отличий:

  1. Состояние объекта.
  2. Действия, которые с ним выполняли.
  3. Устройство, на котором воспроизводится.
  4. Время выполнения действия (какой релиз?).
  5. Способ воспроизведения (GUI, API).
  6. Количество открытых вкладок в браузере.

В отлове багов помогает понимание того, где копятся баги и какого рода: как влияет на работу системы concurrency, миграция данных, перетипизация переменной внутри кода… Зная последствия, вы будете понимать, что именно записать в таблицу отличий.

Локализация ошибки

Если вы можете воспроизвести баг, но не можете локализовать (слишком много шагов воспроизведения / слишком большой файл, внутри которого есть ошибка), то:

  1. Посмотрите код — возможно, это будет самым быстрым решением.
  2. Используйте бисекционное деление.
  3. Придумайте теорию (на баг влияет то и то) — подтвердите ее, а потом попробуйте опровергнуть.
  4. Выкиньте лишнее из шагов — возможно, именно это сбивает вас с толку

На курсе мы будем рассматривать каждую из техник. Вы сможете сразу применить ее на практике на специально подобранных домашних заданиях, которые показывают именно данную технику или конкретную проблему (миграции данных, стыка интеграции и т.д.)

О курсе

Это практический курс: теории минимум. Типичная лекция — на 10-15 минут. Короткая лекция «как это применять» и тут же практика! Конечно, есть и сложные лекции (на 30 минут). Есть и короткие, на 7 минут. Нет жесткой привязки ко времени лекции. Сколько надо дать теории, столько и говорю, а дальше уже практикуйтесь.

Для локализации багов мы будем применять техники:

  • Черного ящика — как понять, что происходит, если нет доступа в код.
  • Белого ящика — куда можно посмотреть в коде? Смотреть будем на примере приложения folks с открытым исходным java-кодом. Разумеется, у вас на проекте код будет выглядеть по-другому, но зато вы получите представление, где там могут вылезти баги. Баги, которые мы будем рассматривать на курсе, не были внесены в приложение нарочно — так что все приближено к реальности.

Лекции идут в моем фирменном стиле, с картинками. Посмотрите примеры видео на моем youtube-канале, чтобы понять, подходит ли вам такой стиль изложения.

Если вы переживаете, что не сможете что-то сделать (например, задания на просмотр кода), вот вам задача для самопроверки — соберите проект folks и запустите тесты. Инструкция есть, есть даже видео-инструкция по установке java, maven на Windows, Если справитесь, то и все остальное будет вам по плечу!

Программа курса

0. Введение

Что такое локализация и зачем она вообще нужна тестировщику.

Как умение локализовывать задачи экономит время команды и убирает панику.

Как знание о типовых проблемах помогает воспроизводить баги, которые «не воспроизводятся».

1. Уточнение устройств, на которых есть баг

На что обращать внимание при багах «поехала верстка», «текст вылезает за пределы экрана».

Как понять, в какой момент едет верстка? Какие инструменты использовать:

— как замерить размер окна;
— какие есть линейки;
— как посмотреть размер окна в консоли.

2. Исследование состояний

Изучим разные состояния объекта. Если проблема при сохранении — а кого мы вообще сохраняем?

— свежесозданную карточку
— отредактированную
— удаленную

Если у нас есть пользователь, то какой он? А как регистрировался? Как это может повлиять на воспроизведение бага?

3. Использование классов эквивалентности и граничных значений

Что такое классы эквивалентности.

Почему на границах встречаются баги.

Зачем тестировать ноль и как его найти, если у нас не строка ввода?

4. Опровержение своих теорий

Как опровергать свои теории и зачем это нужно.

— таблица отличий;

— метод «найди 5 отличий»;

— принцип минимализма (отсеивание лишнего).

5. Метод бисекционного деления

Что такое бисекционное деление.

Как его использовать тестировщику для локализации бага.

Как оно используется в разработке и к каким проблемам может привести.

6. Чтение логов

Что такое логи. Что в них записывается?

Как читать логи. Как читать стектрейс ошибки.

Логи на сервере и на клиенте.

7. Просмотр запросов с клиента на сервер

На клиенте помимо JS-логов можно смотреть, что вообще ушло на сервер.

Это помогает понять, где произошла ошибка и кто виноват: клиент или сервер. Учимся это делать.

8. Воспроизведение «от обратного»

Техника расследования закрытой комнаты. Наиболее актуальна для багов с кэшом.

Вот есть баг, из кэша достаются неправильные данные. Как воспроизвести? Идем от обратного, пытаемся получить “плохие данные” разными путями.

9. Проверка по коду

Как читать код, при условии, что разработчики идут вам на встречу и разделяют потроха логики и описание объектов.

Читаем java-объект и схему создания БД. Выверяем их на соответствие друг другу.

Внимание: у вас на проекте может быть не java, но принцип все тот же. На примере домашнего задания вы увидите, как можно найти баг, исследуя код

10. Проверка соответствия типов данных

Если поле встречается в коде несколько раз:

— в объектной модели;

— в схеме создания БД;

— где-то еще

Важно проверять соответствие типов. Смотрим, какие встречаются баги на несоответствие типов.

11. Проверка стыка интеграции

Какая бывает интеграция между системами.

Какие бывают баги на стыке интеграции.

Куда смотреть в первую очередь.

12. Проверка данных после миграции

Зачем тестировщику нужна как чистая база, так и база, живущая веками?

Примеры ошибок, вылезающих после миграции и почему они не ловятся на свежей тестовой БД.

13. Проверка concurrency

Типичная ошибка — выполнение CRUD над одним пользователем. Тестировщик может найти баги, переключаясь между вкладками интерфейса. Но это про поиск багов, а не про локализацию, казалось бы, да?

Но о concurrency важно знать, так как параллельная работа может быть и на другом уровне:

  • Идет забор данных из базы по 1000 записей за раз. Что, если в этой 1000 встретились 2 одинаковых клиента? Строка базы заблокирована первым изменением — второе разваливается.
  • Интеграция по SOAP REST. Если запросов много, там тоже можно влететь на изменение одного и того же клиента.

И в этом случае к вам придут “у меня тут ошибка”, а вы понять не можете, откуда она взялась, так как текст невразумительный. Надо помнить про параллельную работу, чтобы локализовать причину.

14. Заключение

Подводим итоги.

Вопросы и ответы

1. Можно ли проходить курс на Linux или Mac?

Да, он не зависит от вашей OS

2. Какие знания нужны для курса?

Общие знания о тестировании — что это вообще такое, как составлять тесты, что такое классы эквивалентности.

Если будете делать ДЗ с просмотром кода (необязательные), то:

  • Базовое понимание языка программирования (любого) — вы не должны падать в обморок от слов string или «тип данных». Но все, что будет нужно для ДЗ, я объясню.
  • Умение устанавливать новые программы — мы будем смотреть в код, а для этого нужно будет установить java, mercurial, maven. Вот инструкция, соберите проект перед записью на курс.

3. Будет ли мне интересно, если я проходил другие ваши курсы?

Если вы прошли «Школу для начинающих тестировщиков» в группе, то встречались с багами в коде folks — но эти задания на курсе необязательные! Так что сильно не влияют на интерес.

Если вы прошли «Логи как инструмент тестировщика», то уже сделали пару обязательных заданий. Но всё равно будет много нового и полезного

4. А скидку то дадут мне за эти ДЗ?

Да, покажите ваш сертификат и получите скидку:

  • Логи как инструмент тестировщика → 20%
  • Школа для начинающих, пройденная в группе → 10%

Как записаться

Напишите на trainings@software-testing.ru: свое ФИО и желаемый курс («курс про техники отлова ошибок»).

.

Способы оплаты

Регистрация и дата ближайшего запуска

Петя вспоминает, что как-то уже встречал эту ошибку, но она ни разу не повторилась. Он, разумеется, сразу же перепроверяет все кейсы, связанные с сообщениями пользователей, но у него всё точно по ТЗ и никаких ошибок.

Так Петя встретил свой первый плавающий баг.

Давайте подробнее рассмотрим, что же это за баги такие и где они плавают.
Для начала нужно узнать, что такое плавающий баг.

ПЛАВАЮЩИЙ БАГ – это ошибка, которая в одних и тех же условиях то воспроизводится, то нет.

Однако важно понимать, что любая ошибка, даже плавающая, имеет причины появления. И поиск причины – самое сложное в охоте на плавающий баг.

Основные ошибки при охоте

Какие ошибки может допустить Петя при охоте на свой первый плавающий баг?

1. Ринуться с головой в выяснение причин.
Так делать не стоит. Важно сразу понять, насколько ошибка критична, и, уже отталкиваясь от этого, действовать или…

Или оставить всё как есть. Потому что поиск плавающих багов – это всегда большие затраты времени не только QA отдела, но и отдела разработки.

Также не стоит паниковать: баги не вызваны злыми духами и в каждом проекте их в избытке. Просто большинство себя либо не проявило, либо не было замечено.

Также важно удостовериться, что баг действительно плавающий. Будет весьма глупо потратить много часов своей (и вдобавок чужой) работы на отлов ошибки, фикс которой вы пропустили.

Также стоит убедиться, что ошибка является так называемым тестировщиками “лотерейным” багом, то есть багом, всплывающим из-за выпадения какого-то рандома в проверяемом ПО.

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

Как охотиться?

А дальше есть множество способов работы, которые можно применять и каждый из них по-своему хорош:

1) Подключите к процессу стороннего человека, а лучше нескольких. Свежий взгляд часто замечает то, что вашему замыленному взгляду кажется несущественным.

2) Ищите инструменты, которые помогут вам точнее отслеживать проблему. Например, логи проекта (технические сообщения от программы, падающие в консоль или её аналог) позволят вам не ломать голову над тем, как же воспроизвести только что сломанное ПО. А вместо этого сразу отдать разработчику то, что укажет, что именно сломалось под капотом программы.

3) Налаживайте коммуникацию с пользователями. Спрашивайте детали у тех, кому не повезло столкнуться с плавающей ошибкой. Возможно, именно их помощь будет ключевой. Но не будьте излишне уверены в чужих словах.

4) Поищите в списке багов похожие проблемы. Иногда информация о похожих багах помогает в исправлении.

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

6) Провести стресс-тесты. Возможно, ошибка случилась из-за чрезмерной нагрузки.

7) Поговорите с разработчиками о том, чтобы поставить “ловушку” (функцию в программе, сообщающую о том, что что-то не так), которая даст необходимую информацию.

8) Если ничего не помогает, то дайте проблеме отлежаться. Может, она решится сама собой, а может, вы найдете необходимую информацию.

_______
Пост написан совместно с одним из наших преподавателей (Андрей Высоцкий).
В следующем посте рассмотрим, как на практике происходит поиск плавающих багов и поговорим про ошибке, которые допускаются при их поиске.

Неуловимые, раздражающие, заставляющие сомневаться – это все про плавающие баги. Попробуем разобраться, что это такое и с чем его едят.
Ловить ошибки – основная задача тестировщика, но бывают ситуации, когда ошибка зафиксирована, а повторить ее не получается. Загадочное поведение программы, которое невозможно воспроизвести или зафиксировать – одно из самых сложных явлений в работе инженеров по QA.
Обнаружить, поймать и превратить в обычный – схема охоты на плавающий баг. Говорят, будто плавающие баги есть в любой программе, просто некоторые из них еще ни разу не проявились.

Что такое плавающий баг?​

Нежелательное поведение программы, которое возникает спонтанно и непредсказуемо, называют плавающим багом или гейзенбагом с отсылкой к немецкому физику Вернеру Карлу Гейзенбергу – автору принципа неопределенности из квантовой физики.

Вернер Гейзенберг говорил, что «чем более пристально вы глядите на один предмет, тем меньше внимания вы уделяете чему-то еще».

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

Самые интересные случаи из практики тестировщиков чаще всего связаны именно с этим типом багов, т.е. с загадочными проблемами, которыми не станут заниматься разработчики, пока не будут понятны шаги воспроизведения. Определить, где они «живут» – задача специалистов по QA. В тоже время не всякое неустойчивое поведение равно плавающему багу. Например, неопределенность результатов при броске игральных костей не несет в себе угрозы и не является гейзенбагом.
Алгоритмов автоматического определения плавающих багов пока не придумали, поэтому инженерам по QA приходится создавать лучшие тестовые покрытия из возможных и учиться локализовать проблемы.

31596e84cf63d2db3cfaa1412bfeca62.jpg

Как работать с плавающими багами?​

Для избавления от плавающих багов используется традиционный принцип «повторить и разобрать», но с некоторыми оговорками:

  1. Как проверить, что перед вами плавающий баг, а не обычный? Во втором случае вы понимаете, откуда взялась проблема, а в первом – нет. Именно поэтому внимательность и способность ничего не упускать – одно из главных достоинств тестировщика. Самое смешное, неисправленный плавающий и исправленный обычный баги очень похожи – они не воспроизводятся, но плавающий баг может в любой момент вернуться.
  2. Чем выше тестируемость продукта, тем легче найти в нем плавающий баг.
  3. Любая произошедшая по непонятным причинам ошибка может вернуться. «Прошло само» не работает. Код – это четкая структура, поэтому умение локализовать баги важно развивать. Этот навык пригодится, когда ошибка будет воспроизведена, но как – непонятно.
  4. Плавающие баги могут легко воспроизводиться в продуктивной среде и плохо проявляться или вовсе не проявляться в тестовой. Это важно учитывать и соотносить с процессом релиза системы.
  5. В появлении плавающих ошибок может быть виноват целый комплекс причин, поэтому при тестировании используйте таблицы со множеством вариантов. Иногда простой перебор сочетаний различных условий приводит к успеху.
  6. Никогда не пытайтесь скрыть плавающий баг от заказчиков и пользователей. В будущем это может привести к еще большим проблемам.

Яркий пример того, как попытка Intel скрыть ошибку привела к убыткам:
В выпускавшихся Intel в 1994 году процессорах Pentium была проблема с некорректным делением чисел с плавающей запятой. В компании посчитали, что дефект может повлиять на работу очень узкого круга пользователей, и решили его скрыть. Возникший в обществе резонанс заставил Intel изменить позицию и принес убытков на $475 млн.

Как локализовать ошибку, если первичный анализ ничего не дал?​

  • Обратите внимание на межфункциональные и межсистемные блоки. Ошибки часто живут на границах.
  • Изучайте логи и трассировки.
  • Создавайте аналогичных тестовых пользователей с одинаковыми правами и полномочиями, проверяйте работу программы на них.
  • Попробуйте тест на других машинах с аналогичными и отличающимися характеристиками.
  • Исследуйте от частного к общему всю среду, в которой работает программа, и наоборот, попробуйте пойти от ошибки. Какие условия могут быть важны для ее проявления?

5521f17c0dc7950036a8e945f7805594.jpg

Почему возникают плавающие баги?​

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

  1. Переполнение. Какое-либо поле или контейнер могут переполняться и провоцировать сбой при корректной работе связанных с ним функций. В эпоху больших запасов памяти тестировщики часто упускают это из вида. Например, внутри системы могут считаться огромные суммарные значения, и она окажется не способна переварить такое количество символов.
  2. Проблема кода, которую также называют «Проблемой ТЗ». Зачастую плавающий баг связан с тем, как написан код (мы не рассматриваем сейчас некачественную работу, только непредсказуемую). Например, составителю технического задания на разработку очевидно, что при выборке данных нужно взять некий уникальный объект, но разработчик этого знать не может и прописывает свободный выбор. Бывает, что код написан верно, но какое-то сочетание условий приводит не к поломке, а к подмене функций. В этом месте не будет ошибки, но будет неверная работа программы в целом.
  3. Проблемы ввода. Например, в поле свободного ввода пользователь внес непредусмотренные алгоритмом данные, либо ошибочный символ (запятую вместо точки и т.д.). Сюда же относятся ошибки, связанные с использованием клавиатуры вместо мыши или ошибки призрачного ввода, когда данные вносит машина (особенно где-то в середине расчетов). В таких случаях проблему можно обнаружить, проставляя контрольные «стопы» и проверяя работу кода по частям. Еще один вариант – дефектный ввод, когда данные клиент-серверных приложений повреждены или переданы с ошибкой.
  4. Проблемы оборудования возникают, когда ошибки связаны с физическими факторами. Например, из-за перебоев с электропитанием, высоких температур в серверной, физических повреждений компьютера и т.д.
  5. Случайности. Некая комбинация условий может сработать корректно, но впоследствии привести к ошибке.
  6. Deus Ex Machina. Эти проблемы возникают, когда одновременно с вами кто-то еще использует приложение: разработчик, хакер или другой тестировщик.
  7. Неочевидные моменты. При анализе специалисты часто отбрасывают ненужное, чтобы сосредоточиться на важном, а оказывается, что проблема возникает из-за отброшенных ранее вариантов.
  8. Неизвестное. Невозможно учесть все. Например, в системе может быть функция, о которой тестировщику неизвестно, или некие источники искажений. Внутри приложения могут создаваться незадокументированные переменные и т.д. и т.п.

Еще несколько советов по работе с плавающими багами:​

  • Всегда проверяйте базу. Характеристики компьютера, что тестируете, исходные данные в документах и по факту.
  • Всегда проверяйте информацию со стороны. Не задавайте вопросы в чате пользователю или коллеге, лучше сходите и посмотрите сами.
  • Если кажется, что все уже проверено от и до, причем несколько раз, попросите коллег посмотреть. Без вас и ваших рассказов, с минимумом вводных.
  • Поищите похожие кейсы и посмотрите, как решались такие вопросы раньше.
  • Сохраняйте все логи. Возможно вам придется сравнивать не только исходный и последний, а еще и промежуточные.
  • Проверяйте то, что на первый взгляд не имеет значения. Даже если вам кажется, что это вообще не относится к вопросу. Часто именно оно оказывается искомым.
  • Проверяйте конфликты на границах разных модулей и систем, особенно если интеграция происходит между продуктами разных разработчиков.
  • Если используете сторонние компоненты, обратитесь в техподдержку разработчика.
  • Если нет никакой информации, ничего не помогает, а ошибка по прежнему не найдена, дайте проблеме отстояться. Вернитесь к ней завтра, а сегодня переключите внимание на другие задачи.
  • Не отчаивайтесь. Ищите инструменты, которые помогут решить вопрос – однажды вы обязательно их найдете.
  • Соотнесите пользу от устранения бага и потраченные на это усилия. Иногда достаточно знать о наличии проблемы: это не баг, это фича.

***
Невыявленные ошибки могут приводить к опасным последствиям. В 1962 году космический аппарат Mariner должен был направиться к Венере, но сломалась антенна и он перешел на автопилот, полетев не туда. В итоге аппарат пришлось взорвать над Атлантическим океаном, а произошло это из-за пропущенного при программировании системы навигации в одной из формул символа. Большинство багов не настолько фатальны, да и системы поиска ошибок стали надежнее, но стремительный рост информационных технологий приводит и к росту сложности систем. Найти в них даже обычные ошибки становится все труднее, а количество плавающих багов увеличивается. Их устранение – уже не начальный уровень в работе тестировщика, но тем интереснее решать подобные задачи. Удачи вам в обучении!

Источник статьи: https://proglib.io/p/chto-takoe-geyzenbag-i-kak-s-nim-borotsya-2021-02-28

Тестировщик зафиксировал в программе ошибку, а вот повторить ее не удается. Значит, попался плавающий баг — его нужно найти, поймать и превратить в обычный. Но сделать это бывает сложно. 

Рассказываем, что нужно знать о гейзенбаге и как его исправить. 

Что такое гейзенбаг
 

Гейзенбаг (плавающий баг) — это возникающие спонтанно нежелательные действия программы. Такие баги ищут QA-специалисты. Алгоритмов, которые автоматически определяют плавающие баги, нет. 

Термин назван в честь физика Вернера Гейзенберга. Он сформулировал принцип неопределенности в квантовой физике.

Причины появления плавающего бага

  • Время

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

  • Память 

При дебаггинге адреса переменных могут измениться. Выполнение кода, скомпилированного без оптимизации, также может привести к перемещению некоторых переменных из регистров в оперативной памяти. 

  • Assert

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

  • Переполнение

Тестировщик может не обратить внимания на то, что поле или контейнер переполнены и это спровоцировало сбой в работе. Система не может справиться, если у нее внутри считаются огромные значения. 

  • Рандомизация

Если в коде есть рандомизация, это также может вызвать несоответствия между разными прогонами, и нужные условия для возникновения ошибки могут периодически появляться.

Как решить проблему с плавающим багом
 

Универсального решения нет, но есть техники, которые способны помочь: 

  • Мониторинг системных процессов

Важно, чтобы никакой другой процесс не мешал основному. 

  • Запуск на CPU вместо GPU. Графический процессор дает прирост производительности, но программное обеспечение по умолчанию может его не поддерживать. Выключите графический процессор в своей системе и попробуйте запустить его на CPU.
     
  • Проверка кода на наличие генераторов случайных чисел. Нужно протестировать его, находя генераторы случайных чисел, и отследить случайный вывод для удачных и ошибочных прогонов.
     
  • Запуск на одном узле NUMA гарантирует, что плавающий баг возник не из-за проблем с архитектурой системы. Между узлами NUMA часто наблюдается нестабильность межсоединений.
     
  • Изменение зависимости ПО. Важно, чтобы гейзенбаг не исходил от внешнего программного компонента. Например, вместо использования TensorFlow, оптимизированного для Intel с DNNLv1.1, можно попробовать Vanilla TensorFlow (созданный из исходных кодов или установленный с помощью pip).
     
  • Удаление лишних функций по очереди позволит выяснить, какая из них — источник плавающего бага.
     
  • Запуск стресс-тестов поможет выявить потенциальные ошибки в экстремальных условиях. Но тестирование не доказывает отсутствие ошибок. Стресс-тесты только позволяют снизить риск незамеченных ошибок в рабочей среде.
     
  • Использование специальных алгоритмов для обнаружения потенциального состояния гонки (Race condition). Алгоритм набора блокировок сообщает о потенциальном состоянии гонки, когда к общей памяти обращаются два или более потоков, удерживающих общую блокировку. Он может сообщать о ложных срабатываниях. Алгоритм «происходит до» основан на частичном упорядочении событий (любой инструкции, включая чтение/запись и блокировки) в распределенных системах внутри и между потоками. Этот алгоритм генерирует очень мало ложных срабатываний, но он чувствителен к порядку выполнения, поэтому может потребоваться запустить его несколько раз, прежде чем удастся обнаружить состояние гонки, вызывающее плавающий баг.

  • Обратный дебаггинг — способность дебаггера останавливаться после сбоя в программе и возвращаться к истории выполнения, чтобы раскрыть причину сбоя.
     
  • Использование специальных инструментов дебаггинга для состояния гонки. Вот несколько примеров:

#1. Microsoft CHESS — инструмент для поиска и воспроизведения гейзенбага в параллельных программах. CHESS многократно запускает параллельный тест. Если чередование приводит к ошибке, CHESS может воспроизвести его для улучшения дебаггинга.

#2. The Intel Inspector помогает находить и отлаживать ошибки потоковой передачи, памяти и постоянной памяти на ранних этапах цикла проектирования.

#3. Kiuwan — инструмент статического анализа кода. Он обнаруживает угрозы безопасности до того, как они попадут в рабочую среду. 

#4. RacerX использует чувствительный к потоку межпроцедурный анализ для обнаружения как состояния гонки, так и взаимоблокировок.

  • Использование инструментов дебаггинга:

C ++: UDB. Находит и исправляет ошибки. 

C #: RevDeBug. Исправляет ошибки при диагностике сбоев программного обеспечения. 

Python: RevPDB. Позволяет перемещаться вперед и назад.

Регистрация на курс

Плавающий баг?

Ох уж эти мистические «плавающие ошибки». Сколько вокруг них мифов! Но, когда причина найдена, всегда оказывается, что нет плавающих багов, а есть недолокализованные.

Поэтому мы будем учиться локализовывать баги, которые «не воспроизводятся». Учиться искать причину проблемы без помощи разработчика. Учиться смотреть в код и искать причину снаружи. Делить бисекционно и читать логи. В общем, всё, что нужно для воспроизведения!

Воспроизведение ошибки

Если вы не можете вопроизвести ошибку, то:

  1. Прочитайте логи — если есть доступ к логам, всегда в первую очередь смотрим туда! Если у нас веб-приложение, проверьте, что ушло с клиента на сервер.
  2. Проверьте граничные значения — баги часто тусят на границах.
  3. Попробуйте пойти «от обратного» — подумать, как получить саму проблему. Этот метод хорошо работает для багов с кэшом
  4. Составьте таблицу отличий — у вас то все работает. Что отличает ваш кейс от падающего?

Что записывать в таблицу отличий:

  1. Состояние объекта.
  2. Действия, которые с ним выполняли.
  3. Устройство, на котором воспроизводится.
  4. Время выполнения действия (какой релиз?).
  5. Способ воспроизведения (GUI, API).
  6. Количество открытых вкладок в браузере.

В отлове багов помогает понимание того, где копятся баги и какого рода: как влияет на работу системы concurrency, миграция данных, перетипизация переменной внутри кода… Зная последствия, вы будете понимать, что именно записать в таблицу отличий.

Локализация ошибки

Если вы можете воспроизвести баг, но не можете локализовать (слишком много шагов воспроизведения / слишком большой файл, внутри которого есть ошибка), то:

  1. Посмотрите код — возможно, это будет самым быстрым решением.
  2. Используйте бисекционное деление.
  3. Придумайте теорию (на баг влияет то и то) — подтвердите ее, а потом попробуйте опровергнуть.
  4. Выкиньте лишнее из шагов — возможно, именно это сбивает вас с толку

На курсе мы будем рассматривать каждую из техник. Вы сможете сразу применить ее на практике на специально подобранных домашних заданиях, которые показывают именно данную технику или конкретную проблему (миграции данных, стыка интеграции и т.д.)

О курсе

Это практический курс: теории минимум. Типичная лекция — на 10-15 минут. Короткая лекция «как это применять» и тут же практика! Конечно, есть и сложные лекции (на 30 минут). Есть и короткие, на 7 минут. Нет жесткой привязки ко времени лекции. Сколько надо дать теории, столько и говорю, а дальше уже практикуйтесь.

Для локализации багов мы будем применять техники:

  • Черного ящика — как понять, что происходит, если нет доступа в код.
  • Белого ящика — куда можно посмотреть в коде? Смотреть будем на примере приложения folks с открытым исходным java-кодом. Разумеется, у вас на проекте код будет выглядеть по-другому, но зато вы получите представление, где там могут вылезти баги. Баги, которые мы будем рассматривать на курсе, не были внесены в приложение нарочно — так что все приближено к реальности.

Лекции идут в моем фирменном стиле, с картинками. Посмотрите примеры видео на моем youtube-канале, чтобы понять, подходит ли вам такой стиль изложения.

Если вы переживаете, что не сможете что-то сделать (например, задания на просмотр кода), вот вам задача для самопроверки — соберите проект folks и запустите тесты. Инструкция есть, есть даже видео-инструкция по установке java, maven на Windows, Если справитесь, то и все остальное будет вам по плечу!

Программа курса

0. Введение

Что такое локализация и зачем она вообще нужна тестировщику.

Как умение локализовывать задачи экономит время команды и убирает панику.

Как знание о типовых проблемах помогает воспроизводить баги, которые «не воспроизводятся».

1. Уточнение устройств, на которых есть баг

На что обращать внимание при багах «поехала верстка», «текст вылезает за пределы экрана».

Как понять, в какой момент едет верстка? Какие инструменты использовать:

— как замерить размер окна;
— какие есть линейки;
— как посмотреть размер окна в консоли.

2. Исследование состояний

Изучим разные состояния объекта. Если проблема при сохранении — а кого мы вообще сохраняем?

— свежесозданную карточку
— отредактированную
— удаленную

Если у нас есть пользователь, то какой он? А как регистрировался? Как это может повлиять на воспроизведение бага?

3. Использование классов эквивалентности и граничных значений

Что такое классы эквивалентности.

Почему на границах встречаются баги.

Зачем тестировать ноль и как его найти, если у нас не строка ввода?

4. Опровержение своих теорий

Как опровергать свои теории и зачем это нужно.

— таблица отличий;

— метод «найди 5 отличий»;

— принцип минимализма (отсеивание лишнего).

5. Метод бисекционного деления

Что такое бисекционное деление.

Как его использовать тестировщику для локализации бага.

Как оно используется в разработке и к каким проблемам может привести.

6. Чтение логов

Что такое логи. Что в них записывается?

Как читать логи. Как читать стектрейс ошибки.

Логи на сервере и на клиенте.

7. Просмотр запросов с клиента на сервер

На клиенте помимо JS-логов можно смотреть, что вообще ушло на сервер.

Это помогает понять, где произошла ошибка и кто виноват: клиент или сервер. Учимся это делать.

8. Воспроизведение «от обратного»

Техника расследования закрытой комнаты. Наиболее актуальна для багов с кэшом.

Вот есть баг, из кэша достаются неправильные данные. Как воспроизвести? Идем от обратного, пытаемся получить “плохие данные” разными путями.

9. Проверка по коду

Как читать код, при условии, что разработчики идут вам на встречу и разделяют потроха логики и описание объектов.

Читаем java-объект и схему создания БД. Выверяем их на соответствие друг другу.

Внимание: у вас на проекте может быть не java, но принцип все тот же. На примере домашнего задания вы увидите, как можно найти баг, исследуя код

10. Проверка соответствия типов данных

Если поле встречается в коде несколько раз:

— в объектной модели;

— в схеме создания БД;

— где-то еще

Важно проверять соответствие типов. Смотрим, какие встречаются баги на несоответствие типов.

11. Проверка стыка интеграции

Какая бывает интеграция между системами.

Какие бывают баги на стыке интеграции.

Куда смотреть в первую очередь.

12. Проверка данных после миграции

Зачем тестировщику нужна как чистая база, так и база, живущая веками?

Примеры ошибок, вылезающих после миграции и почему они не ловятся на свежей тестовой БД.

13. Проверка concurrency

Типичная ошибка — выполнение CRUD над одним пользователем. Тестировщик может найти баги, переключаясь между вкладками интерфейса. Но это про поиск багов, а не про локализацию, казалось бы, да?

Но о concurrency важно знать, так как параллельная работа может быть и на другом уровне:

  • Идет забор данных из базы по 1000 записей за раз. Что, если в этой 1000 встретились 2 одинаковых клиента? Строка базы заблокирована первым изменением — второе разваливается.
  • Интеграция по SOAP REST. Если запросов много, там тоже можно влететь на изменение одного и того же клиента.

И в этом случае к вам придут “у меня тут ошибка”, а вы понять не можете, откуда она взялась, так как текст невразумительный. Надо помнить про параллельную работу, чтобы локализовать причину.

14. Заключение

Подводим итоги.

Вопросы и ответы

1. Можно ли проходить курс на Linux или Mac?

Да, он не зависит от вашей OS

2. Какие знания нужны для курса?

Общие знания о тестировании — что это вообще такое, как составлять тесты, что такое классы эквивалентности.

Если будете делать ДЗ с просмотром кода (необязательные), то:

  • Базовое понимание языка программирования (любого) — вы не должны падать в обморок от слов string или «тип данных». Но все, что будет нужно для ДЗ, я объясню.
  • Умение устанавливать новые программы — мы будем смотреть в код, а для этого нужно будет установить java, mercurial, maven. Вот инструкция, соберите проект перед записью на курс.

3. Будет ли мне интересно, если я проходил другие ваши курсы?

Если вы прошли «Школу для начинающих тестировщиков» в группе, то встречались с багами в коде folks — но эти задания на курсе необязательные! Так что сильно не влияют на интерес.

Если вы прошли «Логи как инструмент тестировщика», то уже сделали пару обязательных заданий. Но всё равно будет много нового и полезного

4. А скидку то дадут мне за эти ДЗ?

Да, покажите ваш сертификат и получите скидку:

  • Логи как инструмент тестировщика → 20%
  • Школа для начинающих, пройденная в группе → 10%

Как записаться

Регистрация и дата ближайшего запуска

Способы оплаты

Что вы знаете о тестировании ПО? А об исследовании плавающих багов? Роль тестирования в современном мире нельзя преувеличить, а получить знания и даже углубить в перспективной отрасли Вы можете на курсах тестирования ПО в Минске.

Если вы способны уверенно справляться с плавающими багами – вы входите в тот процент хороших тестировщиков. Именно самые интересные истории в тестировании ПО связаны с охотой на “белых китов” в океане сложного кода.

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

К слову, плавающие баги не проблема. Все программирование крутится вокруг контроля неустойчивого поведения. Итак, в чем проблема?

Нас не должно беспокоить неустойчивое поведение, если:

  1.  так и задумано
  2.  данное поведение не несет в себе угрозы 

Давайте рассмотрим такой пример: когда мы подбрасываем монету или тянем за рычаг автомата, результат подброшенной монеты или шанс выбить 777 в автомате – хороший пример неустойчивого поведения. Даже странное неустойчивое поведение не должно беспокоить при условии, что есть уверенность в отсутсвии проблем. Когда вы тестируете, вы ведь не задумываетесь о таких вещах, как магнитные поля или мелкие скачки напряжения, хотя они влияют на результат тестирования.

Многие плавающие баги никем не обнаружены просто потому, что они еще ни разу не проявились, или проявились, но никто их не зафиксировал. Все, что мы можем сделать – это позаботиться о создании наилучшего тестового покрытия и придерживаться этого подхода. Не существует алгоритмов для автоматического определения или предотвращения всех плавающих багов.

Итак, то, что обычно называется плавающим багом – это непонятное, нежелательное поведение  системы, которое наблюдалось как минимум единожды, и которое мы не можем вызвать снова.

Наша задача – превратить плавающий баг в обычный, поняв его природу. После этого он станет головной болью программистов.


Принципы работы с плавающими багами:

  • Успокойтесь, баги, скорее всего, не проявление агрессии злых духов.
  • Подумайте, багов проявился один разы – значит, он проявится снова.
  • Если не исправить бга, врядли можно говорить о гарантии качества.
  • С осторожностью относитесь к исправлениям плавающих багов. Исправленный баг и неисправленный плавающий баг практически невозможно отличить друг от друга в течение какого-то времени и/или при определенных условиях.
  • Любое состояние системы, переход в которое занимает длительное время в обычных условиях, можно достигнуть в непредсказуемых ситуациях.
  • Сложное и непонятное поведение обычно вызвано причиной, которая, на самом деле, лежит на поверхности.
  • Сложное и непонятное поведение иногда вызвано целым рядом причин.
  • Зачастую, плавающих баги могут помочь узнать свой продукт чуточку лучше.
  • Если вы думаете, что вы абсолютно правильно предполагаете о причинах багов, скорее всего, вы не правы.
  • Иногда соверешенно другой человек может дать вам ключик от разгадки.
  • Скорее всего, выявленный баг в руках тестировщика также проявится в руках пользорвателя.
  • Принцип Pentium 1994: плавающая техническая проблема может привести к систематическим и очень дорогостоящим проблемам.
  • Даже если баг “плавающий”, риск всегда стабилен.
  • Чем выше тестируемость продукта, тем легче исследовать плавающие баги.
  • Когда вы перепробовали все невозможное, то то, что осталось, каким бы невероятным оно ни казалось, могло уже принести не мало убытков! Поэтому не ждите момента, когда вы вызовите баг снова, фиксируйте его!
  • Если вы не успеваете выловить плавающий баг до релиза, сделайте все, что в ваших силах, чтобы все-таки поймать его и исправить.

Общие советы по исследованию плавающих проблем:

  • Перепроверьте свои базовые предположения: используете ли вы именно тот компьютер?
  • Тестируете ли вы именно то, что нужно? Верны ли ваши наблюдения?
  • Слова постронних людей иногда могут принести большую пользу, но все таки полагайтесь на себя.
  • Пригласите других тестировщиков, подключите к процессу большее количество людей.
  • Просите людей сообщать о плавающих проблемах.
  • Если вам сказали, что причина проблемы точно не в этом, обратите на это особое внимание.
  • Проверьте сайты технической поддержки каждого из используемых сторонних компонентов.
  • Возможно, ваша проблема там указана.
  • Ищите инструменты, которые помогут вам наблюдать за поведением системы и контролировать его.
  • Налаживайте коммуникацию с юзерами (особенно с реальными пользователями).
  • Объедените все плавающие баги, чтобы легче было отслеживать закономерности.
  • Пройдитесь по списку багов, попробуйте найти в нем похожие на плавающий баг проблемы.
  • Относитесь серьезнее к фиксированию багов, используйте специальные инструменты.
  • Точнее контролируйте данные, которые вы вводите (включая их последовательность, время, типы, размеры, источники, итерации, комбинации).
  • Систематически покрывайте тестами данные ввода и состояния системы.
  • Сохраняйте абсолютно все логи. Возможно, позже вам понадобится сравнить новые логи со старыми.
  • Если проблема чаще возникает в одних ситуациях и реже в других, проведите статистический анализ разницы между закономерностями в этих ситуациях.
  • Начните контролировать то, что раньше казалось не важным.
  • Упрощайте. Пробуйте менять одну переменную за раз, делить систему на части (помогает узнать природу и изолировать проблему).
  • Усложняйте. Пробуйте менять несколько переменных за раз, устройте в системе бедлам (помогает выявить баги-лотереи).
  • Добавьте элемент случайности в состояния системы и обрабатываемые данные (возможно, при помощи менее жесткого контроля), чтобы добиться состояний, которые, возможно, не вписываются в ваш обычный шаблон использования.
  • Создайте нагрузку на систему (большие объемы данных).
  • Поставьте ловушку, чтобы при возникновении проблемы в следующий раз вам удалось изучить ее получше.
  • Подумайте насчет код-ревью.
  • Узнавайте и держите в  голове случаи локализации плавающих багов.
  • Систематически размышляйте о причинах плавающих багов.
  • Перед тем, как потратить много времени на исправление мелкого бага, подумайте, стоит ли он того.
  • Если ничего не помогает, попробуйте отвлечься от всего и заняться другими проблемами, чтобы понять, удастся ли выявить плавающих баг в этом случае.

Возможные причины плавающих багов:

Исследуя плавающий баг, думайте о том, что может вызвать проблемы такого рода. Ниже – список эвристик, которым можно пользоваться в подобным ситуациях. Некоторые из причин дублируются, потому что их можно рассматривать с разных точек зрения.

Причина 1: Поведение системы не отличается от ее исходного поведения. Кажущийся сбой поведения – артефакт, относящийся к вашему восприятию.

Неграмотное наблюдение. Наблюдатель мог быть невнимательным – например, подвергнуться “Слепоте невнимания” – феномену, когда мозг занят чем-то еще, и человек не видит того, что находится у него прямо перед носом. Если показать ему то же самое еще раз, он увидит нечто новое для себя и предположит, что раньше такого не происходило. К тому же так работает ряд оптических иллюзий, демонстрируя кажущееся иным поведение при том, что ровным счетом ничего не изменилось.

Плохая память. Возможно, наблюдатель плохо запомнил свои впечатления, или записи, фиксирующие проблему, недоступны. Мозг работает с огромными объемами информации. Он пытается проанализировать их, сделать какие-то выводы, но что-то важное в таком случае может быть упущено. К тому же в процессе разработки и тестирования одно и то же действие может повторяться многократно, и можно просто запутаться в своих впечатлениях.

Неправильаня атрибуция. Наблюдатель может приписать свое наблюдение не тому, чему нужно. Например, “Microsoft Word упал” может означать, что упала Windows, и этого не будет связано с прогарммой никаких образом. Word вообще ничего не сделал. Этот феномен еще называют “ложной корреляцией” и часто встречается, когда одно событие следует сразу же после другого, и кажется, что это причина и следствие. Благодаря ложной корреляции плавающие баги зачастую считаются обычными багами, появившимися из-за крайне сложного и маловероятного ряда причин.

Искажение фактов. Наблюдатель, возможно, неверно передает свои впечатления. Это происходит, когда: он настолько уверен в своих предположениях, что передает свои впечатления определенным образом.

Ненадежная коммуникация. Коммуникация с наблюдателем может быть неполной. У нас создается ощущение, что мы нашли плавающий баг, потому что сообщения о нем не всегда до нас доходят, даже если проблема вполне предсказуема. Фраза “Мне кажется, проблема больше не проявляется” может означать, что люди просто перестали о ней сообщать.

Ненадежный оракул. Мнение наблюдателя насчет того, что является проблемой, а что нет, постоянно меняется. У нас может создаться впечатление, что проблема плавающая, только потому, что некоторые люди – иногда – не считают это поведение проблемой, даже если оно вполне предсказуемое. Другие люди могут отнестись к вопросу иначе, и даже один и тот же человек может поменять свое мнение.

Причина 2. Система ведет себя иначе, потому что это другая система

Deus ex machina. Разработчик мог специально что-то поменять, а затем октатить изменения. Довольно расспространенное явление, когда над разными частями платформы одновременно работает несколько разработчиков или команд, при этом не координируя свои действия друг с другом. А возможно, это просто модификации приложения хакерами.

Случайное изменение. Разработчик мог внести правки случайно. (Возможно, именно внесение изменений приводит к появлению плавающих багов..

Изменение платформы. Один из компонентов платформы мог быть заменен или переконфигурирован. Пользователь мог что-то изменить в компоненте, от которого зависит четкая работа продукта. Довольно расспространенный источник таких проблем – автоматические обновления Windows, изменения в конфигурации памяти и дискового пространства.

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

Чужая система. В работу вашего приложения может вмешаться какое-нибудь еще. Например, в веб-тестировании я могу иногда получать неверные результаты из-за прокси-сервера провайдера, который загружает кэшированную версию страницы в неподходящий момент. Другие примеры такого вмешательства – это сканирование на вирусы, обновления системы, другие программы или та же самая программа, запущенная повторно.

Раздвоение личности. То, что для вас является единой системой, может состоять из нескольких систем, работающих как единая. Например, я могу получать разные результаты от Google в зависимости от того, на какой сервер Гугла я попадаю, или я опечатался в URL и случайно начал тестировать на другом сервере.

Человеческий фактор. Возможно, за запуск некоторой части системы отвечает человек, и человек может иногда ошибаться.

Причина 3. Система ведет себя иначе, потому что находится в другом состоянии.

Замершее условие. Решение, которое должно основываться на статусе условия, могло перестать проверять это условие, застряв в состоянии “всегда да” или “всегда нет”.

Неверная инициализация. Одна или несколько переменных могли не инициализироваться. Стартовое состояние расчетов становится зависимым от предыдущих расчетов той же или иной функции.

Отказ в ресурсах. Критически важный файл, поток или другая переменная недоступны для системы. Это может произойти, потому что они не существуют, повреждены или заблокированы другим процессом.

Прогрессивное повреждение данных. Система могла превратиться в хаос из-за постепенно накапливающихся мелких багов. Проявлением может быть рассинхрон временных циклов.

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

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

Другой режим или настройки. Система может работать при разнообразных режимах, и пользователь может установить какой-то другой. Отличия могут быть незаметны с первого взгляда.

Причина 4. Система ведет себя иначе, потому что получила другие вводные данные.

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

Секретные границы и условия. Софт может вести себя иначе в некоторых частях ввода данных, чем в других. Это может произойти из-за скрытых границ или областей падения, которые никем не зафиксированы и которых вы не ожидаете, предполагая совсем другой исход.

Другой профиль. Использование приложений некоторыми пользователями может чем-то отличаться от других пользователей. Немного отличающийся ввод данных может привести к соверешенно неожиданному результату.

Призрачный ввод. В некоторых случаях машина – источник ввода данных. Пользователь может не заметить такой ввод, однако машина включает вариации из-за разных файлов, различные сигналы от периферийных устройств, или данные, поступающие по сети.

Deus Ex Machina. Кто-то еще работает с продуктом в то же самое время, что и пользователь – другой тестировщик, другой пользователь, хакер.

Дефектный ввод. Данные ввода могли быть повреждены или перехвачены на пути к системе. Особенно это касается клиент-серверных приложений.

Время в качестве вводных данных. Плавающие баги могут возникать на основе времени. Время не стоит на месте вне зависимости от того, удалось ли вам проконтролировать и зафиксировать все остальное. Когда время и дата, или временные интервалы, используются в качестве данных, баги могут проявляться только в определенное время.

Временная лотерея. Вариации ввода, которые обычно не имеют значения, могут внезапно стать проблемой в определенное время или при определенной нагрузке.

Комбинационная лотерея. Вариации ввода, которые обычно не имеют значения, могут вызвать проблему, если они скомбинированы определенным образом.

Причина 5. Другие причины связаны с тем, что ваша ментальная модель системы и того, что на нее влияет, неверна или неполна.

  • Вы можете быть не в курсе всех переменных, влияющих на систему.
  • Вы можете не знать об источниках искажений, влияющих на ваши наблюдения.
  • Вы можете не знать об инструментах, которые помогли бы вам понять систему или наблюдать за ней.
  • Вы можете не знать всех границ системы и характеристик этих границ.
  • Фактически в системе может и не быть такой функции, которую вы подозреваете, или могут быть дополнительные функции.
  • Сложный алгоритм может работать непредстказуемо, например, в случае математического хаоса, который можно принять за отклонение от нормы.

Записаться сейчас / Бесплатная консультация

Понравилась статья? Поделить с друзьями:
  • Что такое раскаяние почему важно признавать свои ошибки
  • Что такое системная ошибка msvcp110 dll
  • Что такое перманентная ошибка
  • Что такое периодическая ошибка монтировки
  • Что такое системная ошибка 8646