Владимир Синявский Инженер следующего изменения Каждое решение меняет цену следующего.

Протокол 002

Миграция на ощупь

Старую систему заменяют по частям, не останавливая прод.

Неделя 01 Прод

Три новых модуля сломались на одних данных

Отображение показывает пустой блок. Проверка ответа возвращает 500. Ночная выгрузка падает.

Контекст миграции

Это платформа онлайн-обучения, которая 10 лет росла как Rails-монолит. Новые запросы бизнеса всё чаще упирались в старую модель и растягивались на месяцы, но остановить сервис и переписать всё сразу было нельзя. Поэтому команда переносила прикладной слой в .NET по одному маршруту: переключённые запросы уходили в новую систему, остальные продолжал обслуживать Rails. База пока оставалась общей, поэтому новый код встречал те же поля, разные типы значений и исключения, которые за 10 лет накопились в старой системе.

Проблема проявилась в первую же неделю: пришли 3 отчёта об ошибках – пустой экран, HTTP 500 при проверке ответа и упавшая ночная выгрузка. Ошибки возникли в разных модулях и сначала выглядели не связанными друг с другом. Найдите их общий источник, затем выберите 2 первых рубежа миграции. Третий станет следующим дорогим изменением: каждый порядок переносит риск в другое место.

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

Что связывает 3 сбоя

  1. 01 Экран Тип задания listening_v2 → экран пуст
  2. 02 Проверка Тип задания mc_polyglot → проверка дала HTTP 500
  3. 03 Выгрузка Поле задания cues пришло как object → выгрузка упала
  4. 04 Источник 3 локальных парсера читают один kind + JSONB
  5. 05 Снимок данных 14 форм, ещё 13 расхождений

Доказанная причина

Форма данных из старой системы пересекла границу 3 раза. Новый код повторил её неопределённость.

Реальная хронология заканчивается доказанной причиной. Порядок решений ниже – архитектурный сценарий.

В каком порядке строить защиту?

Rails 65–70 маршрутов поведение не описано

Переключение

.NET 30 маршрутов поведение сверено

Все 3 действия обязательны. Первое изменит цену 2 следующих.

  1. Объём

    Ограничить объём

    Оставить в миграции только маршруты, которые блокируют развитие.

  2. Маршрутизатор

    Сделать переключение обратимым

    Переключать каждый маршрут отдельно и возвращать его в Rails одним изменением настройки.

  3. Сверки

    Зафиксировать поведение

    Сравнивать Rails и .NET на реальных входных данных и побочных эффектах.

Что поставить вторым?

Цена следующих действий появится после первого выбора.

  1. 1ПервоеНе назначено
  2. 2ВтороеНе назначено
  3. 3ПоследнееНе назначено

Ниже показаны все 6 порядков. При включённом JavaScript останется только выбранный результат.

6 порядков, 6 разных цен

Порядок изменений

Быстрые данные с прода

Первые маршруты переключаются до появления полного эталона поведения.

  1. 1 Ограничить объём
  2. 2 Сделать переключение обратимым
  3. 3 Зафиксировать поведение

Следующее дорогое изменение

Зафиксировать поведение

Сравнивать Rails и .NET на реальных входных данных и побочных эффектах.

Порядок изменений

Управляемое переключение

Данные с прода приходят позже, зато каждое расхождение уже объяснимо.

  1. 1 Ограничить объём
  2. 2 Зафиксировать поведение
  3. 3 Сделать переключение обратимым

Следующее дорогое изменение

Сделать переключение обратимым

Переключать каждый маршрут отдельно и возвращать его в Rails одним изменением настройки.

Порядок изменений

Ранние данные с прода

До ограничения объёма обе системы успевают поработать параллельно.

  1. 1 Сделать переключение обратимым
  2. 2 Ограничить объём
  3. 3 Зафиксировать поведение

Следующее дорогое изменение

Зафиксировать поведение

Сравнивать Rails и .NET на реальных входных данных и побочных эффектах.

Порядок изменений

Наблюдаемая, но широкая миграция

Эталон поведения строится для области, которую ещё не решили переносить.

  1. 1 Сделать переключение обратимым
  2. 2 Зафиксировать поведение
  3. 3 Ограничить объём

Следующее дорогое изменение

Ограничить объём

Оставить в миграции только маршруты, которые блокируют развитие.

Порядок изменений

Знание раньше трафика

Часть дорогих сверок отбрасывается вместе с маршрутами, которые решили не переносить.

  1. 1 Зафиксировать поведение
  2. 2 Ограничить объём
  3. 3 Сделать переключение обратимым

Следующее дорогое изменение

Сделать переключение обратимым

Переключать каждый маршрут отдельно и возвращать его в Rails одним изменением настройки.

Порядок изменений

Полная картина, лишняя работа

Причины расхождений понятны, но объём ограничивается последним и поэтому дорого.

  1. 1 Зафиксировать поведение
  2. 2 Сделать переключение обратимым
  3. 3 Ограничить объём

Следующее дорогое изменение

Ограничить объём

Оставить в миграции только маршруты, которые блокируют развитие.