JavaRush /Курси /Модуль 4: FastAPI /Синхронізація міграцій у командах розробки

Синхронізація міграцій у командах розробки

Модуль 4: FastAPI
Рівень 7 , Лекція 7
Відкрита

Отже, ми плавно підійшли до ще складнішого, але дуже практичного питання — як синхронізувати міграції в командах розробки. Річ, що здається простою на початкових етапах, може перетворитися на справжній кошмар у великих проєктах, якщо її ігнорувати. Що ж, досить прелюдій — переходимо до справи.

Уявіть, що ваша команда розробників працює над великим проєктом, який включає безліч таблиць і моделей бази даних. Один розробник додає нове поле в таблицю users, інший змінює структуру таблиці orders, а третій взагалі вирішує додати нову таблицю products. Кожен із них створює свої міграції, працює локально, і все це виглядає досить невинно. Доки... доки ви всі не намагаєтесь злити свої зміни в основний репозиторій.

"Merge conflict in migration file" — одна з найненависніших рядків, яку можна побачити. А якщо до цього додати непорозуміння через різні версії бази даних на локальних машинах, тестових серверах і в production, то результат може бути катастрофічним.

Отже, синхронізація міграцій у команді — це не просто «гарна традиція», а реальна необхідність для збереження узгодженості проєкту.


Як зробити синхронізацію міграцій простішою?

1. Використання систем контролю версій для міграцій

Почнемо з основ. Усі міграції обов'язково мають бути у вашому репозиторії. Це очевидно, але давайте все ж зафіксуємо. Коли розробник додає нову міграцію, її потрібно закомітити й запушити в загальний репозиторій.

Як це виглядає на практиці?

Припустимо, розробник A додає нове поле в модель User і генерує міграцію:


alembic revision --autogenerate -m "Add last_login field to User"

Це створює файл міграції, наприклад versions/202310110101_add_last_login_field_to_user.py.

Потім він комітить його в Git:


git add versions/202310110101_add_last_login_field_to_user.py
git commit -m "Added migration for last_login field"
git push origin feature/last-login-field

Усі члени команди повинні витягнути ці зміни й застосувати міграцію у себе:


git pull origin main
alembic upgrade head

Так ми мінімізуємо проблеми, пов'язані з "забутими" міграціями.

2. Визначення порядку роботи з міграціями

Часто робота над міграціями йде паралельно, і це створює конфлікти. Наприклад, двоє розробників створюють міграції, не знаючи про наявність міграції один одного. В результаті Alembic бачить, що є два "батьки" для однієї й тієї ж міграції, і відмовляється їх застосовувати.

Що робити в такому випадку? Ваша команда має домовитися про наступний робочий процес:

  1. Перевірка перед створенням міграції. Перш ніж створювати нову ревізію, стягніть останні зміни з основного репозиторію і переконайтеся, що ваші локальні міграції в актуальному стані:
    
    git pull origin main
    alembic upgrade head
    
  2. Створення міграції. Лише після цього створюйте нову ревізію.
  3. Обов'язково тестуйте міграції! Застосуйте її локально й переконайтеся, що все працює як очікується. Ніхто не хоче бути людиною, що зламала базу даних.
  4. Пушення міграції в основний репозиторій. Комітьте й пуште вашу міграцію в загальний репозиторій.

Погляньмо на практиці. Припустимо, розробник B працює з таблицею Orders. Перед тим як створити свою міграцію, він виконує:


git pull origin main
alembic upgrade head

Після цього робить зміни, наприклад додає нове поле order_status, генерує міграцію і пушить її. Це вбереже нас від безлічі непотрібних конфліктів.


Робота з конфліктами міграцій

Навіть при грамотній організації процесу конфлікти міграцій неминучі, особливо якщо проєкт активно розвивається. Як бути?

Уявіть, що у вас є такі міграції:

  1. versions/202310110101_add_last_login_field_to_user.py (розробник A)
  2. versions/202310110102_add_order_status_field_to_orders.py (розробник B)

Коли ви намагаєтесь застосувати міграції, Alembic скаржиться, що в них два різні "батьки".

Alembic дозволяє вказати, що одна міграція має бути "дитиною" двох міграцій. У цьому випадку створюється так звана "merge-міграція".


alembic revision -m "Merge migrations 101 and 102" --head <head_one> --splice

Наприклад:


alembic revision -m "Merge migrations add_last_login_field and add_order_status_field" --head 202310110101 --splice

В результаті буде створено новий файл міграції, який об'єднує обидва шляхи.


Автоматизація міграцій у CI/CD

Автоматизація — ваш найкращий друг, особливо в великих проєктах. Замість того щоб змушувати розробників вручну застосовувати міграції в кожному середовищі, налаштуйте процес так, щоб це робилося автоматично під час деплою.

Налаштування в CI/CD

На етапі розгортання додайте команду, яка автоматично застосовуватиме міграції:


alembic upgrade head

Якщо ви використовуєте GitHub Actions, крок виглядатиме приблизно так:


- name: Apply Alembic migrations
  run: |
    alembic upgrade head

Це гарантує, що на staging і production завжди актуальна структура бази даних.


Важливість домовленостей у команді

Технічні інструменти хороші, але нічого не працює, якщо команда не дотримується правил. Ось кілька порад:

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

Складні кейси і як їх вирішувати

  1. Проблема: різні версії бази даних на локальних машинах і серверах

    Найпростіший спосіб уникнути цієї проблеми — автоматизація. Налаштуйте процес так, щоб база даних у Docker завжди містила останню версію. Наприклад:

    Dockerfile

    
    CMD alembic upgrade head && uvicorn app:app --host 0.0.0.0 --port 8000
    
  2. Проблема: пропущені міграції

    Додайте перевірку в CI/CD, яка порівнює поточний стан моделей з останньою застосованою міграцією. Для цього можна написати тест з використанням Alembic:

    
    from alembic.script import ScriptDirectory
    from alembic.config import Config
    
    def test_migrations():
        alembic_cfg = Config("alembic.ini")
        script = ScriptDirectory.from_config(alembic_cfg)
        assert script.get_heads(), "There are unapplied migrations!"
    

Використовуйте ці підходи, щоб підтримувати узгодженість міграцій у вашій команді. Робота з базою даних у команді може бути безболісною, якщо слідувати найкращим практикам і трохи автоматизувати рутину. Побачимось на наступній лекції!

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ