จัดการ Database Migration ให้ง่ายขึ้นด้วย Miglite v0.8.0 ฝังไฟล์ลง Binary จบในตัวเดียว

8 นาที 7 views บันทึกเป็น PDF
จัดการ Database Migration ให้ง่ายขึ้นด้วย Miglite v0.8.0 ฝังไฟล์ลง Binary จบในตัวเดียว

เบื่อไหมที่ต้องคอยก๊อปปี้ไฟล์ Migration ไปวางที่เซิร์ฟเวอร์? มาดูวิธีใช้ Miglite v0.8.0 ฝังไฟล์ SQL เข้าไปใน Binary ของโปรแกรม Go เพื่อให้การ Deploy ง่ายและปลอดภัยขึ้น

ทำความรู้จักกับ Migrations และปัญหาที่มือใหม่มักเจอ

ในการพัฒนาซอฟต์แวร์ เรามักต้องเก็บข้อมูลลงใน Database (ฐานข้อมูล หรือที่เก็บข้อมูลของแอป) เมื่อแอปมีการอัปเดต เรามักต้องปรับเปลี่ยนโครงสร้างตารางข้อมูลตามไปด้วย Migration (กระบวนการจัดการการเปลี่ยนแปลงโครงสร้างฐานข้อมูล) จึงเป็นเครื่องมือที่เข้ามาช่วยให้เราบันทึกการเปลี่ยนแปลงเหล่านี้ไว้ในรูปแบบไฟล์โค้ด เพื่อให้เราย้อนกลับหรืออัปเดตโครงสร้างฐานข้อมูลได้อย่างปลอดภัยและเป็นระเบียบ

สำหรับมือใหม่ ปัญหาที่พบบ่อยคือการลืมนำไฟล์เหล่านี้ติดตัวไปตอนที่เรา Deploy (เอาโค้ดขึ้นเซิร์ฟเวอร์จริง หรือการทำให้โปรแกรมของเราพร้อมใช้งานบนอินเทอร์เน็ต) ทำให้แอปบนเซิร์ฟเวอร์รันไม่ได้เพราะหาไฟล์คำสั่งจัดการฐานข้อมูลไม่เจอ การต้องคอยก๊อปปี้โฟลเดอร์ migrations/ ไปวางไว้ข้างๆ โปรแกรมทุกครั้งเป็นเรื่องยุ่งยากและมีโอกาสเกิดข้อผิดพลาดสูงมาก

Miglite เวอร์ชัน 0.8.0 เข้ามาแก้ปัญหานี้ด้วยแนวคิดการ Ship (ขนส่งหรือรวมไฟล์เข้าด้วยกัน) โดยการฝังไฟล์เหล่านี้เข้าไปใน Binary (ไฟล์โปรแกรมที่คอมไพล์แล้ว หรือไฟล์ที่รันได้โดยตรงเหมือน .exe ใน Windows) ทำให้เราไม่ต้องกังวลเรื่องการลืมเอาไฟล์ไปวางที่เซิร์ฟเวอร์อีกต่อไป เพราะทุกอย่างรวมอยู่ในไฟล์เดียวจบครบในตัวเดียวครับ

การฝังไฟล์ Migration เข้าไปใน Binary

ในภาษา Go เรามีเครื่องมือที่ชื่อว่า go:embed ซึ่งช่วยให้เราสามารถดึงไฟล์ภายนอก เช่น ไฟล์ SQL เข้ามาเก็บไว้ในหน่วยความจำของโปรแกรมตอนที่มันทำงานได้ การใช้งานนี้ทำให้เราไม่ต้องมีโฟลเดอร์แยกต่างหากในเครื่องเซิร์ฟเวอร์อีกต่อไป โปรแกรมจะอ่านไฟล์จากภายในตัวมันเองแทนการมองหาไฟล์บนฮาร์ดดิสก์

ลองมาดูตัวอย่างการเขียนโค้ดเพื่อฝังไฟล์เหล่านี้เข้าไปในโปรแกรมของเรากันครับ นี่คือวิธีการตั้งค่าพื้นฐานที่ทำให้ Miglite รู้จักไฟล์ที่ถูกฝังอยู่ข้างในตัวมันเอง แทนที่จะไปหาจากโฟลเดอร์ข้างนอกเหมือนแบบเดิม

//go:embed migrations/*.sql
var migrationFS embed.FS

func main() {
    // กำหนดให้ใช้ไฟล์ที่ฝังอยู่ในตัวโปรแกรม
    mig, err := miglite.NewAuto(func(cfg *miglite.Config) {
        cfg.Migrations.Path = "migrations"
    })
    // เชื่อมต่อกับฐานข้อมูลและสั่งรันการอัปเดต
    mig.SetFS(migrationFS).SetSqlDB(db)
    mig.Up(command.UpOption{Yes: true})
}

ในตัวอย่างนี้ บรรทัดแรกคือคำสั่งพิเศษที่บอกให้ Go นำไฟล์ SQL ทั้งหมดในโฟลเดอร์มาเก็บไว้ในตัวแปร migrationFS ส่วน mig.SetFS(migrationFS) คือการบอกให้ไลบรารีไปอ่านไฟล์จากหน่วยความจำแทนการอ่านจากโฟลเดอร์ปกติ ผลลัพธ์คือเมื่อเราสั่งคอมไพล์โปรแกรม เราจะได้ไฟล์เดียวที่รวมทั้งตัวแอปและโครงสร้างฐานข้อมูลไปใช้งานได้ทันที

การใช้ Flag --db เพื่อเลือกฐานข้อมูลที่ต้องการ

บ่อยครั้งที่นักพัฒนาต้องการทดสอบโปรแกรมกับฐานข้อมูลหลายที่ เช่น ฐานข้อมูลสำหรับทดสอบ หรือฐานข้อมูลจำลองจากข้อมูลจริง การแก้ไขไฟล์ตั้งค่าทุกครั้งเป็นเรื่องที่เสียเวลาและเสี่ยงต่อการลืมเปลี่ยนกลับ การใช้ Flag (ตัวเลือกเสริมสำหรับคำสั่ง) จึงเป็นทางออกที่สะดวกและปลอดภัยกว่ามากครับ

ใน Miglite v0.5.0 เป็นต้นมา เราสามารถใช้คำสั่ง --db เพื่อระบุชื่อฐานข้อมูลที่ต้องการจัดการได้ทันทีโดยไม่ต้องไปแก้ไฟล์ตั้งค่าหลัก สิ่งนี้มีประโยชน์มากตอนที่เราต้องการรันคำสั่ง SQL (ภาษาที่ใช้คุยกับฐานข้อมูล) เฉพาะกิจบนฐานข้อมูลที่เรากำหนดเอง

# ตรวจสอบสถานะของฐานข้อมูลที่ระบุ
miglite --db my_test_db status

# รันคำสั่ง SQL บนฐานข้อมูลที่ต้องการโดยไม่ต้องแก้ไฟล์ Config
miglite exec --db my_test_db --yes "SELECT * FROM users;"

บรรทัดแรกคือการสั่งให้เช็คสถานะการอัปเดตบนฐานข้อมูลที่ชื่อว่า my_test_db เท่านั้น บรรทัดที่สองคือการรันคำสั่ง SQL ตรงๆ ลงไปในฐานข้อมูลดังกล่าวโดยข้ามขั้นตอนการยืนยัน ผลลัพธ์ที่ได้คือเราสามารถจัดการฐานข้อมูลหลายตัวได้จากคำสั่งเดียวโดยไม่ต้องกังวลว่าจะไปกระทบกับค่าตั้งค่าถาวรของโปรแกรมครับ

การทำงานของ exec แบบ Transaction เดียว

Transaction (ชุดคำสั่งที่ต้องสำเร็จทั้งหมดหรือล้มเหลวทั้งหมด) คือหัวใจสำคัญของการจัดการข้อมูลที่ปลอดภัย ในเวอร์ชันก่อนหน้านี้ exec จะรันคำสั่งทีละบรรทัด หากคำสั่งที่ห้าพัง คำสั่งที่หนึ่งถึงสี่จะถูกบันทึกลงไปแล้ว ทำให้ข้อมูลอาจจะค้างอยู่ในสถานะไม่สมบูรณ์ แต่ตอนนี้ Miglite ปรับปรุงใหม่ให้รันคำสั่งทั้งหมดในชุดเดียวแล้วครับ

การทำงานแบบใหม่นี้จะแบ่งคำสั่ง SQL ออกเป็นส่วนๆ และรันภายใต้ Transaction เดียวกัน หากมีคำสั่งไหนผิดพลาด ระบบจะทำการ Rollback (การย้อนกลับสถานะข้อมูลให้เหมือนก่อนเริ่มรันคำสั่ง) ให้โดยอัตโนมัติ ทำให้มั่นใจได้ว่าฐานข้อมูลของเราจะไม่พังเพราะคำสั่งที่รันไม่จบ

ตัวอย่างการใช้งานคือการนำไฟล์ SQL ที่มีคำสั่งหลายบรรทัดมาสั่งรันผ่านคำสั่ง exec ของ Miglite ซึ่งระบบจะจัดการเรื่องความปลอดภัยให้เราเองโดยไม่ต้องเขียนโค้ดเพิ่ม วิธีนี้เหมาะมากสำหรับการนำเข้าข้อมูลเริ่มต้น (Seed data) ที่เราต้องการให้แน่ใจว่าข้อมูลทุกอย่างต้องเข้าฐานข้อมูลไปพร้อมกันอย่างสมบูรณ์

การปรับปรุงภายในเพื่อความเสถียร

การพัฒนาซอฟต์แวร์ที่ดีต้องมีการปรับปรุงโครงสร้างภายในหรือที่เรียกว่า Refactor (การปรับปรุงโค้ดโดยไม่เปลี่ยนการทำงาน) อยู่เสมอ ในเวอร์ชัน 0.7.0 ทางทีมผู้พัฒนาได้แยกส่วนการทำงานออกจากค่าคงที่ของระบบ ทำให้การรันคำสั่งต่างๆ มีความอิสระและแม่นยำมากขึ้นกว่าเดิมครับ

จุดที่สำคัญสำหรับมือใหม่คือการแก้ไขเรื่อง up --skip-err ที่เคยถูกละเลยไป ตอนนี้หากมีการรัน Migration แล้วเกิดข้อผิดพลาด ระบบจะข้ามไฟล์นั้นไปและรันไฟล์ถัดไปให้จนจบ แต่จะคืนค่าสถานะเป็น "ผิดพลาด" ให้เราทราบ ซึ่งช่วยให้การรันสคริปต์ใน CI/CD (ระบบทดสอบและส่งโค้ดขึ้นเซิร์ฟเวอร์อัตโนมัติ) ทำได้ง่ายขึ้นและตรวจสอบได้จริง

นอกจากนี้ การจัดการเรื่อง Connection (การเชื่อมต่อกับฐานข้อมูล) ก็ทำได้ดีขึ้น โดย Miglite จะไม่ปิดการเชื่อมต่อที่เราส่งเข้าไปเองอีกต่อไป ทำให้เราสามารถนำตัวเชื่อมต่อเดิมไปใช้งานต่อได้หลังจากรัน Migration เสร็จสิ้น ซึ่งเป็นสิ่งที่นักพัฒนาที่ต้องดูแลแอปพลิเคชันระยะยาวควรรู้ไว้นะครับ เพราะมันช่วยลดปัญหาการเชื่อมต่อฐานข้อมูลหลุดโดยไม่ตั้งใจได้ดีมาก

สรุป: การเริ่มต้นใช้งาน Miglite ในโปรเจกต์ของคุณ

การอัปเกรดมาใช้ Miglite v0.8.0 นั้นแทบไม่มีผลกระทบกับโค้ดเดิมของคุณเลย เพราะไม่มีการเปลี่ยนคำสั่งหรือรูปแบบไฟล์ตั้งค่า สิ่งที่เปลี่ยนคือความสะดวกในการจัดการไฟล์และการทำงานที่เสถียรขึ้น หากคุณกำลังมองหาเครื่องมือจัดการฐานข้อมูลที่เบาและใช้งานง่าย ผมแนะนำให้ลองเริ่มจากโปรเจกต์เล็กๆ ของตัวเองก่อนครับ

สมมติว่าคุณกำลังทำโปรเจกต์เว็บแอปพลิเคชันส่วนตัว ให้ลองเปลี่ยนจากการวางโฟลเดอร์ migrations/ ไว้ข้างๆ โปรแกรม มาลองใช้ go:embed เพื่อฝังไฟล์เหล่านี้เข้าไปดูครับ คุณจะพบว่าขั้นตอนการ Deploy ของคุณจะง่ายขึ้นมาก เพราะไม่ต้องคอยกังวลว่าไฟล์สำคัญจะหายไปตอนอัปโหลดขึ้นเซิร์ฟเวอร์อีกต่อไป

จำไว้ว่าการเป็นโปรแกรมเมอร์ที่ดีไม่ใช่แค่การเขียนโค้ดให้รันได้ แต่คือการใช้เครื่องมือที่ช่วยให้การทำงานของเรามีประสิทธิภาพและเกิดข้อผิดพลาดน้อยที่สุด Miglite เป็นตัวอย่างที่ดีของเครื่องมือที่ช่วยลดความยุ่งยากในงานพื้นฐาน เพื่อให้คุณมีเวลาไปโฟกัสกับการเขียนฟีเจอร์ใหม่ๆ ที่สนุกและท้าทายกว่าเดิมครับ


ที่มา: miglite v0.8.0: ship migrations inside the binary — DEV Community

แชร์บทความ

Facebook X LINE

บทความที่เกี่ยวข้อง

เทคนิคเขียนแอป Flutter สำหรับ Meta Smart Glasses ให้ลื่นไหลและมีประสิทธิภาพ

เทคนิคเขียนแอป Flutter สำหรับ Meta Smart Glasses ให้ลื่นไหลและมีประสิทธิภาพ

เรียนรู้วิธีเขียนแอป Flutter เชื่อมต่อ Meta Smart Glasses ให้ทำงานเร็ว ไม่กระตุก ด้วยการวางสถาปัตยกรรมโค้ดและการจัดการข้อมูลแบบมือโปรที่มือใหม่ทำตามได้จริง

ที่มา: DEV Community

3 hours ago 10 นาที
5 views
เปรียบเทียบ WebSocket, SSE และ Polling เลือกวิธีทำระบบ Real-Time ให้เหมาะกับงาน

เปรียบเทียบ WebSocket, SSE และ Polling เลือกวิธีทำระบบ Real-Time ให้เหมาะกับงาน

อยากทำระบบ Real-Time แต่ไม่รู้จะเลือกใช้ Polling, SSE หรือ WebSocket ดี? มาดูวิธีเลือกใช้ให้เหมาะกับงาน เพื่อให้แอปของคุณทำงานลื่นไหลและประหยัดทรัพยากรเซิร์ฟเวอร์

ที่มา: DEV Community

6 hours ago 10 นาที
4 views