🛑 1. The Problem First: "Dependency Hell" ใน Express
ลองดูเวลาเราเขียน Express แบบไม่มีโครงสร้าง:
// ❌ Naive Approach: ทุกอย่างวางรวมกันมั่วซั่ว
const userService = new UserService(new DatabaseRepo(new PostgresDriver()));
app.post("/users", (req, res) => {
// Logic คัดกรองข้อมูล, เช็ค Auth, คุยกับ DB อยู่ในนี้หมดเลย!
});
ปัญหา: เมื่อโปรเจกต์ใหญ่ขึ้น ไฟล์จะยาวเป็นพันบรรทัด การจะแก้ไขอะไรสักอย่าง (เช่น เปลี่ยน DB) คุณต้องไล่แก้ทั้งโปรเจกต์ และการสร้าง new Service() ซ้อนกะนหลายชั้นแบบนี้จะทำให้การทำ Unit Test กลายเป็นนรก!
💡 2. Real-Life Analogy: เลโก้ชุดสำเร็จรูป vs กล่องสุ่ม
ลองนึกภาพว่าคุณกำลัง "สร้างเมือง".
- Express: เหมือนคุณมีกล่องสุ่มที่มีตัวเลโก้ทุกแบบปนกันมั่วไปหมด (Schema-less) คุณอยากต่ออะไรก็ได้ แต่พอจะหาชิ้นส่วนที่ต้องการดันหาไม่เจอ
- NestJS: เหมือนคุณซื้อ "เลโก้ชุดสถานีตำรวจ" หรือ "ชุดโรงพยาบาล".
- แต่ละชุดมี Module (ป้ายกำกับชัดเจน)
- มี Controller (เคาน์เตอร์ประชาสัมพันธ์)
- และมี Service (พนักงานข้างหลัง)
- ทุกชิ้นส่วนถูกออกแบบมาให้ "เสียบ" เข้าหากันได้พอดี (Dependency Injection)
🚀 3. Execution Journey: มหากาพย์การ Request
เมื่อลูกค้าส่งคำสั่ง POST /users นี่คือเส้นทางของข้อมูล:
🛠 Step-by-step:
- Middleware/Guard: ข้อมูลมาถึงหน้าประตู (Check Auth)
- Controller: เคาน์เตอร์รับออเดอร์ ข้อมูลถูกตรวจสอบหน้าตา (DTO Validation) แล้วส่งต่อให้คนข้างใน
- Service: พนักงานหลังบ้านทำหน้าที่คำนวณเงิน บันทึกลงสมุด (Business Logic & Database)
- Module: ผู้จัดการเป็นคนรวบรวมพนักงานทุกคนและเคาน์เตอร์ทั้งหมดมาเข้าหมวดหมู่เดียวกัน
// ✅ Best Practice: แยก Logic ออกจาก Controller เสมอ
@Controller("users")
export class UsersController {
constructor(private readonly usersService: UsersService) {} // 🛠 ฉีด Service เข้ามาใช้ (DI)
@Post()
create(@Body() dto: CreateUserDto) {
return this.usersService.create(dto); // 👈 Controller แค่สั่งงาน ไม่ลงมือทำเอง
}
}
🪤 4. The Junior Trap: โรค "Controller บวม"
จูเนียร์ส่วนใหญ่มักจะขี้เกียจสร้างไฟล์ Service:
// ❌ Junior Trap: เขียน Logic ยาวเหยียดใน Controller
@Post()
create(@Body() dto: CreateUserDto) {
if (dto.name === 'admin') throw new Error('Bad name');
const user = await db.save(dto);
return user;
}
ระวัง: ถ้าวันหนึ่งคุณอยากสร้าง User ผ่านทางอื่น (เช่น Cron Job หรือ Command Line) คุณจะใช้ Logic นี้ไม่ได้เลย เพราะมันติดอยู่กับ HTTP Controller เท่านั้น!
✅ การแก้ไข: ย้ายทุกลอจิกการเช็คและบันทึกไปไว้ใน Service เพื่อให้ส่วนอื่นเรียกใช้ได้เสมอ
⚖️ 5. The Why Matrix: Express vs NestJS
| หัวข้อ | Express (Minimal) | NestJS (Opinonated) |
|---|---|---|
| ความเร็วในการเริ่ม | เร็วมาก เขียน 10 บรรทัดรันได้ | ช้ากว่า ต้องสร้างโครงสร้าง |
| การทำงานเป็นทีม | ต่างคนต่างเขียน ระบบมั่วได้ง่าย | ทุกคนเขียนเหมือนกัน เข้าใจกันง่าย |
| Dependency Injection | ต้องทำเอง (Manual) | มีระบบอัตโนมัติ (Built-in) |
🎓 6. Senior Mindset Summary
การเป็น Senior คือการเลิกถามว่า "จะเขียนยังไงให้รันออก" แต่เริ่มถามว่า "จะวางโครงสร้างยังไงให้ทีมงาน 10 คน ทำงานพร้อมกันได้โดยไม่เดินทับรอยกัน" และ NestJS คือคำตอบหนึ่งในนั้นครับ!
Mission Accomplished
You've reached the end of this module. Time to apply these senior mindsets to your real-world projects!