Праздничные дни для Додо Пиццы — дни высокой нагрузки. К таким дням мы готовимся заранее и заводим специальные правила. Самое жаркое время — в декабре: много корпоративов, заказы становятся больше, но и прибыль выше. Во многих городах плохая погода — где-то снег только выпал и дороги не расчищены, где-то очень холодно. Всё вместе это создаёт нагрузку и на IT, и на бизнес. От нагрузки может сломаться что угодно: то очередь задач переполнится, то печь выйдет из строя. Чтобы быть готовыми, мы регулярно проводим нагрузочные тестирования, повышаем закупки ингредиентов, распределяем заказы по пиццериям и много чего ещё. Для мобильных разработчиков конец года раньше тоже был особенным: с 23 по 27 декабря App Store закрывался на рождественские праздники, приложения не проверялись, опубликовать что-то было невозможно. Расскажу, как эти ограничения влияют на разработку, какие ошибки мы совершили в прошлые годы и что меняется в расписании. Возможно, что-то из практик пригодится и вам: подсветит риски, поможет договориться о код-фризе с бизнесом. Так получилось, что прошлые декабри проходили у нас довольно стрёмно. Например, пару лет назад мы делали конструктор комбо и зарелизили его в в начале декабря. Оказалось, что фреймворк Dip переполнился от количества связей в DI и приложение стало очень долго запускаться. На новых телефонах это не было заметно, а вот на стареньких iPhone 5 и 6 оно даже не успевало стартануть за 30 секунд!  Мы подозревали, что DI может сломаться, но не подозревали, что это произойдёт так внезапно. Переделать описание всех зависимостей перед последним релизом сулило ещё большие потери, чем могли быть в тот момент. Подробно рассказывали об этом в статье «Бардак на старте: постмортем на скорость запуска iOS-приложения».  На следующий год мы сделали вывод и в начале ноября вспомнили, что надо проверить ключевые показатели заранее. Увы, даже это оказалось поздно для бизнес-планирования: в начале декабря должен был выйти крупный релиз сразу от трёх команд: в Сыктывкаре запускали заказ через приложение в ресторане, чтобы проверить бизнес-процессы. Отменить было нельзя, потому что маркетинг уже подготовил все активности; в Великобритании для пиццерии нового формата сделали другой флоу выбора адреса; начали оповещать пользователя о высокой нагрузке на пиццерию и предлагали сделать отложенный заказ. Фича хорошая — помогает бизнес-процессам и снижает негатив клиентов. Плохо было только то, что выпускали её в середине декабря — к этому времени она была очень нужна и был только один шанс зарелизить. Если в тестировании на продакшене оказалось бы, что в процессах пиццерии что-то идёт не так, то поправить уже ничего не смогли бы.  Вроде бы изменения точечные и касались региональных тестов, но поздний запуск сыграл против нас.  Во-первых, выяснилось, что пиццерия в Сыктывкаре находится в подвале и там плохо ловит связь, поэтому нужно было срочно менять способ загрузки изображений, экономить трафик и переходить с JPEG на более современный формат, что влияет сразу на все приложения. Без этого тестировать в ресторане нечего, приложение у людей совсем не показывает картинки и они не делают заказы.  Во-вторых, флоу Великибритании сильно влияет на старт приложения, хитро переиспользует существующие фреймворки, из-за скорости разработки решение получилось запутанным, в январе пришлось переписывать.  В третьих, визуализация нагрузки на пиццерию была написана в спешке и покрывала лишь самый простой случай, поэтому наше решение задачу решало лишь частично. В итоге тот релиз вышел не очень стабильный и в декабре мы выпустили аж три хотфикса, а потом ещё в январе доделывали и рефакторили.  Стало понятно, что начало ноября — слишком поздно для планирования. Про Новый год нужно думать в конце сентября, до начала четвёртого квартала. Давайте посмотрим на календарь и поймём, какие критичные даты у нас есть. Начнём с конца декабря. С 23 по 27 декабря нельзя релизить приложения в App Store, в Америке рождество. Apple заранее рассылала письма и предупреждала, что сроки сдвинутся. Для многих компаний Новый год — важное время, все хотят закончить свои задачи, а это значит, что неполная неделя с 20 по 23 будет сложной для ревьюверов и время на ревью может увеличиться. В этом году Apple перестала уходить на рождественские каникулы, тем не менее, ревью может быть медленнее обычного.  Это не изменило наши планы, нагрузка на пиццерии не зависит от Apple, но напряжение от сроков стало меньше. По статистике, каждый наш релиз требует хотя бы одного хотфикса. Значит, нужно на неделе с 13 до 15 декабря сделать последний релиз, чтобы успеть исправить, если что-то пойдёт не так.  Проблема не только в том, что мы иногда косячим, но и в том, что в мобильной разработке релизы катятся медленно и фидбэк с продакшена может прийти слишком поздно: если релиз раскатывается постепенно, то за неделю получим обновление у 40% людей; если релиз был открыт на 100%, то за неделю приложение обновится лишь у 70% людей;  через месяц обновятся только 90%, а оставшиеся 10% растянуты на годы, хвост старых версий очень долгий. Получается, что если мы хотим к Новому году закончить фичу и сразу запустить рекламу на неё, то, чтобы не нагружать саппорт вопросами «почему у меня нет такого функционала?», стоит раскатить нужный функционал хотя бы за 2-3 недели до запуска и спрятать его за фича-тоглом до нужного момента.  С другой стороны, если столкнёмся с проблемой, то остановить релиз тоже не получится: приходят новые пользователи и они всегда получают последнюю версию, даже если в ней есть проблемы. Есть и другие причины отодвинуть релизы подальше от конца декабря и праздников в январе: некоторые баги воспроизводятся только в редких ситуациях, за полторы недели пользователи достаточно повзаимодействуют с системой, чтобы можно было считать, что все критичные редко встречающиеся баги всплывут и будут исправлены до Нового года; некоторые проблемы с надёжностью могут иметь накопительный эффект и стрельнуть только при длительной работе под нагрузкой или без перезапуска серверов (как, например, медленное, но уверенное «выжирание» памяти или ЦПУ), поэтому важно посмотреть на работу системы вдолгую, прежде чем со спокойной душой уходить на каникулы; Если мы хотим, чтобы система прожила без нас полторы недели в январе, то давайте посмотрим, как она проживет полторы недели в декабре хотя бы без релизов. Исходя из этого, мы приняли несколько правил. С 1 декабря по 15 не должно выходить очень крупных изменений. Если изменений будет много, то за один хотфикс можно и не успеть всё поправить или изменения не дойдут до пользователя.  Все фичи, которые выходят в декабре, должны быть спрятаны за фича-тоглом и уметь отключаться. У нас есть механизм фича-тоглов, поэтому некоторый функционал можем отключать без релиза. В худшем случаем мы останемся без фичи, но люди смогут заказывать. Увы, некоторые изменения слишком дорого или невозможно тоглить, например инфраструктурные изменения (переход на Tuist). Получается, что зарелизить их нужно ещё раньше, чтобы успеть исправить до того, как начнётся декабрь и высокий трафик. Крайний срок больших изменений — середина ноября.  У бэкенда процессы немного другие: нет ревью от вендора, а обновление происходит сразу для всех, поэтому релизы можно катить чаще. В итоге наш график сейчас такой: 15 ноября — последний релиз инфраструктуры в мобильной разработке, когда не можем оттоглить наши изменения; 29 ноября — последний срок большого релиза, все фичи должны быть затоглены. Если нашли баг, то нужно срочно катить фикс; 6 декабря — последний мажорный релиз бэкенда; 13 декабря — последний возможный релиз небольшой фичи. До изменения режима работы App Store наш график релизов выглядел так, как на картинке выше. По нему видно, что с середины ноября мы не можем катить большие фичи, а это половина квартала. Такое очень важно учитывать при планировании: поменьше взять в работу, запланировать релиз важных фич пораньше. Релизить можно до 13 декабря, но размер и ценность релизов должны плавно снижаться, чтобы сохранять правильный темп, не торопиться, не косячить и в итоге не падать. Неожиданным оказалось то, что продать код-фриз бизнесу несложно: показываете риски, обсуждаете возможные потери, требуете от аналитиков прогноза по доходу от фичи, составляете risk-reward, планируете сроки и как-то быстро приходите к договорённостям.  На деле намного сложнее продать код-фриз программистам: появляются десятки вопросов, уточнений, что можно и что нельзя сделать. Релизы декабря лидеры направлений и SRE одобряют в ручном режиме. Покажу на примере. Команда хочет выпустить фичу, которая будет рассказывать о нашей новой программе лояльности и персональных акциях. Виджет должен появиться на экране меню и визуально изменения небольшие. Уточнив у разработчика, понимаем, что для добавления простой плашки пришлось переверстать весь экран меню (там накопилось теходолга, нужно было исправить), при этом мы добавили анимации на обновление экрана, а они могут конфликтовать и ломать приложение. Это старт приложения, т.е. критичный путь пользователя до заказа, и если что-то пойдёт не так, то мы заденем большую часть пользователей. Затоглить такой рефакторинг сложно, он только повысит шансы что-то упустить. По-хорошему такая фича должна чуть дольше «помариноваться» в dev-ветке среди тестировщиков и разработчиков. С другой стороны, мы рассказываем про бонусную программу. Это хорошо для возвращаемости клиентов, но не несёт прямого профита, эффект от фичи будет заметен не сразу. При этом времени у нас мало: чтобы закончить фичу, нужно отложить все остальные дела и, возможно, подключить другую команду. Не только придётся торопиться, но и поломать процессы, повысить напряжение и количество коммуникаций, что приведёт к меньшей стабильности. При этом релиз — не конец пути, могут быть ещё и хотфиксы, команда должна быть готова к этому, а не выжата под конец сезона. Хочется всё ровно наоборот: фича может зарелизиться, но только если мы всё сделали спокойно, контролируем и можем безопасно откатиться. Решение: не торопимся, фича выйдет в январе. Раз новогодние праздники — это время повышенных нагрузок, то нужно к этому подготовиться. Мы постоянно проводим нагрузочное тестирование для бэкенда, хотя бы потому, что пиковые дни в Додо Пицце случаются равномерно круглый год: 14 и 23 февраля, 8 марта, 1 и 9 мая, 1 июня, 1 сентября. Тем не менее, Новый год — продолжительнее. Сначала он даёт высокую нагрузку в декабре, а затем долгий период без релизов в январе, поэтому нужно уделить особое внимание тем местам, до которых обычно руки не доходят. Повысить качество сервиса Подумать о кейсах, которые могут всплыть при нагрузке на пиццерии. Например, заказы на отложенное время очень часто приходятся на обед, а это сверхнагрузки на производственную линию. Вместе с корпоративами и большими заказами комбо-наборов это может создавать лавинный эффект, мы не сможем или произвести, или доставить такое количество.   Узнать у саппорта о самых частых проблемах, разобрать кейсы, специфичные для Нового года. Так мы снизим нагрузку на поддержку и дадим им возможность обработать наплыв обращений.  Снизить нагрузку на процессы. Например, если везём заказ дольше часа, то дарим сертификат на следующую бесплатную пиццу. Недавно эти сертификаты стали электронным и теперь они не могут закончиться, курьер не сможет забыть его выдать — это просто больше не его задача.  Повысить прозрачность Построить дашборды, которые покажут потенциальные проблемы. Подчистить ошибки в логах, чтобы не отвлекаться на них в случае ЧП. Убрать старые тоглы, чтобы удалить код и «выпрямить» его. Возможно, так и проблемы покажутся.  Проверить места отказа Профилировать приложение по скорости и памяти, добавить трейсинг на важные места. Поднять crash free. Проверить безопасность приложения. Проверить старые версии iOS. Проверить сценарий недоступности бэкенда при высоком количестве заказов. Обработать недоступность пиццерий 1 и 2 января, когда заказ сделать нельзя.  Таким образом, все задачи делятся на два блока: либо повышаем качество наших проверок, либо готовимся к потенциальной нагрузке (и даже возможным падениям). Лучше перебдеть.  Подойти к задачам можно двумя способами:  если задач много и они важные, то стоит выделить общий спринт-«субботник», когда все команды берут задачи из бэклога подготовки к Новому году и сфокусировано разгребают его, не отвлекаясь на фичевые задачи;  если задач немного или они некритичные, то можно делать их в общем потоке, лишь сместив баланс фичи/теходолг в пользу второго. В мобильной разработке мы пошли вторым путём, а бэкенд временами устраивает субботник на пару дней. По расписанию последний релиз 13 декабря, затем две недели до Нового года мы ничего не релизим, а ведь в январе ещё пара недель праздников. Между релизами проходит месяц, за это время обратную связь от пользователей получить невозможно.  Если две недели все будут писать код и не будут его релизить, то после каникул у нас на продакшен поедет туча изменений, что резко повышает риск что-то сломать. За время каникул могут происходить инциденты, и хотфиксы, с ними связанные. С большой вероятностью придётся решать мёрж-конфликты не только с релизом, который был написан до Нового года, но и со всеми хотфиксами, которые уже на продакшене. После возвращения с каникул можно просто утонуть и запутаться в своём и чужом коде, который был написан в предпраздничном настроении. А уж если это придётся делать на инциденте после неудачного большого релиза... Для планирования сроков важно понимать, какое время поставки кода на продакшен.  Мобильные приложения у нас релизятся каждые пару недель, для них остановка релизов в декабре не будет заметна. Бэкенд релизится несколько раз в день. Для него простой в пару недель превращается в огромную проблему: изменения копятся, риски увеличиваются, миграции выстраиваются в ряд. Ком изменений может быть настолько огромным, что мы останавливаем разработку на этот срок. Не релизишь — не пишешь код.  Релиз-фриз бэкенда влияет на мобильную разработку: довольно мало фич, которые бы мы можем сделать на фронте без изменений бэкенда, поэтому тоже перестаём разрабатывать 13 декабря:  неделю мы оставляем для критичных фиксов; неделю не могли зарелизить из-за магазинов; вопросы про остальные две недели надо направить президенту РФ. Выходит, это целый месяц «ничего-не-делания». Или не совсем? Если не пишем фичи, то это не значит, что все уходим в отпуск (хотя отпуск — тоже вариант). Что можно делать в код-фриз: заняться инфраструктурой переводов, сборки или релиза; заняться дизайн системой и доступностью; учиться тестам, писать тесты, профилировать приложение; составлять или причёсывать бэклог; удалять лишние файлы с компа, открытые вкладки браузера прочитать и закрыть, заметки разобрать; писать запросы к аналитике, строить дашборды; проверять работу приложений на старых версиях телефонов; читать статьи, писать статьи, готовить презентации, снимать видео; проходить курсы, готовиться к ним или проводить их; опенсорсить фреймворки; придумывать идеи для 1 апреля и пробовать их. Чем ближе к Новому году, тем больше хочется отдыхать и развлекаться, поэтому в последние дни декабря мы уходим в отрыв и устраиваем хакатон. Конкурс проходит как в офисе, так и удалённо: все участники получают промокод на пиццу от компании, в случае победы подарки отправляются адресатам в разные города. Так в прошлом году мы попробовали написать App Clip. До релиза он не дошёл, но сделали прототип и поняли, как нам распиливать приложение. К App Clip мы ещё вернёмся! Весь четвёртый квартал у нас проходит в особом режиме: реального времени на разработку в два раза меньше, нужно заранее учесть задачи для подготовки к высокой нагрузке, а в середине декабря наступает код-фриз.  Основная цель всего этого планирования — чтобы всем было хорошо и спокойно: задачи делались в размеренном темпе и выходили вовремя, «нежданчиков» и горячки минимум, в декабре отличная прибыль, а в январе все отдыхаем и не выбегаем на работу по пейджеру. Многое из рассказанного — лишь заплатки на те процессы, которых пока нет на регулярной основе. Тем не менее, подготовка раз в год позволяет справиться с текущими проблемами.  Подписывайтесь на канал Dodo Mobile, я напомню о наступающем Новом годе в следующем сентябре.  Head of Mobile at Dodo Engineering