🛑 1. The Problem First: "สงคราม SQL ในสตริง" (Query Hell)
ลองนึกถึงวันที่คุณต้องเขียน SQL ดิบๆ ในโค้ด Backend:
// ❌ Naive Approach: SQL ในสตริง ไร้ Type Safety และดิ้นรนกับการจัดการ Connection
const query = "SELECT * FROM users WHERE id = " + userId; // 🌋 ระเบิดแน่ถ้าเจอ SQL Injection!
const rows = await db.execute(query);
// แล้ว 'rows' มีฟิลด์อะไรบ้าง? ต้องไปเปิด Schema ดู สลับไปมาจนตาลาย
ปัญหา: การเขียน SQL ดิบหรือใช้ ORM รุ่นเก่าทำให้คุณเสียเวลาอย่างมากกับการ "เดา" ว่าข้อมูลที่ได้กลับมาหน้าตาเป็นอย่างไร และเมื่อต้องแก้ Database Schema ทีหนึ่ง คุณต้องไล่หาทุุกจุดในโค้ดว่ามีตรงไหนพังบ้าง นี่คือฝันร้ายของการ Scale ระบบครับ
💡 2. Real-Life Analogy: นักแปลภาษาอัจฉริยะ (The Fluent Translator)
- Database (Postgres): เหมือน "ห้องสมุดขนาดใหญ่". ข้อมูลถูกเก็บไว้อย่างเป็นระเบียบ แต่คุยคนละภาษากับแอปของคุณ (คุยภาษา SQL)
- Docker Compose: เหมือน "ตู้คอนเทนเนอร์สำเร็จรูป". คุณไม่ต้องสร้างห้องสมุดเอง แค่สั่ง "กางตู้" (docker-compose up) คุณก็ได้ห้องสมุดสภาพดีพร้อมใช้งานทันที ไม่รกพื้นบ้าน
- Prisma (ORM): เหมือน "เครื่องแปลภาษาอัจฉริยะ". มันมองเห็นหนังสือทุุกเล่มในห้องสมุด แล้วสรุปออกมาเป็นเมนูภาษาบ้านคุณ (TypeScript) ที่กดเลือกฟิลด์ได้เป๊ะๆ (Auto-completion) และถ้าห้องสมุดเปลี่ยนป้ายชื่อ เครื่องนี้จะเตือนคุณทันทีว่า "เมนูเดิมใช้ไม่ได้แล้วนะ!"
🚀 3. Execution Journey: มหากาพย์การสร้างฐานราก
เราจะสร้างระบบที่ "แก้ไขง่าย ตายยาก" ด้วย 3 ขั้นตอนระดับ Senior
🛠 Step-by-step:
- Infra with Docker: ใช้ Docker Compose เพื่อให้ทุกคนในทีมมี Database แบบเดียวกันเป๊ะๆ
- Schema Definition: กำหนดโมเดลใน
prisma/schema.prismaเพื่อให้เป็น Single Source of Truth - NestJS Service: สร้าง
PrismaServiceเป็นกองกลาง (Singleton) เพื่อให้ทุุกโมเดลหยิบไปใช้ได้ง่ายๆ
// ✅ Best Practice: สร้างกองกลาง Prisma
@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit {
async onModuleInit() {
await this.$connect(); // 🛠 เชื่อมต่อทันทีเมื่อ Start แอป
}
}
🪤 4. The Junior Trap: โรค "Hardcode DB URL"
จูเนียร์มักจะใส่ความลับไว้ในโค้ดโดยไม่รู้ตัว:
// ❌ Junior Trap: ความลับที่เปิดเผย
const dbUrl = "postgresql://user:password@localhost:5432/mydb";
// 🌋 พัง! เมื่อคุณ Push ขึ้น GitHub หรือเปลี่ยนเป็น Server จริง
// ระบบจะล่มเพราะ URL ไม่ตรงกัน และ Hacker จะยิ้มกริ่มกับ Password ของคุณ
ระวัง: ข้อมูลความลับห้ามอยู่ในโค้ดเด็ดขาด!
✅ การแก้ไข: ใช้ ConfigModule ของ NestJS เพื่อโหลดค่าจาก .env และใช้ ConfigService ในการดึงค่ามาใช้งานอย่างปลอดภัย
⚖️ 5. The Why Matrix: Prisma vs TypeORM
| หัวข้อ | TypeORM (แบบคลาสสิก) | Prisma (ยุคใหม่) |
|---|---|---|
| Type Safety | ⚡⚡ ดี (อิงตาม Class) | ⚡⚡⚡ เทพ (อิงตาม Database จริง) |
| Developer Experience | ปานกลาง (ต้องเขียน Decorator เยอะ) | 🚀 สูงมาก (Auto-generated Client) |
| Migration | 🐢 ค่อนข้างวุ่นวาย | ⚡⚡ ง่ายและแม่นยำมาก |
| ประสิทธิภาพ | สูง (แต่คุมยาก) | สูง (เพราะมี Rust Engine อยู่ข้างหลัง) |
🎓 6. Senior Mindset Summary
การเป็น Senior คือการมองว่า "Database ไม่ใช่แค่ที่เก็บของ แต่คือหัวใจของความถูกต้อง (Data Integrity)". การใช้ Prisma ร่วมกับ NestJS ไม่ใช่แค่เรื่องความเท่ แต่คือการสร้าง "สัญญา" (Contract) ระหว่าง Code และ Data ให้แข็งแรงที่สุดเท่าที่จะเป็นไปได้ครับ!