Ось урок на тему "Міграції бази даних", створений у стилі CS50: енергійний, зрозумілий і орієнтований на "чому", а не просто "як".
🎓 CS50: Міграції бази даних (Database Migrations)
Вітаю, друзі! 👋
Уявіть, що ми з вами будуємо хмарочос. Ми залили фундамент, звели стіни, провели електрику. Люди вже заселилися, живуть, варять каву, дивляться серіали.
І тут замовник каже: "Слухай, а давай перенесемо ліфт на іншу стіну і додамо басейн на 5-му поверсі?"
У будівництві це катастрофа. Вам доведеться виселяти людей і ламати стіни. Але в програмуванні ми робимо це щодня! 🏗️
Як змінити структуру бази даних, коли в ній вже є дані живих користувачів, не видаляючи все під нуль? Тут на сцену виходять Міграції.
1. 🔥 Вступ: Проблема та мотивація
Давайте чесно: коли ви тільки вчитеся, ви часто робите так:
1. Створили таблицю Users.
2. Зрозуміли, що забули додати поле email.
3. DROP TABLE Users (видалили таблицю).
4. CREATE TABLE Users (створили нову з email).
Це працює, поки ви один. Але уявіть, що це Facebook. У вас мільярд користувачів. Ви ж не скажете Цукербергу: "Марк, мені треба видалити базу на хвилинку, нехай усі зареєструються заново, бо я забув додати колонку для TikTok-посилань"? 😅
Питання до вас: Як нам змінити креслення будинку, не руйнуючи сам будинок?
Нам потрібен спосіб еволюціонувати схему бази даних крок за кроком. Нам потрібна історія змін. Нам потрібна "машина часу". Це і є міграції.
Без них будь-яка зміна на "живому" проєкті (production) перетворюється на рулетку: пощастить — дані збережуться, не пощастить — шукайте нову роботу.
2. 🧠 Теоретична база (без нудних лекцій)
Давайте заглянемо під капот. Що таке міграція фізично?
Це просто файл з інструкціями. Зазвичай він має дві частини (назвемо їх методами):
- ⬆️ UP (Вгору): Що треба зробити? (Наприклад: "Додай колонку
age"). - ⬇️ DOWN (Вниз): Як це скасувати, якщо ми помилилися? (Наприклад: "Видали колонку
age").
Це як Git, але для структури бази даних.
Як це працює?
Уявіть, що ваша база даних веде щоденник. У ній є спеціальна службова таблиця (часто називається migrations або alembic_version).
Коли ви запускаєте команду "оновити базу", програма дивиться в цей щоденник:
* "Ага, міграцію №1 ми вже робили."
* "Міграцію №2 теж."
* "О! З'явилася міграція №3, якої в мене немає. Виконую її!"
🔑 Що треба запам’ятати залізно:
- Міграції гарантують консистентність. У всіх розробників у команді буде однакова структура БД.
- Міграції мають бути зворотними. Завжди пишіть
DOWN, щоб мати шлях для відступу.
3. 🧪 Приклади: Від "Hello World" до реальності
Давайте подивимось, як це виглядає. Я буду використовувати псевдокод, схожий на SQL та Python, щоб ви зрозуміли суть, незалежно від мови.
Приклад 1: Початок (Initial Migration)
Ми створюємо таблицю користувачів.
Файл: 001_create_users_table
def up():
CREATE TABLE users (
id INTEGER PRIMARY KEY,
username VARCHAR(50) NOT NULL
);
def down():
DROP TABLE users;
Тут все просто. Ми створили світ. Якщо треба відкотити — знищуємо світ.
Приклад 2: Реальна потреба
Проєкт живе місяць. Маркетологи кажуть: "Нам треба знати, чи підписаний користувач на розсилку!". Треба додати колонку is_subscribed.
Питання до вас: Що буде, якщо ми просто додамо цю колонку? Яке значення буде у тих 1000 користувачів, які ВЖЕ є в базі? 🤔
(Пауза на подумати)
Правильно, NULL (пустота). А якщо нам не можна NULL? Нам треба значення за замовчуванням (DEFAULT).
Файл: 002_add_is_subscribed
def up():
# Додаємо колонку, і для старих записів ставимо FALSE
ALTER TABLE users
ADD COLUMN is_subscribed BOOLEAN DEFAULT FALSE;
def down():
# Прибираємо сліди нашого експерименту
ALTER TABLE users
DROP COLUMN is_subscribed;
Бачите? Ми не чіпали існуючі дані (username і id). Ми просто "прибудували балкон".
Приклад 3: Складний випадок (Data Migration)
Це рівень сеньйора. У нас була колонка full_name ("Taras Shevchenko"), а тепер ми хочемо розділити її на first_name і last_name.
Тут мало змінити структуру (схему), треба змінити дані.
Файл: 003_split_names
def up():
# 1. Створюємо нові колонки
ALTER TABLE users ADD COLUMN first_name VARCHAR;
ALTER TABLE users ADD COLUMN last_name VARCHAR;
# 2. Магія: переносимо дані (скрипт)
FOR user IN users:
parts = user.full_name.split(" ")
user.first_name = parts[0]
user.last_name = parts[1]
SAVE user;
# 3. Видаляємо стару колонку
ALTER TABLE users DROP COLUMN full_name;
def down():
# О ні! Треба повернути все назад
ALTER TABLE users ADD COLUMN full_name VARCHAR;
FOR user IN users:
user.full_name = user.first_name + " " + user.last_name
SAVE user;
ALTER TABLE users DROP COLUMN first_name;
ALTER TABLE users DROP COLUMN last_name;
4. 🛠 Практична частина
Час забруднити руки! Уявіть, що ви працюєте над інтернет-магазином.
Завдання 1: Ініціалізація
Напишіть (на папері або в редакторі) міграцію UP для створення таблиці Products (поля: id, name, price). Не забудьте DOWN.
Завдання 2: Забудькуватість
Ви забули додати поле "Кількість на складі" (stock_quantity). Напишіть нову міграцію, щоб додати це поле.
Завдання 3: Критичне мислення
У вас є таблиця Orders. Ви хочете змінити тип колонки order_id з тексту на число.
* Питання: Що станеться, якщо в базі вже є замовлення з id "ORD-555"? Чи пройде міграція успішно? Як це вирішити?
Завдання 4: Міні-кейс
Прийшов менеджер і каже: "Ми видаляємо функцію 'Відгуки' з сайту, вона нікому не треба".
Ви пишете міграцію DROP TABLE reviews.
Через тиждень менеджер біжить у сльозах: "Поверни все назад, клієнти скаржаться!".
* Питання: Чи допоможе тут метод DOWN? Чому? (Підказка: куди діваються дані при DROP TABLE?)
5. 💡 Мислення як у розробника
Ось що відрізняє новачка від профі в темі міграцій:
⚠️ Головна заповідь: Не змінюйте минуле!
Якщо ви вже "закомітили" (зберегли в Git) файл міграції і ваші колеги його застосували — ніколи не редагуйте цей файл. Якщо ви зробили помилку в міграції №5, не виправляйте файл №5. Створіть міграцію №6, яка виправляє помилку. Чому? Бо інакше у вас і вашого колеги будуть різні версії "реальності" під одним номером. Це пекло для дебагінгу.
🧠 Як думає сеньйор:
- "Чи безпечно це?" Чи не заблокує ця міграція базу даних на годину, поки вона виконується? (На великих базах додавання колонки може "повісити" сайт).
- "Чи можу я відкотитися?" Сеньйор завжди тестує
DOWNперед тим, як відправити код на сервер. - "Дані — це золото". Схема — це просто скелет. Дані — це плоть. Втратити схему не страшно, втратити дані користувачів — це кінець бізнесу.
6. 🧩 Підсумок
Отже, що ми сьогодні зробили?
- Зрозуміли, що база даних — це живий організм, який постійно росте.
- Дізналися, що міграції — це спосіб керувати цим ростом безпечно, як архітектор з кресленнями.
- Вивчили мантру: UP будує, DOWN рятує.
- Зрозуміли, що історію (старі файли міграцій) переписувати не можна.
Тепер ви вмієте: Не просто створювати таблиці, а керувати часом вашої бази даних. Ви можете рухати проєкт вперед і, що важливіше, безпечно повертати його назад, якщо щось піде не так.
🔜 У наступній серії: Ми писали SQL руками. Це круто, але іноді довго. На наступному уроці ми познайомимося з ORM (Object-Relational Mapping). Уявіть, що ви пишете звичайний код на Python/Java/JS, а він сам перетворюється на SQL-міграції. Магія? Ні, технології!
А поки що — спробуйте не "дропнути" базу! 😉 Це був CS50. Побачимось!