Что может а что не может содержать миграция?



@kot999

Приветствую! Недавно возник вопрос про обработку данных в приложении. Поделитесь своим опытом, что вы в таком случае делаете.

1. Например нам нужно добавить какие-то данные в существующей таблице, предположим колонку, и на основании сложных вычислений (которые невозможно просто описать простым SQL запросом) проставить там данные. Для примера, представим, что нужно с помощью внешнего сервиса проставить — доступен ли email адрес пользователя который указан в его профиле.

2. Нам нужно запустить обработку всех картинок хранящихся на сайте, и сделать ресайз в новом разрешении (база даных вообще не участвует в этом случае, предположим).

Обычно я бы сделал это создав скрипт миграции, прокинул бы в него необходимые сервисы, при деплойменте скрипт бы отработал, в таблицу миграций была необходимая запись и цель была бы достигнута.
Но встретил непонимание коллег которые уверены в том, что единая ответственность миграций это вносить изменения в схему баз данных, а никак не в сами данные, и тем более уж не запускать какую-то обработку картинок которая к базе данных не имеет прямого отношения.
Во время дискуссии пришли к тому, что надо сделать CLI команду, которая бы запустилась один раз после деплоймента данных, внесла изменения и во время следующего деплоя ее выпилить, чтобы больше не запускалась, либо предусмотреть механизм как в миграциях — запись в таблицу информации о том, что команда уже запустилась.
Для меня это выглядит так, будто мы переизобрели механизм миграций, только назвали их не-миграциями.

У меня нет цели отстоять свою точку зрения, а скорее разобраться в вопросе. Как это принято делать у вас в проекте.
Разработка ведется на php, на одном из фреймворков. Но вопрос релевантен для любого стека.
Возможно есть статьи или книги которые описывают лучшие практики с вашей точки зрения, можете поделиться названием/ссылкой.
Спасибо.


Решения вопроса 1



@zoonman

Нормальная миграция подразумевает следующие характеристики:

  • идемпотентность — будучи запущена, серия миграций приводит к одинаковому результату
  • обратимость — любой шаг миграции можно откатить с откатом версии приложения
  • целостность — миграция переводит приложение из рабочего состояния в рабочее (баги не в счет)

Естественное применение миграций — это CI/CD. Т.е. в большинстве случаев ожидается минимальный простой приложения во время деплоя, именно поэтому миграции в большинстве своем изменяют структуры данных.
Но это совсем не означает того, что данные не могут быть изменены. Часто так бывает, что некоторые системные справочники требуют обновления или же данные пользователей требуют изменений. Например — для имени и фамилии использовалось одно поле, а теперь оно делится на два, как положено. Миграция данных в данном случае естественный и необходимый процесс, который может занять значительное время. Поэтому используется запланированный процесс выкатки приложения с его аннонсированием для пользователей. Запланированный даунтайм стандартная практика больших и сложных приложений, которые могут это себе позволить.
Если ваше приложение не может себе позволить остановку обслуживания пользователей, то для таких случаев пишется вспомогательный код, который делает обработку случаев немигрированных данных и вообще всевозможные костыли, лишь бы оно работало (основной источник гемора).

Является ли ресайз картинок частью миграции? И да и нет. Это зависит от ряда факторов — сломается ли приложение, если не будет картинки или будет старая картинка, это критичная функция или нет. Пример критичной функции — инстаграм.
Если дизайн приложения сделан правильно и функция второстепенная, то миграция происходит лишь на уровне БД, а сам ресайз на уровне приложения (скрипта во время выкатки). Пример — новый размер юзерпика, никто не умрет, если он будет больше или меньше, может выглядеть не очень какое-то время, но в конце концов он станет нормальным. Если для нового размера добавляется новый столбец, то в него во время миграции копируются данные из другого столбца, чтобы не рушить функционал.

Итак, мои ответы по вашим вопросам (как бы делал я):

  1. Добавил бы миграции с внесением/удалением 2 новых столбцов. Первый для email, второй email_verified. После развертывания запустил бы скрипт верификации почты (ох нескорый и ненадежный этот процесс). По-хорошему, по первому логину просил бы проверить и верифицировать email путем отправки кода на него. Думаю, вы уже поняли, что мы попадаем в серую область того, что машинная проверка здесь неуместна. Но допустим, мы использовали машинную верификацию, все проверили, все нужно сделали. В следующей версии мы удаляем столбец email_verified.
  2. Как правило, такие вещи данные в БД не изменяют, а значит нет необходимости в миграциях, достаточно скрипта. Но, если вы ок с простоем приложения, то можно вполне внести данный скрипт в миграцию, а также не забыть об откате этой миграции (удалять новые размеры, к примеру).

Как мы все видим, миграцию можно рассматривать, как в контексте СУБД, так и в контексте приложения в целом.
Общепринятая практика — рассматривать миграцию в контексте баз данных. Все остальное — скрипты и костыли в самом приложении.

Универсального рецепта нет. Все завязано на бизнес-логику и реализацию кода приложения. Если нельзя отделить сложную обработку данных от процесса деплоя, то эту логику следует встраивать в код миграций. Пример такой обработки — получение какого-нибудь системного идентификатора, который используется при работе приложения, например ротация API ключей при смене системы аутентификации.



2

комментария


Ответы на вопрос 4



@vitaly_il1

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



@Adamos

Важное свойство миграций — их обратимость, возможность откатить изменения и получить то же самое состояние сайта, как было до.
С дополнительной колонкой и seed-скриптом, который подсчитает ее значение для уже существующих записей, все нормально. Откат миграции ее просто удалит вместе со всеми этими значениями.
Потом вы, возможно, что-то доделаете и примените ту же миграцию снова. Миграция — не одноразовый скрипт.

А вот переваривание картинок вы хрен откатите. Так что к миграциям оно никакого отношения не имеет, это именно одноразовый скрипт.



@2ord

Миграции данных в СУБД и масштабирование изображений — это разные задачи. Следовательно, у каждой из них есть своя специфика.

1. В сценарии миграции на DSL фреймворка обычно описывал добавление колонки, затем
запрос типа SELECT id, email FROM users LIMIT 100 OFFSET :x. При получении списка компоновка список адресов в HTTP запрос на сторонний сервис и затем обновление колонки (тут есть некоторые особенности).

2. Это похоже не на переход из одного состояния в другое, а на сценарий подготовки при разворачивании веб-приложения. Мы ведь не пишем миграции для компиляции assets (webpack и пр.), так ведь?
То есть, в случае с изображениями мы не меняем состояния приложения. Оно каким было, таким и остается после запуска скрипта масштабирования. Один раз развернули приложение, получив нужные размеры изображения и все, этого достаточно. Когда выйдет новая версия, обновление уже не должно касаться повторного запуска скрипта — достаточно выполнить миграцию данных.



@saboteur_kiev

Миграция — это
1) изменение формата данных/таблиц
2) переезд на другой хост/версию, шард, когда данные куда-то переезжают.

В обоих случаях в зависимости от объема данных и критичности приложения, можно либо положить приложение на момент миграции, либо предусматривать воркэраунды в самом приложении.

А просто ресайз картинок в базе можно просто делать по живому, не аффектя приложения. Разве что если что-то касается верстки, можно в приложении сделать заранее проверку.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *