Migration: การเปลี่ยนสคีมาอย่างปลอดภัย
สคีมาของคุณจะเปลี่ยนแปลงไปเรื่อย ๆ — คุณจะเพิ่มคอลัมน์ เปลี่ยนชื่อตาราง เพิ่ม index ลองนึกภาพว่ามันเหมือนการติดตามการแก้ไขในเอกสารที่ใช้ร่วมกัน ทุกการเปลี่ยนแปลงถูกบันทึกไว้ตามลำดับ เพื่อให้ทุกคนอัปเดตสำเนาของตัวเองให้ตรงกันได้ด้วยวิธีเดียวกัน migration คือสคริปต์ที่มีเวอร์ชันและทำซ้ำได้ ซึ่งอธิบายการเปลี่ยนแปลงหนึ่งอย่างนั้น migration สำคัญเพราะสคีมาในเครื่องของคุณ เครื่องของเพื่อนร่วมทีม และระบบจริง ต้องเหมือนกันทุกอย่าง
กฎที่ทำให้ migration ปลอดภัย
- อย่าแก้ไขฐานข้อมูลด้วยมือในระบบจริงเด็ดขาด ให้เขียน migration แทน
- Migration เดินหน้าเสมอ แต่ละอันเป็นไฟล์ใหม่ คุณไม่เขียนไฟล์เก่าที่รันไปแล้วซ้ำ
- ทำการเปลี่ยนแปลงที่ทำลายข้อมูลด้วยความระมัดระวัง การลบคอลัมน์หรือตารางจะลบข้อมูลอย่างถาวร ต้องมีแบ็กอัพไว้ก่อน
- การเปลี่ยนแปลงแบบเพิ่มเติมปลอดภัยที่สุด การเพิ่มคอลัมน์ที่ยอมให้เป็น null ไม่ค่อยทำให้อะไรพัง แต่การเปลี่ยนชื่อหรือลบคอลัมน์อาจทำให้โค้ดที่กำลังรันอยู่พังได้
Migration ก่อตัวเป็นห่วงโซ่ตามลำดับ แต่ละอันคือขั้นตอนที่มีหมายเลขกำกับ ซึ่งพาสำเนาฐานข้อมูลทุกชุดจากสถานะที่รู้จักหนึ่งไปสู่สถานะถัดไป เพื่อให้เครื่องของคุณ เครื่องของเพื่อนร่วมทีม และระบบจริง ลงเอยเหมือนกันหมด
empty DB
│
▼
┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐
│ 001_init │ ▶ │ 002_add │ ▶ │ 003_index │ ▶ │ 004_bio │
│ users │ │ posts │ │ on author │ │ column │
└────────────┘ └────────────┘ └────────────┘ └────────────┘
apply in order ─────────────────────────────────────────▶ current
never edit a step that already ran — add a NEW one
เครื่องมืออย่าง Prisma, Drizzle หรือ Rails migrations สร้างและติดตามสิ่งเหล่านี้ให้คุณโดยอัตโนมัติ ปล่อยให้มันทำหน้าที่ไป
migration หนึ่งอันประกอบด้วยสองส่วน คือการเปลี่ยนแปลงที่จะใช้ (up) และวิธียกเลิกมัน (down) เครื่องมือที่เชื่อถือได้จะสร้างทั้งสองส่วนให้ เพื่อให้การ ที่ผิดพลาดสามารถย้อนกลับได้อย่างเรียบร้อย
-- up: add an optional bio, safe to apply live
ALTER TABLE users ADD COLUMN bio TEXT;
-- down: reverse it
ALTER TABLE users DROP COLUMN bio;
migration ที่อันตรายจริง ๆ คือการ เปลี่ยนชื่อ (rename) และ เปลี่ยนชนิดข้อมูล เพราะโค้ดเก่ากับสคีมาใหม่จะขัดแย้งกันชั่วคราว วิธีที่มืออาชีพใช้คือแบ่งมันออกเป็นขั้นตอนแบบเพิ่มเติม เพิ่มคอลัมน์ใหม่ เติมข้อมูลย้อนหลัง (backfill) สลับให้โค้ดอ่านคอลัมน์ใหม่ แล้วค่อยลบคอลัมน์เก่าใน deploy ครั้งถัดไป เมื่อไม่มีอะไรอ้างอิงถึงมันแล้วเท่านั้น มันดูเหมือนจะช้า แต่มันคือความแตกต่างระหว่างการปล่อยเวอร์ชันที่ราบรื่นกับการเกิดข้อผิดพลาดหน้า 500 ถล่มทลายกับผู้ใช้ทุกคนกลางคัน deploy