Back to notes
mastery-backend-express
Featured

Express.js Architecture: วางรากฐานระบบให้ใหญ่แค่ไหนก็ไม่พัง

จัดโครงสร้าง Express แบบ 3-Layer Architecture (Controller-Service-Data) เพื่อการเพิ่มฟีเจอร์ที่ลื่นไหล การ Test ที่แม่นยำ และการ Scale ระบบได้จริง

January 30, 20263 min read readNNexis by Seereen

🛑 1. The Problem First: "โค้ดรวมมิตร" (The Spaghetti King)

ลองดูโค้ดแบบจูเนียร์ที่เขียนเสร็จไวแต่แก้ทีไรแล้วร้องไห้:

HLJS JAVASCRIPT
// ❌ Naive Approach: เขียนทุุกอย่างใน Router/Controller
app.post("/register", async (req, res) => {
  const { email, password } = req.body;
  // 1. Validation อยู่ที่นี่
  if (!email.includes("@")) return res.status(400).send("Invalid email");
  // 2. Database Query อยู่ที่นี่
  const existing = await db.user.findUnique({ where: { email } });
  if (existing) return res.status(400).send("Email exists");
  // 3. Business Logic / Hash Password อยู่ที่นี่
  const hashed = await bcrypt.hash(password, 10);
  // 4. Send Email อยู่ที่นี่... (ยาวไปเรื่อยๆ)
  res.send("OK");
});

ปัญหา: เมื่อ Logic ทุกอย่าง (DB, Email, Validation) ไปกองกระจุกอยู่ในที่เดียว ถ้าวันหนึ่งคุณอยากเปลี่ยนจาก Database SQL ไปเป็น MongoDB หรืออยากจะเขียน Unit Test เฉพาะการสมัครสมาชิก คุณจะทำไม่ได้เลยเพราะทุกอย่างมัน "ผูกติดกัน (Tightly Coupled)" จนแกะไม่ออก นี่คือที่มาของ Technical Debt มหาศาลครับ


💡 2. Real-Life Analogy: ห้องเครื่องของเรือยอร์ช

  • Controller (ต้นหน): เหมือนคนที่อยู่บนดาดฟ้า คอยรับพิกัด (Request) และบอกว่า "ฉันต้องการไปที่นี่" แต่เขาไม่รู้หรอกว่าเครื่องยนต์ทำงานยังไง
  • Service Layer (ช่างเครื่อง): เหมือนคนที่อยู่ในห้องเครื่อง รู้ว่าถ้าจะไปข้างหน้าต้องทำตัวเลขไหน (Business Logic) แต่เขาไม่เคยเห็นน้ำทะเล (HTTP) และไม่แคร์ว่าน้ำมันมาจากถังไหน
  • Data Access/Repository (ถังน้ำมัน): เหมือนคนดูแลน้ำมัน มีหน้าที่แค่ "ส่งน้ำมันให้ช่าง" ไม่ต้องรู้ว่าน้ำมันนั้นจะเอาไปขับเคลื่อนเรือหรือเอาไปทำอะไร

🚀 3. Execution Journey: พลังของ 3-Layer Architecture

การแยกชั้น (Decoupling) ช่วยให้โค้ดของคุณพรีเมียมและ Test ง่ายขึ้น 1,000%

🛠 Step-by-step:

  1. Controller Layer: รับ req, res แล้วส่งต่อข้อมูลให้ Service (อย่ามี logic!)
  2. Service Layer: เขียน Business Logic ล้วนๆ (คำนวณเงิน, เช็คเงื่อนไขธุรกิจ)
  3. Repository Layer: คุยกับ Database เท่านั้น (SELECT, INSERT, UPDATE)
HLJS JAVASCRIPT
// ✅ Best Practice: แยกความรับผิดชอบ (Clean Architecture)
// 🛠 [Controller]
const register = async (req, res) => {
  const userData = await userService.signUp(req.body); // 👈 ส่งไม้ต่อให้คนฉลาด
  res.status(201).json(userData);
};

// 🛠 [Service]
const signUp = async (data) => {
  const exists = await userRepository.findByEmail(data.email); // 👈 คุยกับถังข้อมูล
  if (exists) throw new Error("Email Already Taken");
  return userRepository.create(data);
};

🪤 4. The Junior Trap: โรค "Controller ฉลาดเกินไป"

จูเนียร์มักจะเผลอเอา req.body หรือ res.status เข้าไปไว้ในชั้น Service:

HLJS JAVASCRIPT
// ❌ Junior Trap: ผูกติดกับ HTTP ในชั้นที่ไม่ควร
// user.service.js
async function register(req, res) {
  // 🌋 พัง! ถ้าวันหลังเราจะสมัครสมาชิกผ่าน CLI หรือ CRON Job
  // เราจะรันฟังก์ชันนี้ไม่ได้เพราะมันถามหา 'req' และ 'res'
}

ระวัง: ชั้น Service ต้อง "บริสุทธิ์" (Pure Business Logic) ไม่ควรรู้จักโลกภายนอกอย่าง HTTP เลย ✅ การแก้ไข: รับเฉพาะตัวแปรธรรมดา (String, Object, Array) และส่งค่ากลับเป็น Data เท่านั้น


⚖️ 5. The Why Matrix: ท่าเดิม vs ท่าใหม่

หัวข้อโค้ดรวมมิตร (Flat Structure)โค้ด 3-Layer (Senior Style)
การเขียน⚡⚡⚡ เร็วมากในวันแรกช้ากว่าเล็กน้อย (ต้องสร้างหลายไฟล์)
การบำรุงรักษา🐢 ยากนรกแตก (แก้หนึ่ง พังเจ็ด)⚡⚡ ง่าย (แยกส่วนกันชัดเจน)
การทำ Unit Testแทบทำไม่ได้⚡⚡⚡ ทำได้ 100% (Mock ง่ายมาก)
การขยายระบบต้อง Code ใหม่หมด⚡⚡⚡ เปลี่ยน DB หรือ API สบายๆ

🎓 6. Senior Mindset Summary

การเป็น Senior คือการมองว่า "เราไม่ได้เขียนโค้ดเพื่อให้คอมพิวเตอร์รันได้ แต่เราเขียนเพื่อให้คน (รวมถึงตัวเราในอนาคต) อ่านรู้เรื่องและแก้ไขได้". การจัดโครงสร้างที่ดีคือการลงทุนที่คุ้มค่าที่สุดในระยะยาวของโปรเจกต์ครับ!

Share this note

© 2026 My Notes by Seereen