Back to notes
mastery-backend-nestjs
Featured

Domain-Driven Design (DDD) ใน NestJS: เมื่อโปรเจกต์ไม่ได้มีแค่ CRUD

ยกระดับการเขียน Backend จากการก๊อปวาง Boilerplate สู่การออกแบบระบบตาม 'โดเมน' ของธุรกิจ เพื่อรองรับการขยายตัวที่ไร้ขีดจำกัด

February 5, 20262 min read readNNexis by Seereen

🛑 1. The Trap: "Folder Based on Technology"

คนส่วนใหญ่มักเริ่มสร้างโปรเจกต์ NestJS โดยการแยกโฟลเดอร์ตามประเภทของไฟล์ เช่น controllers, services, entities:

  • ปัญหา: เมื่อโปรเจกต์โตขึ้น มี 50 Controllers อยู่ในโฟลเดอร์เดียว คุณจะหาโค้ดไม่พบ และทุกอย่างจะพันกันจนแยกไม่ออก (Tight Coupling)

Senior Solution: เราต้องเปลี่ยนจากการจัดโฟลเดอร์ตาม "เทคโนโลยี" มาเป็นการจัดตาม "ธุรกิจ" หรือที่เรียกว่า Domain-Driven Design (DDD) ครับ


💡 2. Real-Life Analogy: ห้องครัวร้านอาหาร vs โรงอาหารโรงเรียน

  • โฟลเดอร์แบบเดิม (Technical Split): เหมือนคุณเก็บ "มีดทุกเล่ม" ไว้ในลิ้นชักเดียว "เขียงทุกอัน" ไว้อีกลิ้นชัก พอจะทำซูชิ คุณต้องเดินวุ่นไปทั่วครัวเพื่อหยิบของที่กระจัดกระจาย
  • โฟลเดอร์แบบ DDD (Domain Split): เหมือนการแยก "สเตชัน". สเตชันซูชิมีครบทั้งมีดสำหรับปลาและเขียงเฉพาะทาง ทุกอย่างที่เกี่ยวข้องกับการทำซูชิรวมอยู่ที่เดียว (Encapsulation)
  • บทสรุป: เมื่อธุรกิจต้องการเพิ่มเมนู "สเต็ก" คุณแค่เพิ่มสเตชันใหม่ โดยไม่กระทบกับสเตชันซูชิเดิมครับ

🚀 3. Execution Journey: ขั้นตอนการจัดโครงสร้างแบบ Domain-First

ในโปรเจกต์ Aura Tour Booking ผมไม่ได้มองแค่ว่ามี Table อะไรบ้าง แต่มองว่ามี "Domain" อะไรบ้าง:

🛠 Step-by-step:

  1. Identify Domains: แยกส่วนงานที่อิสระจากกัน เช่น Tours, Bookings, Users, Payments
  2. Module Encapsulation: ทุก Domain จะมี Module ของตัวเอง ซึ่งภายในจะมี Controller, Service และ Entity ที่ทำงานร่วมกันเท่านั้น
  3. Communication via Interfaces: ถ้า Bookings ต้องการข้อมูลจาก Tours ต้องคุยผ่าน Service ที่ Export ออกมาเท่านั้น ห้ามแอบไปยิง Database ข้ามเครื่องกันเอง
HLJS TYPESCRIPT
// ✅ โครงสร้างโฟลเดอร์แบบ Senior (DDD Lite)
src / tours / tours.controller.ts;
tours.service.ts;
tours.module.ts;
entities / tour.entity.ts;
bookings / bookings.controller.ts;
// ...

🪤 4. The Junior Trap: "Circular Dependency"

เมื่อคุณเริ่มแยก Module จูเนียร์มักจะเผลอเอา Module A เรียก B และ B กลับมาเรียก A:

  • ปัญหา: NestJS จะรันไม่ขึ้นเพราะมันงงว่าจะสร้างอะไรก่อน (Infinite Loop)
  • ✅ การแก้ไข: จงสร้าง "Shared Module" หรือ "Core Module" สำหรับเก็บสิ่งที่ทุกคนต้องใช้ร่วมกัน หรือใช้ Domain Events (Pub/Sub) เพื่อให้แต่ละ Module ไม่ต้องรู้จักกันโดยตรงครับ

⚖️ 5. The Architecture Matrix: ยิ่งซับซ้อน ยิ่งต้องใช้วินัย

หัวข้อSimple CRUD (Junior)Professional DDD (Senior)
ความเร็วในตอนเริ่ม🚀 เร็วมาก🐢 ช้ากว่า (ต้องวางแผน)
ความง่ายในการแก้ Bug😱 ยาก (เพราะโค้ดพันกัน)✅ ง่าย (แก้แค่ใน Domain นั้น)
การทำ Unit Testยาก (ต้อง Mock มหาศาล)✅ ง่ายมาก (Scope ชัดเจน)
การขยายทีมทุกคนแก้ไฟล์เดียวกันแยกกันทำงานตาม Domain ได้เลย

🎓 6. Senior Mindset Summary

การเขียนโค้ดให้ "รันได้" ใครๆ ก็ทำได้ แต่การรักษาโค้ดให้ "อ่านออกและแก้ได้" หลังจากผ่านไป 2 ปี นั่นคือหน้าที่ของ Senior ครับ การใช้ DDD ไม่ใช่แค่การจัดโฟลเดอร์ แต่คือการมัดรวม Business Logic กับ Technical Implementation ให้เดินไปในทิศทางเดียวกันครับ!

## References

Share this note

© 2026 My Notes by Seereen