Если вы еще не читали первую часть, настоятельно советуем сделать это здесь!
Авторами этой статьи также являются Лукас Тальяни и Тейс Онофрио, так как мы недавно объединились в роли ведущего технического специалиста.

6. Разверните как можно больше
Чем больше мы вносим изменений в производство, тем меньше эти изменения будут. Если в нашем развертывании есть какие-либо проблемы, будет довольно легко определить, что вызвало проблему. Кроме того, при развертывании чего-то, что было недавно разработано, оно все еще свежо в нашей памяти, и мы помним весь контекст, связанный с этим.
Напротив, ожидание объединения нескольких дней работы для создания релиз-кандидата и развертывания его в рабочей среде будет включать в себя различные изменения, команда, скорее всего, не будет так хорошо помнить весь контекст этих изменений, и потребуются дни, чтобы получить обратную связь. о внесенном изменении.
По нашему опыту, раньше у нас был другой сценарий, развертывание в рабочей среде примерно раз в неделю. Мы начали постепенно менять это, поощряя команду чаще развертывать систему. Мы увидели, что ежедневное развертывание в рабочей среде повысило уверенность в наших выпусках. Мы быстро получаем отзывы о только что разработанном изменении и можем быстро откатить или деактивировать функцию, если она не работает должным образом, не влияя на другие функции. Кроме того, команда приносит пользу каждый день.
Чтобы увеличить частоту развертываний, мы использовали несколько методов, таких как: переход от сине-зеленого развертывания к канареечному выпуску, широкое использование флагов функций и включение A/B-тестирования.
7. Сине-зеленое развертывание
Когда вы работаете с тысячами пользователей одновременно, как мы, вы можете захотеть избежать простоев при развертывании.
Если вам нужно, чтобы ваше приложение было доступно при развертывании в рабочей среде, сине-зеленый может быть очень хорошей стратегией, чтобы убедиться в этом. Таким образом, вы можете поддерживать два маршрута — обычно называемые синим и зеленым — одновременно. Одна из них будет «живой» версией вашего приложения, которая будет доступна вашим пользователям. Другой маршрут будет «спящим» и обычно не будет иметь большой пропускной способности.
Нам нужно убедиться, что артефакт кода будет хорошо работать в производственной среде. Вот что происходит: мы развертываем новые выпуски на спящем маршруте, затем запускаем все тесты взаимодействия пользователя с ним, используя реальную среду, а не приложение внутри контейнера докеров, как мы делали на предыдущих шагах. Также важно помнить, что каждая среда будет использовать данные из разных источников. У него также будут включены различные флаги функций и, возможно, даже некоторые уникальные конфигурации A/B-тестирования. Если в наших тестах есть какие-либо сбои, задание по развертыванию тут же останавливается.
Это важная часть нашего процесса развертывания, которая помогла нам выявить проблемы, прежде чем продвигать изменения несколько раз в прошлом. Мы также проводим там ручное тестирование, прежде чем сделать неактивный маршрут активным. Как только все это сделано, и мы уверены, что все в порядке, мы просто нажимаем кнопку, и маршруты переключаются (спящий становится активным в то же время, когда живой становится бездействующим).
Кроме того, если после переключения маршрутов мы обнаружим проблему (например, через несколько часов), все, что требуется, — это «нажать кнопку», чтобы вернуться к неактивному маршруту, который был активен и стабилен до последнего релиза. Это проще, чем настраивать новый деплой, и вам действительно не нужно думать о том, какая была последняя рабочая версия, потому что она уже знает это.
Обратите внимание, что может быть разумным управлять экземплярами (горизонтальная масштабируемость) ваших маршрутов. Если ваш бездействующий маршрут не будет получать так много запросов, возможно, вы сэкономите деньги, если установите для него минимальное количество экземпляров.
8. Канарские релизы
Можем ли мы быть еще более осторожными при развертывании в рабочей среде? Да, мы могли. Канарские релизы можно считать следующим уровнем сине-зеленого развертывания для нас. Теперь мы можем не только развертывать неиспользуемый маршрут с помощью canary, но и выпускать его для наших пользователей понемногу.
Обычно мы определяем, что только 1% пользователей увидит новую версию в течение первых ~15 минут. Затем мы проверяли цифры и следили за диаграммами и журналами, чтобы увидеть, не привлечет ли что-нибудь негативное внимание к этому 1% пользователей. Если это произойдет, мы прервем развертывание. Если этого не произойдет, мы будем продолжать увеличивать количество пользователей, которые увидят новую версию нашего приложения.
Мы увеличиваем примерно до 5%, 15%, 30%, 50%, 75%… пока не достигнем 100%. Продолжайте смотреть на данные перед каждым увеличением.
Таким образом, даже если вы выпускаете версию своего приложения с проблемами, она будет видна меньшему количеству пользователей, чем при обычном способе развертывания в рабочей среде. У этого есть много преимуществ, таких как экономия ваших денег и предотвращение влияния проблем на всех ваших пользователей.
Если вам интересно, почему у него такое название, откройте эту ссылку, прокрутите до конца и проверьте Примечания.
9. Флаги функций
Флаги функций — важная часть того, что позволяет нам выполнять развертывание часто и уверенно. Этот метод позволяет нам функционально модифицировать производство без внесения изменений в код. Всякий раз, когда мы разрабатываем новую функцию или даже проводим большой рефакторинг, мы прячем код за флагом функции. Таким образом, мы можем безопасно объединять код, когда функция еще находится в разработке, зная, что это не повлияет на производственный код. Когда функция завершена, мы можем просто включить флаг.
Кроме того, с точки зрения бизнеса, функциональные флаги необходимы, когда нам нужно, чтобы функция или изменение функциональности заработало в определенную дату или время дня. Мы развертываем изменения кода ранее за флагом функции, а затем в указанную дату выпуска мы нажимаем кнопку, чтобы включить этот флаг функции, и изменение вступает в силу.
Поработав некоторое время с этой техникой, мы считаем важным помнить о некоторых вещах. Во-первых, тесты должны охватывать сценарии с включенной и выключенной функцией. Это единственный способ убедиться, что мы не меняем никакого поведения, когда флаг снят, и что мы добавляем правильное поведение, когда флаг включен.
Кроме того, флаги функций должны жить только до тех пор, пока они необходимы, поэтому важно их очистить. Удаление флагов функций, которые больше не используются, важно для уменьшения сложности кода и связанных с ним тестов. Каждая часть кода, на которую влияет флаг функции, может иметь двойную сложность, поскольку для ее условного выражения добавлен новый логический поток. Для этого мы начали писать карты, связанные с удалением флагов функций, как только мы их создаем, поэтому мы не забываем удалять код, который больше не нужен, и удалять флаги функций из любого используемого инструмента. для их создания.
10. А/Б-тесты
В чем-то похожие на флаги функций, A/B-тесты можно использовать для получения различных функций, которые можно активировать без развертывания. Однако вместо того, чтобы включать и выключать функциональность, с помощью A/B-тестов мы можем одновременно включать разные функциональные возможности, но для определенного процента пользователей. Например, мы можем изменить цвет кнопки, которая ведет к рекламным акциям, для определенного процента пользователей, и провести A/B-тестирование, чтобы выяснить, какой цвет кнопки чаще проходит через воронку продаж и приносит больший доход. Поэтому это ценно с точки зрения бизнеса.

Прежде чем решить, хотим ли мы выпустить новую функциональность, мы можем провести ее A/B-тестирование и выпустить для определенного набора пользователей на основе пользовательских атрибутов, а затем сравнить бизнес-показатели, чтобы определить ценность, которую функциональность приносит или не приносит. . С технической точки зрения мы не можем слишком привязываться к коду. По результатам эксперимента новый функционал может оказаться удаленным, и это совершенно нормально, и мы не хотим сохранять ненужную сложность в нашей системе.
Как и в случае с флагами функций, важно тестировать любые варианты A/B-тестов и не забывать очищать их, включив по умолчанию функциональность, выбранную на основе результатов тестирования.
11. Модель по вызову
Даже со всеми слоями качества, которые у нас есть в нашем процессе, плюс методы, которые мы должны использовать для выпуска нашего приложения, мы по-прежнему осознаем, что работаем с программным обеспечением, а это означает, что что-то неожиданное может произойти в любое время. Когда это происходит, независимо от времени суток, мы должны быть готовы и способны справиться с этим.
Учитывая, что мы большая команда, дежурные работают парами. Обычно мы пытаемся подобрать одного опытного разработчика к тому, у кого еще нет такого большого опыта. Мы делаем это как часть процесса адаптации. Важно убедиться, что не только опытные члены команды могут справиться или понять эти сложные ситуации. Кроме того, мы искренне верим, что два мозга лучше, чем один, для решения проблем, особенно в условиях стресса, связанного с производственной средой.
Вот как это происходит: всякий раз, когда мы сталкиваемся с инцидентом в продакшене, он инициирует телефонный звонок, SMS и push-уведомление двум разработчикам нашей команды одновременно. Затем они войдут в систему, рассмотрят проблему и решат ее вместе как можно скорее.
12. Наблюдаемость
Помимо всех других методов и инструментов, о которых мы упоминали ранее, для поддержания работающей системы в продакшене важна наблюдаемость. Это дает нам возможность устранять неполадки в нашей системе в случае возникновения инцидента.
Когда пара разработчиков находится на связи и получает вызов для решения проблемы, они должны иметь возможность быстро и легко выяснить, в чем проблема и как ее решить. Это стало возможным благодаря наличию хороших инструментов мониторинга, журналов и информационных панелей, которые очерчивают проблему и позволяют разработчикам найти основную причину. Таким образом, мы можем настроить оповещения на основе определенных вещей, таких как журналы, количество ошибок или пороговое время отклика, и автоматически вызывать разработчиков для поддержки.
Настроенные вами оповещения будут зависеть от вашего проекта и его потребностей. Например, мы внимательно следим за временем отклика и количеством ошибок как на стороне сервера, так и на стороне клиента. Если эти цифры внезапно превысят ожидаемые, мы получим предупреждение и сможем действовать быстро.
Выявление проблем в производственной среде имеет важное значение, но мы также должны иметь возможность наблюдать за нашими приложениями и находить тенденции до того, как они станут проблемой. Вот почему у нас есть привычка постоянно заглядывать в наши информационные панели и исследовать любое другое поведение, которое мы там видим. То же самое делается для более низких сред, чтобы мы могли обнаруживать любые проблемы до того, как артефакт достигнет других сред.
Это основные методы, которым мы следуем, чтобы избежать проблем в производстве. Это не значит, что их вообще не бывает, но мы сталкиваемся с меньшим количеством проблем, чем если бы у нас не было всего этого процесса.
Мы знаем это, потому что в прошлом сталкивались со многими из этих проблем, и с каждой проблемой мы могли адаптироваться и изучать новые методы, которые повышали надежность нашего приложения.
Кстати, это не высечено на камне. Мы продолжаем учиться, обновлять и улучшать наши практики.
Вы узнали все темы из этой статьи? Насколько отличается этот процесс в вашем текущем проекте? Планируете ли вы добавить один из них в свой текущий путь к производству? Не стесняйтесь комментировать здесь или отправить нам сообщение!