Для чего нужны миграции базы данных на проектах

Максим Лавриненко, директор по информационным технологиям 22.11.2019

TL;DR: Чтобы повысить качество и уменьшить риски.

Приведенный ниже подход используется при разработке веб-проектов на различных фреймворках. В качестве примера возьмем разработку на «Битриксе», потому что на нем делается очень много сайтов в России, «инфоблоки» на слуху, поэтому так будет понятнее, о чём идёт речь.

С точки зрения руководителя проекта со стороны заказчика, который немного подкован в администрировании Битрикс, задача, которая требует создания нового инфоблока и вывода информации из этого инфоблока в публичную часть, схематично решается в два шага:

  • Создание и настройка свойств инфоблока через интерфейс системы;
  • Разработка, подключение и настройка компонента в публичной части.

Однако, с точки зрения программиста, использующего современные подходы при разработке, практически что угодно «через интерфейс системы» имеет ряд существенных недостатков:

  • Отсутствие возможности быстро воспроизвести результат. При необходимости повторить настройку на другой копии сайта (например, на продуктиве), это придётся сделать вручную. Разработчик выполняет работу на своей отдельной инстанции сайта и автоматически изменения, сделанные в базе данных, на продуктивный сервер не попадут.
  • Как следствие — Риск ошибиться при повторных настройках. Забыл, что надо было где-то поставить галочку? Получи баг. Баг — негатив, отладка, потеря времени на исправление, а иногда и потеря данных.
  • Невозможность быстро отменить изменения. Вот мы, наконец, перенесли долгожданный функционал на продуктив, все настроили и вдруг обнаруживаем критичную проблему. Все надо отменить! В панике бросаемся в формы где настраивали изменения и пытаемся настроить все по старому. Велик риск ошибиться, что в итоге может привести к тому, что проблема полностью или частично останется, а так же в каких-то случаях будут возможны потери данных. В каких-то случаях просто невозможно быстро отменить изменения, потому что их внесение занимало долгое время, либо они по техническим причинам необратимы (например, в связи с тем, что после внесения изменений некоторые процессы что-то уже сделали с данными и эти изменения необратимы).

Но непосредственно программист — не один человек, делающий проект. Крупные проекты делаются усилиями десятков, а иногда и сотен разработчиков, и когда на проекте столько много голов, каждая может начать «тянуть» в свою сторону, с точки зрения технологий, подходов и других аспектов. Поэтому в дело вступает технический лидер команды проекта, осуществляя надзор над правками кодовой базы проекта — ревью. Но как ему убедиться, что изменения, сделанные в базу данных, корректны? Если их сделали вручную, то никаких «артефактов» этих действий не остается. И вот мы получаем ещё одну проблему:

  • Отсутствие адекватного контроля качества. Технический лидер проекта не может убедиться, что все сделано правильно. Да, ему могут рассказать и подготовить какую-то инструкцию. Но где гарантия, что в инструкции нет ошибки?

Что же делать? Писать миграции — код, который вносит нужные изменения в базу данных, а также позволяет их отменить.

  • Код говорит за себя и его качество можно проверить
  • Можно обеспечить воспроизводимость результата
  • Риск ошибиться уменьшается, так как действия начинает выполнять машина
  • Применение и отмена правок происходит одинаково

Ура! Наши проблемы решены, но мы решили даже те проблемы, которые сразу не было видно. Например:

  • Невозможность простой передачи наработок изменений в базе данных от одного разработчика к другому. Человек может заболеть, уйти в отпуск или банально «не справиться». Надо передавать другому разработчику. Нет миграций — передача осложняется. Можно повторить вручную (долго, риск ошибки), либо сделать бекап базы первого разработчика и развернуть его у второго. Но это время, да и к тому же у второго разработчика могут быть собственные наработки, которые при загрузке новой базы он потеряет и едва ли будет этому доволен — это потеря времени

В случае наличия миграции, проблема уходит — миграция=файл, а значит её легко сохранить в контроле версий и передать с помощью её возможностей.

  • Невозможность оптимизировать процесс внесения изменений. На первый взгляд кажется, что создание вручную через интерфейс — довольно быстрый процесс и все интуитивно понятно. На деле порой требуется выполнить много однообразных действий

Когда разработчик пишет миграцию, он может воспользоваться наработками и выполнить те же самые действия быстрее. А интуитивность программного кода для разработчика чаще даже выше, чем веб-интерфейс.

  • Десинхронизация между кодом и структурой базы данных. Представим, что мы меняем тип данных определённого поля и параллельно исправляем код, который работал с этим полем, чтобы он обрабатывал новые данные. Но что произойдёт, если мы загрузили новый код, но пока не изменили тип поля? Старый код не сможет обрабатывать новые данные, возникнет поломка. Если изменить тип поля, а уже потом код, то поломка возникнет между моментом, когда мы изменили тип поля, и загрузкой кода. К тому же может потребоваться изменить не только сам тип поля, но и данные, которые были в этом поле сохранены, — сконвертировать их. Определённые доработки могут требовать огромного количества изменений, и время поломки может быть долгим. «Но мы ведь можем добавить в код обработку и старой, и новой версии!» - скажет внимательный читатель. Верно! Но теперь наш код разросся, его стало сложнее читать и поддерживать. Можно «почистить» потом, но это тоже займёт время. И нет ничего более постоянного, чем временное. Чуть оставил «мусора» и появляется риск, что он останется в проекте навсегда. Чисто не там где убирают, а там, где не сорят.

В большинстве случаев миграции выполняются крайне быстро, проблема теряет актуальность.

Идеален ли этот подход? Как и все в нашей жизни — отнюдь. Он хорош, но порой может «потребовать» больше, чем отсутствие какого-либо подхода:

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

Наша практика показывает, что это несущественные недостатки.

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

Все статьи