какие могут быть баги на сайте
Поиск багов как образ жизни: обзор №2
Длительная работа в IT натаскивает видеть несовершенства в пользовательском софте. Иногда это откровенные баги, которые хорошо бы исправить. Но сообщить об этом затруднительно из-за непрофессиональной работы поддержки. Публикация таких обзоров багов действительно помогает привлечь внимание разработчиков. В этом обзоре будут рассмотрены проблемы на сайтах ОнлайнТрейд и Ростелеком, в мобильном приложении банка Рокетбанк и даже Хабра! Про Ростелеком вообще детектив получился.
Введение
В прошлом обзоре были рассмотрены баги на сайтах телеканала 2×2, ресторана MaMaMia, провайдера Ростелекома, моб приложениях РЖД, ВТБ и Сбербанк.
Хабра-эффект от статьи был очень положительным. В течение двух недель в приложении ВТБ починили загрузку скриншотов в чате поддержки, а на сайте Ростелекома убрали значение NULL из имени пользователя личного кабинета. Этим проблемам было 6 месяцев и больше года. А тут поправили за две недели. Отличный результат! Я даже подумываю начать собирать баги от пользователей для написания обзоров. Очевидно, что проблемных программ намного больше, чем я сам могу использовать, поэтому могу помочь кому-то привлечь внимание к проблемам.
Баги на сайтах
Магазин ОнлайнТрейд
На сайте ОнлайнТрейд половину верхнего сайта занимает окошко для быстрого поиска товаров. Это стандартный интерфейс для такого рода сайтов. Так сделано, чтобы максимально быстро погрузить потенциального пользователя в ассортимент доступных товаров. Но на этом сайте есть странный баг с поиском.
При вводе текста выводятся результаты быстрого поиска в виде «выпадающего» списка. До этого момента у меня происходит всё стандартно, но при выборе какого-нибудь пункта поисковые предложения сворачиваются.
Проблема очень старая (для меня по крайней мере). Иногда переход таки выполняется, но в целом нормально пользоваться сайтом у меня не получается. Год назад поддержка ничего дельного не ответила. Сейчас я попробовал ещё раз сообщить о проблеме.
Первый же уточняющий вопрос навёл на определённые мысли:
Скажите, а как осуществляется клик по товару? Мышка, трекбол, трекпад? Или клавиатурой?
И правда. Позиционирование с тачпада ноутбука и компьютерной мыши отличается. Скорее всего, с моего устройства клик происходит мимо результатов поисковой выдачи, и они всегда сворачиваются. Случайные переходы по ссылкам, видимо, работали при случайном попадании на них.
Кстати, год назад проблема повторялась с другого ноутбука. Но оба фирмы ASUS. Нигде больше такого поведения не встречал. Поддержка тоже удивлена:
Нет, просто с этой проблемой обратились только вы, анализируем, в чем может быть причина.
ЛК Ростелеком
В прошлом обзоре я приводил такую проблему в личном кабинете Ростелекома:
Сейчас многие поглядывают за электронными сервисами родителей. Например, в Ростелеком можно объединить лицевые счета в одном личном кабинете. Я периодически настраиваю себе такое. Периодически, потому что работает это нестабильно. О чём, собственно, эта история.
Года 2 назад я завёл себе ещё один личный кабинет Ростелеком по новому адресу и решил объединить лицевые счета в одном месте. Для этого на сайте есть специальная кнопка с красивым описанием:
Для управления Вашими услугами или услугами Ваших близких, проживающих в любом регионе России, привяжите нужные лицевые счета Ростелеком.
Этот функционал уже тогда был и уже тогда не работал нормально. Кое-как с помощью поддержки мне подцепили второй лицевой счёт и несколько лет я не знал проблем.
Но недавно я имел неосторожность залогиниться в личном кабинете с данными от прикреплённого лицевого счёта, перепутал. и он открепился!
А этот баг (или фича), с невозможностью настройки через личный кабинет, всё ещё существует. Нажимаем в личном кабинете на кнопочку «Привязать лицевой счёт» и начинаем наш квест.
Нас встречает такая незамысловатая формочка. Мы видим, что шагов всего 4 (спойлер: до результата дело не дойдёт). Вводимые данные понятны, за исключением чекбокса «промокод от друга». Даже идей нет, что это и зачем здесь. Если от этого есть хоть какая-то польза, то формулировка явно неудачная. Вводим номер лицевого счёта и идём дальше.
Не этой странице ни у кого не должно возникнуть затруднений. Продолжаем квест.
Та-дам! Ваш пароль от прикрепляемого лицевого счёта не подходит. Хотя у вас есть данные авторизации от двух лицевых счетов, можно в любой момент залогиниться с ними, дальше этой формочки никто не пройдёт. Всё, что вы видели ранее — не более, чем пара дизайнерских страничек. Функционала – ноль. Следующий мем вполне отражает эмоции в этот момент:
П: Здравствуйте! Сообщите, пожалуйста, лицевой счет и ФИО владельца договора на счет, который хотите присоединить.
П: Сообщите, пожалуйста, лицевой счет.
П: Спасибо за ожидание. Проверьте, пожалуйста, еще раз. Возможно, лицевой счет уже присоединился в личном кабинете.
П: Спасибо за ожидание. Я еще раз уточнила информацию, лицевой счет уже присоединен в личном кабинете, пожалуйста, обновите страницу.
П: Спасибо за ожидание. Сообщите, пожалуйста, лицевой счет и ФИО владельца договора, именно того, лицевого счета, который не можете привязать в личном кабинете.
П: Спасибо за ожидание. Уточните, пожалуйста, паспортные данные владельца (серию и номер), чтобы я попробовала присоединить данный лицевой счет в личном кабинете.
Тут меня выкидывает с сайта, и я больше не могу зайти в личный кабинет некоторое время:
Я представляю, как у оператора ничего не получается сделать, он врывается в серверную, вырывает жёсткий диск для ручного редактирования данных. После чего возвращает диск обратно.
Тем временем, доступ появляется к сайту, и я возвращаюсь в чат.
П: Приношу Вам извинения за доставленные неудобства. Напишите, пожалуйста, дату последнего платежа по данному лицевому счету.
П: Спасибо за ожидание. Лицевой счет N 1234567890 успешно присоединен.
Мы прошли квест за 45 минут. Хотя могли бы сделать это на сайте в один клик. Эту функцию на сайте надо либо удалить, либо доработать. Вообще, личный кабинет уже давно бесполезен. Там нельзя прикрепить счёт, нельзя сменить тариф, нельзя сменить режим оплаты и, наверняка, ещё много чего. Всё делается только по звонку или в чате (спасибо хоть на этом). Какой стыд приоритизировать такую поддержку. Даже банки уходят от этого.
Мобильные приложения
Рокетбанк
Рокетбанк – неплохой банк. Хорошая поддержка, что характерно для большинства интернет-банков. Но почему-то меня постоянно преследуют какие-нибудь баги.
При оплате квитанций ЖКУ по реквизитам (с помощью QR-кода) сходу не найдёшь кнопку подтверждения операции. А её просто нет. Чтобы она появилась, надо сделать несколько специальных движений:
Кнопка перевода денежных средств появится в правом верхнем углу. Для появления кнопки ещё можно стереть и заново ввести сумму. В банке о проблеме знают. Пока не исправили.
Другая проблема тоже связана с платежами по реквизитам. На изображении ниже я совместил 2 скриншота. На левом оплата квитанции по реквизитам. На правом – создание автоплатежа по той же самой квитанции.
А проблема в том, что в настройках автоплатежа нет кнопки с «запятой». Нельзя запланировать автоплатёж для вещественного числа. По-моему, это странное различие. Выглядит как баг. Банк уже в курсе моего пожелания (или бага), но за 2 месяца ничего не сделал.
Уже 2-й месяц подряд я захожу в автоплатежи (где-нибудь в конце месяца) и обнаруживаю, что один из них достиг нужной даты и завис. Это было в декабре, повторилось в январе. Вот на днях уверяли, что точно исправили, поэтому полный обзор не делаю. Но обязательно вернусь, если снова не заработает.
Хабр – новостной сайт про информационные технологии, который уже много лет намеренно игнорирует тренд на популяризацию мобильных устройств для веб-серфинга. В мобильном приложении для iOS функционал сайта максимально урезан. Предложения не реализуются. Баги не исправляются. Вот некоторые из них:
Периодически в мобильном приложении всплывает предложение оставить отзыв в App Store. Любителей оставлять отзывы на что-либо обычно очень мало из общей массы пользователей. Особенно положительных отзывов. Как и в случае с товарами, люди склонны больше сообщать о проблемах. Так вот отказ от написания отзыва в приложении Хабр реализован очень интересно. Приложение вырубается. Это крэш или тролль – неизвестно. Но многие пользователи шутку не оценили и после десятка завершений приложения таки пишут отзывы, причём только негативные. Интересный маркетинг. В духе выражения «Дурная слава – тоже слава».
Вот несколько свежих отзывов об этом баге:
Ilyas Momynon: «Пока что сайт гораздо удобнее, а ещё приложение крашнулось после вопроса о том, нравится ли мне приложение и положительного ответа :D»
Neifmetus: «Уже 5-й раз на iPad выскакивает „оцените приложение“. 5-й раз хочу поделиться, чем не нравится – крэш. Хорошая защита от негативных отзывов, но если бы вы это раньше починили, я бы вам в вашу кастомную форму написала. А раз вы чинить не хотите – ловите мало звёзд в стор. Цветовая гамма у приложения неприятная и полоска с новостями и не доходит до края экрана — бесит»
Daemon100: «Хорошо, но приложение падает каждый раз на предложение „Нравится приложение?“ отвечаешь „Да“, а затем на предложение оставить отзыв в App Store отвечаешь „Нет“.»
И это только за последний месяц и только про этот баг.
Почитав отзывы в App Store, я встретил много знакомых багов и хотелок, которые поддерживаю. Но вот один баг с поиском я не встречал и решил его повторить. Выглядит так:
Действительно. При поиске по фразам на кириллице Хабр выдаёт всякую дичь.
Связь с поиском ошибок в коде
Появление описанных проблем и ошибок имеет определённые причины. Это недочёты в процессе разработки программ, а также в организации работы сотрудников в целом. От написания кода до доставки приложения пользователю проходит несколько этапов.
Выявленные проблемы – это, в первую очередь, допущение отделов тестирования. В крупных компаниях это обычно большие команды, занимающиеся только тестированием. Но их эффективность может страдать от разных факторов.
Один из важных факторов, ухудшающий работу тестировщиков, – ошибки, которые можно было исправить ещё на этапе написания кода. Обработка найденных багов отнимает время нескольких людей. Но некоторые из них могли бы и не дойти до тестировщиков, что, в свою очередь, сэкономило время тестировщиков. Они бы потратили его на более продуктивное и высокоуровневое тестирование.
Так, наша команда разработчиков анализатора кода PVS-Studio продвигает методологию статического анализа. Это этап разработки программного обеспечения, который стоит перед передачей приложения в отдел тестирования. По нашему опыту, большинство ошибок являются недочётами этапа разработки. И их можно исправить на раннем этапе, сэкономив время и деньги.
К сожалению, в отличие от программ с открытым исходным кодом, тут у меня нет возможности самостоятельно проверить код на наличие ошибок. Но если код написан на C, C++, C# или Java, то этим командам было бы полезно зайти на сайт, скачать анализатор и прогнать его на своём коде. С помощью этого инструмента делается серьезный вклад в программы с открытым исходным кодом
Заключение
Работа с отзывами пользователей — одна из точек роста для программного продукта. Растёт продукт – растёт бизнес. Я думаю, многим компаниям стоит пересмотреть работу отделов тестирования и поддержки.
Как я уже сказал вначале, используемых мною приложений и сайтов очень мало от общего числа продуктов в этой индустрии. В принципе, это всё, что накопилось за последний год. Если вас беспокоят какие-то баги, то вы можете написать мне. Попробуем воспроизвести их и привлечь внимание разработчиков.
UPD 1: Хабр для iOS более не поддерживается, если кто не знал…
UPD 2: Проблему на сайте ОнлайнТрейд исправили после публикации.
Типы багов: этимология и энтомология
1. Немного этимологии и энтомологии
Давайте посмотрим попристальней на такое знакомое и (до боли?) родное слово БАГ. Происходит оно от английского слова Bug, означающего «насекомое». Есть еще много сторонних значений, в частности английское выражение «to go bugs» — сойти с ума, что легко кореллируется со вполне русским «тараканы в голове завелись». Также вспоминаются и «жучки на линии» (тоже, кстати, по-английски – bugs). И опять мы пришли к насекомым.
Еще в 1878 году, Томас Альва Эдисон (да-да, тот самый!) в письмах к своему соратнику Пускасу писал: «It has been just so in all of my inventions. The first step is an intuition, and comes with a burst, then difficulties arise — this thing gives out and [it is] then that ‘Bugs’ — as such little faults and difficulties are called — show themselves and months of intense watching, study and labor are requisite before commercial success or failure is certainly reached». Тем же словом, инженеры называли и сбои радарной электроники во время второй Мировой Войны. Конечно, более распространена история о том, что в 1946 году разработка компьютера Марк-2 (Mark-II) были приостановлена из-за сбоя его функционирования, вызванного попаданием мотылька между контактов. Трупик мотылька был извлечен и приклеен к отчету липкой лентой с комментарием «First actual case of bug being found.» («Первый реальный случай нахождения жучка»). Как нетрудно догадаться, примерно оттуда же «растут уши» и слова «дебаггер» (debugger) – буквально «избавитель от жучков».
2. Виды багов.
Простейший (не как инфузория-туфелька, а самый простой для понимания, модно сказать «классический») баг – это несоответствие между ожидаемым результатом (ОР) и фактическим результатом (ФР). Разберем это на примере:
Действия | Ожидаемый результат | Фактический результат |
---|---|---|
Ввести в ячейку выражение «=2+2*2» (без кавычек) и нажать ENTER | 6 | 8 БАГ. |
(это, кстати, реальный баг старого Microsoft Excel – он не учитывал приоритета математических операций, по которому умножение имеет высший приоритет по сравнению со сложением)
Все просто. Ждем одно – получаем другое. Баг.
Я не буду перечислять все подвиды бага классического – от опечаток в данных и опечаток в коде до бесконечных циклов, от использования оператора присвоения вместо оператора проверки равенства до использования неинициализированной переменной, от состояния гонки (race condition) в мультипоточных приложения до переполнения буфера, и так далее, и тому подобное – все это достаточно обыденные и ясные явления. Обратимся к малознакомой экзотике.
2.1. Гейзенбаг (Heisenbug)
Баг, названный в честь Гейзенбергского Принципа неопределенности – концепции квантовой физики. Простым (хоть слово «просто» здесь и не очень применимо) примером подобного бага будет являться ошибка, проявляющаяся, когда программа запускается на исполнение в рабочей среде, но исчезающая, когда программу запускают в дебаггере.
2.2. Борбаг (Bohrbug)
Тип бага, названный так в честь атомной модели Бора. В противоположность Гейзенбагу, он проявляется постоянно при одном и том же стечении обстоятельств. Вопрос в том, что весь набор обстоятельств бывет невозможно (или очень трудно) отследить.
2.3. Мандельбаг (Mandelbug)
Назван в честь Бенуа Мандельброта, внесшего огромный вклад в теорию фракталов. Мандельбагами называют ошибки, чьи причины настолько сложны и неясны, что фактически кажутся хаотичными и не поддающимися описаниями. (ключевое слово «кажутся»). Подобное, может быть вызвано, например, медленной реакцией системы – то есть ошибка уже произошла, но об этом вы узнаете только через некоторое время, что сильно затруднит локализацию причин.
2.4. Шрединбаг (Schroedinbug)
Шрединбаг назван в честь известного парадокса с кошкой Шредингера (или эта несчастная животина – кот?). Он заключается в том, что кто-нибудь читает код программы (работающей уже некоторое время) и восклицает «Да этого не может быть! Она просто не может функционировать!», после чего программа прекращает свое функционирование пока данная ошибка не будет исправлена. Будучи, казалось бы, абсолютно фантастической, данная ошибка попадается в реальности – спросите знакомых ветеранов- разработчиков, они подтвердят. Хотя, конечно, последующий анализ, как правило, позволяет отнести ошибку к разделам 2.1, 2.2 или 2.3, это удается не всегда.
2.5. Фазы луны
На самом деле такой ошибки не существует – это популярная отговорка тех, кто не хочет (не имеет желания и/или времени) разбираться в сложных причинах возникновения ошибки. Тем не менее, в истории существует пара примеров, когда ошибки возникали буквально из-за фаз луны. Я не буду приводить здесь эти истории, надеясь, что никому из нас не придется работать со столь сложными устройствами. Тем не менее, в любом случае, хотелось бы предостеречь всех от неосторожных умозаключений и попросить быть более внимательными, настойчивыми и скрупулезными в своей работе.
2.6. Статистический (более известный как количественный) баг
Баг возникающий при произведении программой большого количества каких-либо действий. Примером данной ошибки может служить запуск программы, которая должна равномерно расположить на плоскости некоторое количество точек. Если, например, при большом количестве точек программа не только неправильно располагает их, но и норовит расположить все на одной стороне плоскости (при этом до определенного количества точек работая прекрасно) – вуаля, количественный баг.
2.7. Демонстрационный эффект.
Ну и конечно, известный всем, «эффект первого показа», не раз случавшийся и с вашим покорным слугой. Как только приходит пора показать, например, прекрасно функционировавший на тестовом стенде юнит, обязательно происходит что-то ужасное. Причны, как правило, тривиальны – пропуск «незначительных» тест-кейсов, невнимательность к деталям и неучтенные юз-кейсы. Опять же – будьте внимательней.
На этом я закончу краткий обзор багов, буду рад Вашим замечаниям и предложениям.
Как искать баги на фронтенде: 4 основных этапа
В этой статье я рассмотрю вопрос выявления и обработки ошибок, возникающих на фронтенде (браузер или web-view).
На фронтенде код JS выполняется в браузере. JavaScript не является компилируемым языком, поэтому всегда существует вероятность ошибки исполнения при непосредственном использовании программы. Ошибка исполнения блокирует код, расположенный после места ошибки, и пользователи программы рискуют остаться с нефункциональным экраном приложения, который можно будет лишь перезагрузить или закрыть. Но есть методы выявления ошибок и их безопасного сопровождения, позволяющие избежать таких ситуаций.
1. Средства языка JavaScript
Блоки try/catch
Функции, которые могут выполниться с ошибкой, оборачивают в блоки try/catch. Сначала программа пытается выполнить код в блоке try. Если по каким-то причинам выполнение кода сломалось, программа переходит в блок catch, где доступны три параметра:
Для разработчика главное то, что программа сможет продолжить выполнение после блока catch. Таким образом, взаимодействие с пользователем не прервется.
С помощью блока try/catch также можно вызывать собственные ошибки, например при проверке данных:
Наконец, можно расширить эту инструкцию еще одним блоком — finally, который выполняется всегда: и в случае, если в try не было ошибки, и в случае, если управление перешло в блок catch:
Иногда используют инструкцию try/finally (без catch), чтобы была возможность продолжать использование кода без обработки конкретных ошибок.
Событие window.onerror
Часто бывает полезно знать, что скрипт на странице сломался, даже если программа сломалась и пользовательская сессия закончилась неудачно. Обычно эту информацию потом используют в системах логирования ошибок.
У глобального объекта window существует событие onerror (использовать его надо аккуратно: в разных браузерах реализация может отличаться!):
Если разместить этот код в начале скрипта или подгрузить отдельным скриптом в первую очередь, то при любой ошибке ниже разработчику будет доступна подробная информация о ней.
Однако полная информация доступна только для скриптов, которые были загружены с того же домена. Если сломанный скрипт загружен с другого домена, window.onerror сработает, однако подробностей ошибки не будет.
Компоненты фреймворков
Некоторые JS-фреймворки (React, Vue) предлагают собственные решения по обработке ошибок. Например, React сможет отрисовать специальную верстку на месте блока, в котором произошла ошибка:
Фактически, компонент React оборачивается специальным компонентом, который обрабатывает ошибки. Это напоминает оборачивание функций с помощью конструкции try/catch.
2. Средства сборки проекта
Современные JS-скрипты, как правило, делаются транспилируемыми. То есть разработка ведется с использованием последних стандартов ES. А затем код разработчика с помощью сборщика проектов (такого как Webpack) преобразуется в код, который будет гарантированно работать в выбранном числе браузеров.
На этапе сборки код проверяется на верность синтаксиса. Незакрытая скобка или неправильное обозначение поля класса немедленно вызовут ошибку при сборке, и бандл просто не соберется. Разработчику придется сразу исправить такие ошибки, чтобы работать дальше.
Также сборщик может подсказать, что какие-то куски кода не используются при выполнении программы. Возможно, это натолкнет разработчика на мысль о более глубоком изучении кода, что косвенно может повлиять на выявление им новых ошибок.
3. Тестирование
Еще один способ не допустить ошибок в коде – тестировать его. Во фронтенде есть инструменты для эффективного использования юнит-тестов. Обычно используют фреймворки, такие как Jest, Karma, Mocha, Jasmine. Вместе с тестовыми фреймворками часто используют расширения, такие как Enzyme, React Testing Library, Sinon и другие, позволяющие обогатить тесты с помощью мокирования, функций-шпионов и других инструментов.
При поиске ошибок тесты в первую очередь полезны нагрузкой разнообразными данными, которые могут привести к ошибкам исполнения. Так, следующий код пройдет валидацию синтаксиса и сработает ожидаемо:
Однако он сломается, если подать ему неверное значение:
Этот код тоже проходит валидацию при сборке:
Однако он также сломается во время исполнения. После тестирования разработчик наверняка сделает дополнительные проверки:
Часто подобные ошибки возникают при получение данных от сервера (например AJAX-запросом) с их последующим разбором. Тестирование кода позволяет выявить и заранее устранить случаи, когда код может сломаться во время исполнения в браузере клиента.
4. Логирование
Допустим, мы предприняли все возможные меры по недопущению ошибок во время разработки и сборки проекта. Однако ошибки все-равно могут проникать в продуктивный код. Нам требуется как-то узнавать об их наличии и принимать скорые меры по исправлению. Просить пользователей открывать консоль браузера и делать скриншоты — не самый лучший вариант. Поэтому к проекту неплохо подключить логирование ошибок.
Смысл простой: на каждое событие window.onerror или в каждый переход исполнения кода в блок catch выполняется простой AJAX-запрос на специально выделенный адрес сервера, в тело которого кладется информация об ошибке. Далее потребуется инструмент, который быстро оповестит техподдержку и разработчиков о наличии новых ошибок и позволит эффективно работать с ними. Самый популярный из таких инструментов для фронтенда — Sentry.
Система логирования Sentry позволяет собирать, группировать, представлять ошибки в реальном времени. Есть сборки для разных языков, в том числе JavaScript. Проект предоставляет платный доступ с расширенными возможностями для бизнеса, однако можно попробовать его основные возможности на бесплатном тестовом аккаунте.
Подключать Sentry можно как непосредственно в HTML-файле, так и в компонентах, выполненных на одном из популярных фреймворков: React, Vue, Angular, Ember и других.
Для подключения возможностей логирования прямо в браузере в секции загружаем скрипт:
Далее в коде JS инициализируем:
Всё. Если и когда в коде ниже этой строчки произойдет ошибка, Sentry выполнит ее логирование. Логи будут записаны даже тогда, когда ошибка произошла по вине скриптов с других доменов:
Sentry имеет широкие возможности по анализу массива сообщений об ошибках и настройке уведомлений. Также возможна группировка логов ошибок по релизам вашего продукта:
С помощью Sentry в статистику можно передать контекст ошибки, например, информацию о клиенте, fingerprint, уровень ошибки (fatal, error, warning, info, debug), проставить теги.
Есть возможность записывать в статистику пользовательские события. Например, можно поставить на отслеживание изменение размеров окна браузера или совершение AJAX-запроса. Также у Sentry есть собственный виджет с окном обратной связи, которое можно показать пользователю при ошибке. Это даст дополнительную информацию для расследования обстоятельств возникновения ошибки.
Для развертывания Sentry вместе с фреймворками достаточно просто установить пакет и подключить:
Делаем инициализацию в главном скрипте проекта (для React и Angular):
Для Vue и Ember передаем еще одну обязательную строку конфигурации:
Пакет integrations устанавливается отдельно:
Для предотвращения конфликтов и дублирования информации при подключении нескольких скриптов в одном проекте Sentry позволяет создавать отдельного клиента для каждой инициализации логирования: