🛑 1. The Problem First: "โค้ดขยะ" ที่ก๊อปปี้ไปทุกไฟล์
ลองดู Controller ที่จูเนียร์ส่วนใหญ่มักจะเขียน:
// ❌ Naive Approach: เขียนเช็ค Auth และ Validate ในทุกๆ ฟังก์ชัน
app.post("/profile", (req, res) => {
// เช็ค Auth
if (!req.headers.token) return res.status(401).send("No Token");
// เช็ค Input
if (!req.body.name) return res.status(400).send("Name is required");
// ... Logic จริงๆ อยู่ตรงนี้ (ซึ่งมันเริ่มหายไปในดง If-Else)
});
ปัญหา: ถ้าคุณมี 50 หน้า คุณต้องก๊อปปี้โค้ดเช็ค 10 บรรทัดนี้ไป 50 ครั้ง! และถ้าวันหนึ่งคุณอยากเปลี่ยนรหัส Error คุณต้องแก้ 50 ที่! นี่คือนรกของการซ่อมบำรุงครับ
💡 2. Real-Life Analogy: ด่านตรวจคนเข้าเมือง (Immigration)
ลองนึกภาพว่าคุณกำลัง "เดินทางไปต่างประเทศ".
- The Target (Controller): คือที่พักหรือที่เที่ยวที่คุณอยากไป (จุดประสงค์หลัก)
- Middleware: คือ "ด่านตรวจ" ระหว่างทาง
- ด่าน 1 (Logger): กล้องวงจรปิด บันทึกว่าใครเดินผ่านหน้าประตูร้าน (Logger)
- ด่าน 2 (Auth): ตรวจพาสปอร์ต ถ้าไม่มีบัตรก็โดนไล่กลับบ้าน (Unauthorized)
- ด่าน 3 (Validation): ตรวจกระเป๋าเดินทาง ห้ามเอาของผิดกฎหมายเข้า (Invalid Input)
- The Journey: คุณต้องผ่านด่าน 1 -> 2 -> 3 ถึงจะไปถึงที่เที่ยวได้
🚀 3. Execution Journey: เส้นทางเดินของ Request
ใน Express, Middleware คือท่อที่ Request วิ่งผ่านลำดับ 1, 2, 3:
🛠 Step-by-step:
- Request In: แขกเดินเข้ามาพร้อมกะเป๋าข้อมูล
- Middleware 1: ทำงานสำเร็จ เรียก
next()เพื่อส่งต่อ - Middleware 2: ถ้าตรวจเจอความผิดปกติ เรียก
res.send()ทันที (จบงานตรงนี้ ไม่ส่งต่อ) - Controller: เมื่อผ่านทุกด่านแล้ว ถึงจะได้ทำงานจริงๆ
// ✅ Best Practice: แยก Logic การตรวจออกเป็นชิ้นเล็กๆ (Modular)
const isAuthed = (req, res, next) => {
if (req.headers.token) return next(); // 🛠 เรียก next() เพื่อส่งไม้ต่อ
res.status(401).send("Unauthorized");
};
app.get("/secret-data", isAuthed, (req, res) => {
res.send("นี่คือข้อมูลลับ");
});
🪤 4. The Junior Trap: โรค "next() ล่องหน"
จูเนียร์มักจะลืมเรียก next() ในทางแยก:
// ❌ Junior Trap: ลืม next() หรือเรียกซ้อนกัน
const myMiddleware = (req, res, next) => {
if (req.body.admin) {
next();
}
// 🌋 ถ้าไม่ใช่ admin... Request จะค้างอยู่ตรงนี้ตลอดกาล (Timeout)
// เพราะไม่มีใครสั่งให้มันไปต่อ หรือสั่งให้หยุด (res.send)
};
ระวัง: ทุกเส้นทางของ Logic ต้องจบด้วย next() หรือ res.xxx() เสมอ!
⚖️ 5. The Why Matrix: Inline vs Middleware
| หัวข้อ | เขียนใน Controller (Inline) | ใช้ Middleware (Modular) |
|---|---|---|
| การเอาไปใช้ซ้ำ | ยาก (ต้อง Copy/Paste) | ง่าย (แปะชื่อฟังก์ชันจบ) |
| ความสะอาดของโค้ด | สกปรก (Business Logic ผสมกับ Security) | สะอาดแยกส่วนชัดเจน |
| การเทส (Testing) | เทสยาก ต้องจำลองทั้งระบบ | เทสแยกส่วนได้ง่ายมาก |
🎓 6. Senior Mindset Summary
การเป็น Senior คือการมองหา "Pattern ของงานที่ซ้ำซาก" และแยกมันออกมาเป็น Middleware เพื่อให้งานหลัก (Business Logic) คงความสะอาดและดูแลรักษาง่ายที่สุดครับ!