Темы
Релизы · Миграции · Архитектура · AWS
  1. C1Только код

    1. Выкатить
    2. Проверить в продакшене

    Выкатить предыдущий артефакт

  2. C2Схема и данные, аддитивно

    1. Добавить поле
    2. Писать в оба
    3. Залить историю
    4. Читать новое
    5. Перестать писать старое

    Отменить последний шаг, до отмеченного

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

    1. За флагом
    2. Проверить
    3. Открыть

    Возврата нет. Проверять до того, как станет видно.

Одинаковое число шагов вперёд и три разные цены возврата. Отмеченный шаг — там, где вторая строка перестаёт быть обратимой.

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

00 / Что staging на самом деле доказывает

Staging доказывает, что изменение не ломается теми способами, которые вы додумались проверить. Это настоящий и полезный результат, и он меньше, чем кажется, потому что в staging нет ровно тех частей продакшена, из-за которых случаются интересные отказы:

  • объёма данных и того единственного арендатора, чьи данные устроены не как у всех;
  • конкурентности: живых пользователей, делающих что-то одновременно, с уже прогретыми кэшами;
  • интеграций в том состоянии, в котором они находятся сегодня;
  • клиентов в тех версиях, которые у людей действительно запущены.

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

01 / Три класса изменений, и дёшево откатывается только один

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

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

Не откатывается. Разрушительная миграция, ушедшее письмо, вызов чужого API, мобильная сборка, которая уже у людей в телефонах. Для них «откатить» — не план и никогда им не было. Работает другое: сделать изменение невидимым, пока оно не проверено. За флагом, в теневой таблице, в задаче, которая пишет туда, где пока никто не читает.

Большинство инцидентов, которые я видел в этой области, — это изменение из второго класса, с которым обошлись как с изменением из первого.

02 / Радиус поражения — до изменения, а не во время проверки

В SaaS для упаковочной отрасли, где я работал, фронтенд, бэкенд и мобильное приложение жили в разных репозиториях, у каждого был свой конвейер выкатки и свои окружения. Это хорошая структура: каждая часть выходит по своему графику. Она же кое-что прячет, и я это понял при проверке, а не при планировании: сходятся все они на одном слое данных, поэтому изменение общей схемы достаёт дальше того репозитория, который у вас открыт.

На практике это значит: до изменения ответьте на вопрос «что ещё это читает», посмотрев, а не вспомнив. Поле, которое вы удаляете из схемы GraphQL, запрашивают клиенты, которых выкатывали не вы. Веб-клиент чинится за полдня. Мобильный — нет, потому что версия в чьём-то кармане останется у человека, пока он не обновится, и тот, кто обновляется медленнее всех, определяет, сколько ваш бэкенд будет отдавать старую форму.

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

03 / Ночной релиз покупает окно, а не безопасность

Если клиенты собраны в одном часовом поясе, релиз вне их рабочих часов — дешёвое и настоящее преимущество, и доступно оно не всем. Но стоит быть точным в том, что именно он покупает: не меньшую вероятность ошибки, а только время заметить и среагировать до того, как это кого-то коснётся.

Время полезно, лишь если им кто-то пользуется. То есть до релиза нужно решить, на что вы смотрите в первые пятнадцать минут — тот самый запрос, тот самый график, тот самый экран, по которому видно, что миграция сделала задуманное, — и кто принимает решение.

04 / Абзац, который делает всю работу

Не регламент. Пять строк на изменение, написанных, пока вся картина ещё у вас в голове:

  1. Что меняется.
  2. Что ещё это затрагивает.
  3. Как мы проверяем в продакшене, что получилось.
  4. Как возвращаемся.
  5. Когда перестаём чинить вперёд и возвращаемся.

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

Конкретный вариант третьей строки, из миграции Node.js с 16 на 20 на том же продукте: проверкой было не «тесты зелёные». Проверкой был заранее определённый сценарий — завести арендатора, а затем сделать обычные вещи, которые делает клиент, — прогнанный руками по развёрнутой системе, потому что проблемы с зависимостями и рантаймом, которые та миграция породила, юнит-тесты не замечают.

05 / Что я бы выяснил перед следующим

  • К какому классу относится изменение, письменно, и где у него точка невозврата.
  • Что такое предыдущий артефакт и выкатывал ли его кто-нибудь намеренно хоть раз.
  • Самая старая версия клиента, которая ещё в ходу, и безопасно ли для неё изменение.
  • Одна проверка, доказывающая, что изменение сработало, и одна — что нет.
  • Кто не спит и что ему разрешено решать в одиночку.

Длинная версия проекта, из которого всё это взято — что диагностировали, что мигрировали и как выпускали, — описана отдельным кейсом.