Релизы не выходят точно в срок? Множество багов на регрессе? Сам регресс занимает несколько дней? Много жалоб на баги? Релизом занимаются сразу все и продуктовая разработка полностью останавливается? Узнали? Согласны?? Мне кажется, многие сталкивались с этим, в том числе и мы.

Всем привет, меня зовут Даниил, я — QA-лид в мобильном направлении hh.ru. Сегодня я расскажу, как из нестабильных и нерегулярных релизов мы пришли к классному и быстрому релизному процессу мобильных приложений. Наши релизы стали выходить раз в неделю, а число жалоб уменьшилось в разы. Еще расскажу, с какими проблемами мы сталкивались и как их решали.

Это текстовая расшифровка выпуска нашего влога, посему если вам удобнее смотреть, а не читать, добро пожаловать на наш Youtube-канал.

Хьюстон, у нас проблемы

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

  • Огромный и непредсказуемый набор фич

  • Заранее неизвестна точная дата выхода релиза

  • Долгий и полностью ручной регресс

  • Непрогнозируемая дата выхода новых фич

  • Интерфейс слишком сильно менялся от релиза к релизу

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

К чему мы хотим прийти

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

Также благодаря этому мы получим быстрый time-to-market и сможем планировать доставку той или иной функциональности до юзеров.

Предпосылки

Три года назад у нас было две небольшие платформенные команды: iOS и android + несколько QA, но также были планы и по увеличению числа разработчиков и тестировщиков. Если бы мы не начали решать перечисленные проблемы, все могло стать сильно хуже. Пока вас мало и вы находитесь рядом,  можно просто спросить друг у друга, что сейчас происходит с релизом, в каком он статусе и что в него попало. Но, если число команд растет и сами они становятся распределенными, то жить с хаосом в релизах становится намного труднее.

Будем решать проблемы

Проблемы понятны, цели поставлены, теперь можно попробовать их решить.

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

Дежурство

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

Github-flow

Затем мы решили разобраться, почему у нас в девелоп постоянно попадает что-то недоделанное или сломанное. Разобрались. Мы работали по так называемому “trunk-based development”, только в нашем случае это был грязный trunk-based. Мы никогда не тестировали то, что попадало в девелоп, а тестировали какой-то промежуточный вариант, например когда фича полностью сделана или пофикшено несколько багов. 

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

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

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

Автотесты

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

Мысли вслух

Тут хочу сделать небольшое отступление: может сложиться впечатление, что все эти процессные изменения и внедрение автотестов происходило моментально, быстро и безболезненно. Конечно нет. Переход на github-flow был долгим процессом, который постоянно улучшался, скоуп обязанностей дежурных постоянно пересматривается и изменяется. А написание автотестов — это вообще большая, сложная и долгая задача. Все было постепенно и размеренно.

Мы начали изучение подходов и фреймворков для написания тестов. В iOS мы остановились на XCUITests, в Android выбрали Kaspresso. Подробнее узнать о том, как выбрать фреймворк для автотестов мы рассказывали в серии наших видео про вопросы автоматизации.

Параллельно с написанием автотестов мы сразу же начали интегрировать их в наш CI. Мы используем build-сервер Bamboo — это инструмент из стэка Atlassian. Для параллельного запуска android-тестов мы используем утилиту marathon, а в iOS — нативные решения от xcode.

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

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

Кроме того, теперь обязательным условием попадания новой фичи в девелоп стали зеленые тесты. После того как тестировщик протестировал фичу, разработчик открывает pull request в девелоп и на этом pr запускает прогон тестов. Если все успешно — мердж, если нет, соизволь поправить. 

Таким образом мы сильно разгрузили тестировщиков, и добавили еще одну степень защиты нашего девелопа от нестабильности.

Release train, который смог

Итак, мы добились стабильного девелопа, но оставалась еще одна проблема — нестабильная дата релиза. Даже если мы договаривались об определенной дате, это вовсе не значило, что релиз выйдет точно в срок.. Постоянно поступали просьбы в формате “а подождите нас”, “ну пока там регресс идет мы еще докинем?” и так далее. Одной из причин таких просьб было отсутствие четкого понимания сроков следующего релиза. Если не попал в этот релиз, был риск прождать следующего слишком долго. 

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

Конечно, это всё равно оставалось лишь устной договоренностью Мы старались быть гибкими: вникать в отдельные ситуации и даже кого-то ждать. Но в целом всё шло к серьезному закручиванию гаек. В какой-то момент мы начали строго следовать релизному расписанию, и релизы стали уходить еженедельно без каких-либо задержек. Со временем нас вообще перестали просить подождать какой-то недоработанный функционал.

Подведем небольшой итог

Что у нас было: 

  • Большие и нестабильные релизы 

  • Отсутствие четкой даты релиза

  • Долгий регресс

  • Непонятный состав релиза

Какие практики ввели:

  • Github-flow

  • Автотесты

  • Дежурство

  • Релиз трейн

С помощью этого мы укротили хаос релизов, релизы стали регулярными и небольшими. Также существенно сократился и time-to-market.

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

Всю рутину релизов можно разделить на две части: техническая и менеджерская.

Техническая часть включает в себя следующие вещи:

  • Создать руками ветку релиза

  • Поднять там версию 

  • Собрать сборку

  • Запустить автотесты 

  • Выложить в стор 

  • Оповестить всех об этом 

Менеджер же во время релиза создавал страницу в Confluence, на которой указаны ответственный за релиз, состав релиза, даты выкладки в прод, прогона тестов etc.. Кроме того, нужно было заказать тексты для раздела “Что нового”, а у каждой платформы он еще и свой.

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

Как мы автоматизировали всё это добро и что из этого получилось, читайте в следующей статье.

Stay tuned!

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


  1. amedvedjev
    11.11.2021 16:18
    +1

    1) интересно сколько мобильных тестов вы гоняете регулярно в CI ?

    2) сколько всего сейчас мобильных тестов всего (ios / android)?


    1. Xanderblinov
      14.11.2021 14:31
      +1

      У нас два приложения в активной стадии разработки. Одно для соискателей (с которым все знакомы) уже довольно давно живет. В нём картина такая:

      • 390 iOS

      • 452 Android

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

      Гоняются и в ночных прогонах и на PR в develop абсолютно все тесты. Это стало возможным благодаря уходу от trunk-based — не нужно каждый чих проверять на стабильность


      1. amedvedjev
        14.11.2021 14:55
        +1

        О как. Интересно. Т.е. если в день 20 коммитов (в каждый репозиторий) то успеваете за день 20 раз все 800 прогнать. Я правильно понимаю?

        Если так - то мне нравится скорость ваших тестов!


        1. Xanderblinov
          14.11.2021 16:38

          Нет, не правильно поняли!

          1) iOS и Android в разных репозиториях, поэтому тесты гоняются для каждой платформы отдельно

          2) Ночные тесты гоняются на каждой фиче ветке и develop (на ветках разработческих не гоняем). Для ночного среза репозитория из примера(см картинку ниже) будет 3 прогона: 2 на больших фиче ветках и 1 на develop

          3) Также гоняются тесты при PR в develop. Таких моментов на диаграмме изображено 3

          Если просуммировать, то после 20 дневных коммитов может и не быть прогонов, если еще не настала ночь и мы не делали PR в develop. Так понятнее стало?


          1. amedvedjev
            14.11.2021 16:51
            +1

            Ну погодите. Да фичи делают дольше. Но баг фиксы и не большие изменения выкатываются часто в течение дня. У нас например недавно до 40 в день выходило. Сейчас поменьше 10-15 для каждой платформы.

            Мы делаем только ночные прогоны. Около 500 для каждой платформы. И только если надо в течение дня (девы и сами умеют запустить. Не все правда).

            В релизах уже на полные 800 -) разгоняем.

            Прогон 500 тестов занимает около 2 часов. Андроид чуть быстрее. Поэтому все все на каждый коммит в девелоп нам пока сложно по времени уложится.


            1. Xanderblinov
              14.11.2021 17:49
              +1

              У нас багфиксы умещаются внутри фичи. Дело в том, что тестирование фичей проходит в две стадии. Во время разработки QA обсуждает с разработчиком, что можно уже посмотреть, а куда лезть не стоит. Таким образом, когда фича начинает подходить к релизу QA начинает тестирование (пунктир на рисунке ниже). Перед тем, как влить фичу в develop, QA уже тестирует её и все, что можно задеть, капитально.

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

              Что касается времени прогона тестов и всех проверок — у нас есть вот такой вот дашборд:

              Сейчас пришли к тому, что прогон выполняется около 40 минут на Android и около 50 минут на iOS

              Чисто тесты проходят за минут 25 (взял рандомную ветку, поэтому число тестов отличается от того, что написал выше)

              И да, кстати я вас обманул в первом сообщении, на самом деле распределение по числу тестов наоборот:

              • 390 Android

              • 452 iOS


              1. amedvedjev
                14.11.2021 17:55
                +1

                Шикарная скорость! Нам чтобы ускорить надо до вас надо на 60 тредов перейти. У нас сейчас 25 реальных тел (12 iPhone, 13 Android).

                PS и да. Андроид у вас тоже чуть быстрее. Все совпадает.


                1. Xanderblinov
                  14.11.2021 18:38

                  У нас на iOS симуляторы, а Android вообще в k8s запускаем!

                  Интересно послушать, как вы с реальным устройствами справляетесь!

                  Мы на заре нашего UI тестирования пробовали, но не смогли добиться стабильности


                  1. amedvedjev
                    15.11.2021 16:43

                    Ну с реальными все просто. Я ведь фанат Аппиума. Один проект. Один код под обе оси. Просто манагерить. Ну и все равно на чем бежать, просто реальные телефоны проще, плюс часть функционала пашет только на реальных тел. iPhone проще - они примерно все похожи. Android выбрал Nokia - голый Android, дешевые.

                    Может надо тоже этот Kubernetes попробовать. Но его ведь надо локально подымать или запускать тесты рядом. Иначе сетевые задержки все сожрут.


      1. Xanderblinov
        14.11.2021 17:52

        Прошу прощения, в сообщении выше перепутал платформы. На самом деле у нас так на текущий момент:

        • ±390 Android

        • ±452 iOS


  1. onikiychuka
    12.11.2021 14:45
    +2

    #режим зануды включен

    Сори но ваш процесс разработки в ветках это не Github-flow. Github-flow это хорошо описанный легковесный процесс для разработки. Процитирую автора:

    Anything in the master branch is deployable

    • To work on something new, create a descriptively named branch off of master (ie: new-oauth2-scopes)

    • Commit to that branch locally and regularly push your work to the same named branch on the server

    • When you need feedback or help, or you think the branch is ready for merging, open a pull request

    • After someone else has reviewed and signed off on the feature, you can merge it into master

    • Once it is merged and pushed to 'master', you can and should deploy immediately

    То есть как минимум в нем просто не может быть релиз бранчей - тк master по сути и есть релиз бранч.
    #режим зануды выключен.


    1. Xanderblinov
      14.11.2021 14:24
      +1

      Спасибо, мне постоянно казалось, что называем неправильно — похоже мы изобрели hh-flow. Погнали патентовать????