Чёрный экран смерти в Тяжеловато, отчёт об инциденте

25 ноября в 9:10 по Московскому времени вышло обновление приложения Тяжеловато для iOS под версией 1.2.

Релиз привёл к поломке, из‑за которой пользователи в течение полутора суток не могли пользоваться приложением. Приложение открывалось на телефонах, но показывало чёрный экран и не реагировало на жесты и перезагрузку.

Устранить проблему полностью у нас не получилось.

26 ноября в 9:05 было подготовлено обновление с частичным исправлением.
В 19:42 оно стало доступно пользователям в магазине.

Предпосылки

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

Для сохранения веб‑версии офлайн на телефоны пользователей мы использовали AppCache. Когда появились оболочки, кодовая база у веб‑версии и версий для магазинов осталась одна. В одной из первых версий мы допустили ошибку — AppCache‑манифест попал в сборку для магазинов по недосмотру.

Мы удалили AppCache‑манифест и ссылки на него в патч‑обновлении, следовавшем сразу после первой версии.

Недавнее обновление веб‑версии и перевод её с AppCache на ServiceWorker прошли гладко. В обновлении для Android «чёрных экранов смерти» также не появлялось. Тестовая сборка приложения в TestFlight и переход на ней между версиями также не показывали подобных проблем.

Из всего этого мы сделали предположение, что обновление для iOS должно было пройти гладко.

Хронология и анализ

25 ноября в 9:10 по Московскому времени мы запаблишили обновление в AppStore. Обновление должно было использовать старую кодовую базу, а после нажатия кнопки «Сохранить бюджет» — обновить ядро приложения и перейти на новую.

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

В 9:33 мы сделали первое предположение о причине проблемы. Гипотеза заключалась в особенностях работы закэшированных ресурсов, и том, что после обновления мы отказались от использования AppCache, но неправильно очистили кэши после первого обновления.

В 10:06 после разговора с пользователем, который непосредственно пострадал от последствий, гипотеза подтвердилась. Мы начали думать над тем, как исправить ситуацию. Почистить кэши принудительно мы могли только с помощью нативной оболочки.

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

К 20:21 исправление было протестировано на разных версиях iOS и под разными устройствами. Проблема, казалось, была решена и подготовили обновление к релизу в AppStore.

26 ноября в 0:37 после более тщательной проверки выяснилось, что обновление всё‑таки проблему не решает. Принудительное очищение кэшей в оболочке срабатывало не стабильно.

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

В 8:43 мы решили больше не рисковать и помочь пользователям обновить приложение вручную.

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

Инструкция «Что делать дальше»
Экран позора — инструкция «Что делать дальше»

В 9:05 обновление было готово к релизу.

В 11:17 исправление было отправлено в магазин.

В 18:02 приложение прошло ревью магазина.

В 19:47 исправление стало доступно пользователям.

В 19:51 появилось первое сообщение от пользователей, что чёрный экран смерти пропал.

Текущий статус

Свежая версия работает в штатном режиме.

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

Выводы и работа над ошибками

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

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

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

Также ошибкой было считать, что обновление не содержало “breaking changes”. По принципу «Сделать всё за пользователя» переход между версиями технической базы я решил сделать плавным и незаметным.

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

Болеть за продукт

Я, наверное, невероятно очевидную вещь сейчас скажу, но очень надо, ужизвинити.

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

Без веры в продукт задачи становятся просто какими‑то штуками, работать с которыми скучно, неинтересно, субъективно бессмысленно. Чё‑то там сбоку происходит, ну и ладно.

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

Но что делать, если не получается болеть?

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

А можно устать от продукта. Так бывает, люди меняются, всё нормально. Осознайте, насколько сильно просели мотивация и польза (вам и от вас) и примите решение, что делать дальше.

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

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

P.S. Я сейчас не говорю об аспектах, связанных с командой, комьютом, офисом, плюшками и проч. Речь именно о том, над чем вы работаете.

P.P.S. Примерно о том же, но гораздо подробнее, я писал во «Фронтенд — это не больно!».