Тестирование кода в промежуточной среде перед выпуском в продакшен считается отраслевым стандартом. Это трудоемкий процесс, от которого в современном мире вполне можно отказаться в пользу тестирования в производственной среде, на реальных пользователях. В этой статье расскажем, какие практики нужно внедрить, чтобы этот переход прошел безболезненно. Это адаптированный перевод статьи Delete your Staging Environment из блога компании Flagsmith. Повествование ведется от лица автора оригинала. Короткое отступление: несколько месяцев назад наша платформа пережила сорокаминутный сбой API — первый за 18 месяцев. Обновление, которое стало причиной сбоя, прошло все автотесты и отлично работало в промежуточной среде. Это дало нам ложной чувство безопасности, из-за которого в результате пострадали пользователи. Причиной сбоя стало несоответствие в данных между двумя средами, которое привело к ошибке миграции базы данных. Это заставило нас задуматься: если через промежуточную среду проходят такие критические ошибки, зачем вообще она нужна? Задача промежуточной среды — дать командам разработки возможность безопасно тестировать обновления в условиях, близких к производственным. Кейс, описанный выше, показывает, что возможность упустить важную деталь существует всегда. Почему мы не тестируем код сразу в продукте? Я занимаюсь разработкой программного обеспечения последние 25 лет и за это время попробовал множество подходов. Почти во всех проектах промежуточная среда использовалась по дефолту: просто потому, что так принято. За это время произошел ряд изменений, которые позволяют отказаться от промежуточной среды. Сейчас совместная разработка — это отраслевой стандарт. Но давайте представим (а, точнее, вспомним) мир без систем контроля версий. В конце 90-х я работал в команде по разработке софта для USB-накопителей, и мы постоянно сталкивались с проблемой управления исходным кодом. За менеджмент процессов отвечал старший разработчик, задачей которого было объединить код программистов. Для этого он собирал код и запускал его в промежуточной среде для тестирования. Тестирование — ключевой этап сборки программного обеспечения перед развертыванием. Сейчас фокус смещается на тестирование в продакшене на реальных пользователях. На мой взгляд, важной вехой в этих изменениях стало  автоматизированное тестирование. Сегодня программисты вряд ли представляют себе свою работу без автотестов, хотя до появления Selenium в 2004 году модульные тесты были стандартом в индустрии. Автотесты позволяют нам сосредоточиться на качестве продукта для конечного пользователя, а не на совместимости отдельных компонентов приложения. Эта тенденция стала настолько массовой, что теперь в сообществе идут споры, стоит ли заниматься модульным тестированием. Простой при обновлении, к счастью, остался в прошлом. В 1999 году я консультировал крупного британского производителя кредитных карт, программное обеспечение которого работало на серверах Sun E10K. При развертывании новой версии ПО их инженеры ждали полуночи, заходили в серверную комнату, которая находилась в отдельном здании, физически отключали сервера от оптоволоконного кабеля и спустя три часа подключали их обратно. Во время этого процесса могло возникнуть множество ошибок, поэтому и речи быть не могло об обновлении ПО по несколько раз в день. Нулевой простой при обновлении ПО, которое выполняется регулярно, — это огромное достижение. Платформы Heroku и AppEngine сделали этот процесс достаточно надежным — настолько, что необходимость в промежуточной среде постепенно сходит на нет. Возможно, исторически последним изменением в практиках работы с кодом, которое избавляет от потребности в использовании промежуточной среды, стала возможность отделить деплой от релиза. Концепцию фиче-флагов популяризировал Мартин Фаулер: в своей статье он продемонстрировал, как они позволяют тестировать отдельные функции в производственных условиях. Концепция фиче-флагов сводится к тому, что вы тестируете новые функции в производственных условиях, но «прячете» их до тех пор, как они не будут готовы для релиза. Главное преимущество такого подхода в том, что весь код можно проверить в производственной среде, минуя промежуточную. Это самая точная проверка  работоспособности обновлений. Из этой концепции возникло множество новых — например, килл-свитчеры и A/B тесты. Существует пять основных инженерных принципов, которые необходимо реализовать, прежде чем избавляться от промежуточной среды. Даже если вы не готовы отказаться от нее, это полезные практики, от реализации которых вы получите массу пользы. Сейчас мердж-реквесты в GitHub и GitLab — критически важные этапы в процессе разработки. Они позволяют членам команды вместе анализировать код — до появления систем контроля версий взаимодействие такого уровня было невозможно. Написание основного кода приложения без промежуточной среды может показаться сложной задачей — ошибки могут привести к простою и потере денег. Практики анализа кода и парного программирования могут помочь справиться с этими опасениями. Если вы не уверены в своем коде, напишите его вместе с коллегой. Выпуск релизов несколько раз в день требует инструментов, которые позволят сократить количество ошибок в продакшене до минимума. Речь идет о покрытии тестами всего кода: модульных, сквозных, нефункциональных тестах, тестировании браузера и проверки системы на производительность. Фиче-флаги позволяют тестировать обновления в рабочей среде и сохранять контроль над выпуском новых функций при регулярном развертывании кода. Недостаточно указать Pingdom на один эндпоинт в API: необходимо мониторить весь стек в разных точках. Протестируйте значимые эндпоинты API, которые связаны с данных и любыми другими сторонними службами, на которые вы полагаетесь; Протестируйте нефункциональные свойства: задержку, нагрузку, общую производительность и портируемость. Для этого подойдет, например, DebugBear. Настройте систему оповещений об ошибках. Ошибки и сбои будут возникать всегда — вне зависимости от того, используете вы промежуточную среду или нет. Лучший способ сократить их число — введение постмортемов, практики фиксации ошибок. Орагнизовать ее лучше следующим образом: Проанализируйте причину появления бага после того, как его удалось устранить; Сообщите о результатах команде: расскажите, чему вы научились и как планируете использовать эти знания; Обсудите, как не допустить повторения ошибки в будущем. Это самая трудная часть — скорее всего, она будет состоять из комбинации нового кода, инфраструктуры и процессов. Отказаться от промежуточной среды проще всего, если у вас есть веб-приложение. Для этого есть несколько причин: Платформы для статистических сайтов (например, Vercel) хорошо интегрированы с git и позволяют быстро обновлять приложение и откатывать изменения, если что-то пошло нет так; Интерфейсные веб-приложения идеально вписываются в концепцию фиче-флагов: в первую очередь они предназначены для отображения и скрытия элементов пользовательского интерфейса; Как правило, интерфейсы не имеют состояния — если разворачивать их сразу в производственной среде, вы экономите время на трудоемкой задаче миграции баз данных. Еще один вариант — выбрать несколько наименее значимых функций и веток, которые не обязательно проводить через развертывание в промежуточной среде. На эту роль, например, подходят функции, которые отвечают за обновление резервной копии или изменяют стиль приложения. Стоит ли отказываться от промежуточной среды? Это зависит от объема работы, которую вы готовы проделать. Кроме того, важно, на каком этапе развития находится проект — чем раньше вы примете это решение, тем проще будет менять подход к выпуску обновлений.P.S: здесь можно, как устроено развертывание обновлений в Booking, который работает без промежуточной среды.