การวางโครงสร้างโฟลเดอร์สำหรับแอปขนาดใหญ่แบบ Enterprise

1. 🎯 ตอนที่ 33: สถาปัตยกรรมระดับ Enterprise จัดโครงสร้างโฟลเดอร์อย่างไรไม่ให้โปรเจกต์พัง
2. 📖 เปิดฉาก (The Hook)
น้องๆ เคยเจอปัญหานี้ไหมครับ? ตอนเริ่มโปรเจกต์ใหม่ๆ ทุกอย่างดูสวยงาม เรียบง่าย เรามีโฟลเดอร์ components กับ views ที่ Vue CLI หรือ Vite สร้างมาให้
แต่พอเวลาผ่านไป 6 เดือน… โปรเจกต์เรามีหน้าเว็บ 50 หน้า มี Component ย่อยอีก 200 ตัว ถูกจับยัดรวมกันอยู่ในโฟลเดอร์ src/components แบบแบนราบ (Flat) เวลาจะหา Component ของหน้า “ตะกร้าสินค้า” ทีไร ต้องเลื่อนเมาส์หาจนตาแฉะ! แถมบางทีเผลอไปแก้ Component ตัวนึง ดันไปทำให้อีกหน้านึงพัง เพราะเราไม่รู้ว่าใครเรียกใช้มันอยู่บ้าง (Spaghetti Folder Syndrome)
ปัญหานี้เป็นเรื่องคลาสสิกมากครับ วันนี้พี่เลยจะขอหยิบคัมภีร์จากหนังสือ “Vue - The Road to Enterprise” ของคุณ Thomas Findlay มาเล่าให้ฟัง พร้อมจิบกาแฟชิลๆ ไปด้วย เราจะมาดูวิชาการจัดระเบียบโครงสร้างแอปพลิเคชันขนาดใหญ่ ที่จะช่วยให้โค้ดของเราอ่านง่าย ค้นหาไว และสเกลได้แบบไม่มีสะดุดครับ!
3. 🧠 แก่นวิชา (Core Concepts)
โครงสร้างโฟลเดอร์ที่ดี ไม่ใช่แค่การจัดหมวดหมู่ไฟล์ครับ แต่มันคือ “แผนที่ (Blueprint)” ที่บอกให้นักพัฒนาคนอื่นรู้ว่า ระบบของเราทำงานอย่างไร สำหรับแอประดับ Enterprise เราจะแบ่งโครงสร้างหลักๆ ดังนี้ครับ:
🌍 1. การจัดการ Global Components (ชิ้นส่วนส่วนกลาง)
ในโฟลเดอร์ src/components เราจะไม่ยัดทุกอย่างลงไปมั่วๆ อีกแล้ว แต่เราจะแบ่งมันออกเป็นกลุ่มตามการใช้งาน:
base/(ชิ้นส่วนพื้นฐาน): เก็บ Component ที่ถูกเรียกใช้บ่อยมากๆ ทั่วทั้งแอป เช่น ปุ่ม (BaseButton.vue), ช่องกรอกข้อความ (BaseInput.vue) ซึ่งระดับเซียนเขามักจะเขียนสคริปต์ให้มัน Auto-register ตอนรันแอป จะได้ไม่ต้องมานั่ง Import เองทุกไฟล์ครับcommon/(ชิ้นส่วนที่ใช้ร่วมกัน): เก็บ Component ที่อาจจะซับซ้อนขึ้นมาหน่อย และใช้ร่วมกันในบางหน้า เช่นModal.vueหรือDataGrid.vueกลุ่มนี้เราจะ Import เองแบบ Manual เมื่อต้องการใช้
🛠️ 2. The Services Layer (ชั้นของตรรกะและธุรกิจ)
ในแอปขนาดใหญ่ เราจะแยก “ตรรกะการคำนวณ (Business Logic)” ออกจากหน้าตา (UI) ครับ:
services/: โฟลเดอร์นี้จะเก็บไฟล์ JavaScript/TypeScript ล้วนๆ ที่ทำหน้าที่จัดการลอจิกหนักๆ หรือ Stateful services (ไฟล์เก็บ State ย่อยๆ) เพื่อไม่ให้ Component ของเราบวมเกินไปapi/: โฟลเดอร์นี้มีหน้าที่เดียวคือ เป็นศูนย์รวมของการยิง HTTP Requests คุยกับ Backend (API Layer)
📦 3. Feature-based Architecture (แบ่งโฟลเดอร์ตามฟีเจอร์)
นี่คือไม้ตายสำคัญครับ! แทนที่เราจะแยกไฟล์ตาม “ประเภท” (เอา View รวมกับ View, เอา Component รวมกับ Component) เราจะเปลี่ยนมาจัดกลุ่มตาม “ฟีเจอร์ (Feature)” หรือ Domain ของระบบแทน

4. 💻 ร่ายมนต์โค้ด (Show me the Code)
เรามาดูความแตกต่างระหว่างโครงสร้างแบบ “ดั้งเดิม” กับโครงสร้างแบบ “Enterprise (Feature-based)” กันครับ สมมติว่าเรากำลังทำระบบ “จัดการสินค้า (Products)”
❌ แบบดั้งเดิม (แยกตามประเภทไฟล์ - หายาก โค้ดกระจัดกระจาย)
src/
├─ components/
│ └─ ProductForm.vue <-- Component ลูก ดันมาอยู่รวมกับส่วนกลาง
├─ services/
│ └─ productService.js <-- ลอจิกก็แยกมาอยู่นี่
└─ views/
├─ ProductsList.vue <-- หน้าหลัก
├─ AddProduct.vue <-- หน้าเพิ่มสินค้า
└─ EditProduct.vue <-- หน้าแก้ไขสินค้า✅ แบบยุคใหม่: Feature-based (รวมทุกสิ่งที่เกี่ยวข้องกันไว้ด้วยกัน)
ในหนังสือ The Road to Enterprise แนะนำให้เราห่อหุ้ม (Encapsulate) ทุกอย่างที่เป็นของฟีเจอร์นี้ ไว้ในโฟลเดอร์ของตัวมันเองครับ:
src/
└─ views/
└─ products/ <-- 🌟 สร้างโฟลเดอร์สำหรับฟีเจอร์ Products
├─ components/ <-- Component ที่ใช้เฉพาะหน้าสินค้าเท่านั้น!
│ └─ productForm/
│ ├─ ProductForm.vue
│ └─ productFormService.js <-- ลอจิกของ Form ก็เก็บไว้ใกล้ๆ กัน
├─ services/ <-- API หรือ Service ของสินค้า
│ └─ productService.js
├─ ProductsList.vue <-- หน้าหลักสินค้า
├─ AddProduct.vue
└─ EditProduct.vueเวทมนตร์ใน Vue Router: พอเราจัดโฟลเดอร์แบบนี้ การเขียน Vue Router ก็จะสะอาดตาและเป็นระเบียบสุดๆ ครับ:
// src/router/index.js
import { createRouter, createWebHistory } from 'vue-router'
const routes = [
{
path: '/products',
// 🌟 เล็งไปที่โฟลเดอร์ products อย่างเป็นระเบียบ
component: () => import('@/views/products/ProductsList.vue')
},
{
path: '/products/add',
component: () => import('@/views/products/AddProduct.vue')
}
]
export default createRouter({
history: createWebHistory(),
routes
})การจัดโครงสร้างแบบนี้ (High Cohesion) ช่วยให้เวลาทีมงานอีกคนได้รับมอบหมายให้มา “แก้บักหน้าฟอร์มสินค้า” เขาแค่พุ่งตรงมาที่โฟลเดอร์ views/products/ ที่เดียวจบ! ไม่ต้องไปงมหาไฟล์ในโฟลเดอร์ส่วนกลางให้ปวดหัวเลยครับ
5. 🛡️ เคล็ดลับจากคัมภีร์ลับ (Under the Hood / Pro-Tips)
💡 1. กฎเหล็กของการ Encapsulation (อย่าข้ามถิ่น)
ถ้าเราจัดโฟลเดอร์แบบ Feature-based ไปแล้ว กฎเหล็กคือ “ห้ามให้ฟีเจอร์อื่น (เช่น Users) แอบมาดึง Component ในโฟลเดอร์ Products ไปใช้เด็ดขาด!”
ถ้าเมื่อไหร่ก็ตามที่น้องๆ พบว่า ProductForm.vue จำเป็นต้องถูกเรียกใช้ในหน้าอื่นๆ ด้วย… นั่นคือสัญญาณเตือนว่ามันไม่ใช่ของฟีเจอร์นี้อีกต่อไป ให้รีบย้ายมันออกไปไว้ที่ src/components/common ส่วนกลางทันทีครับ!
⚡ 2. ท่าไม้ตาย Auto-Register Base Components
หากน้องๆ มี BaseButton.vue, BaseInput.vue อยู่ในโฟลเดอร์ src/components/base/ เยอะมาก การมานั่ง Import ทุกรอบคงเหนื่อยแย่ ใน Vite น้องๆ สามารถใช้คำสั่ง import.meta.glob() เพื่อกวาดหาไฟล์ที่ขึ้นต้นด้วย Base แล้วสั่ง app.component() ลงทะเบียนให้มันเป็น Global Component ได้แบบอัตโนมัติเลยครับ ประหยัดเวลาไปได้มหาศาล!
🎯 3. อย่า Over-engineer ตั้งแต่วันแรก สถาปัตยกรรมนี้ทรงพลังมาก แต่ถ้าโปรเจกต์ของน้องมีแค่ 3 หน้า การสร้างโฟลเดอร์ซ้อนกันลึกๆ แบบนี้อาจจะกลายเป็นการ “ขี่ช้างจับตั๊กแตน” ได้ครับ พี่แนะนำให้เริ่มจากโครงสร้างปกติก่อน และเมื่อฟีเจอร์ไหนเริ่มโตจนหาไฟล์ยาก (มีเกิน 5 ไฟล์ที่เกี่ยวข้องกัน) ค่อย Refactor แตกมันออกเป็น Feature folder ครับ
6. 🏁 บทสรุป (To be continued…)
การจัดโครงสร้างโฟลเดอร์ที่ดี เปรียบเสมือนการวางรากฐานของตึกระฟ้าครับ ถ้าฐานรากเราแข็งแรง (Architecture for scale) ไม่ว่าโปรเจกต์จะโตไปเป็นหลักแสนบรรทัด หรือมีนักพัฒนาเข้ามาร่วมทีมอีกกี่สิบคน โค้ดของเราก็ยังคงเป็นระเบียบ อ่านง่าย และดูแลรักษาได้อย่างมีความสุข
เมื่อเราสามารถจัดระเบียบไฟล์ต่างๆ ได้อย่างมืออาชีพแล้ว สิ่งสำคัญอีกเรื่องในฝั่ง Enterprise คือ “การเขียนเอกสาร (Documentation)” ครับ ในตอนถัดไป เราจะมาดูวิชาการใช้เครื่องมือสร้าง Document ให้กับ Component ของเรา เพื่อให้เพื่อนร่วมทีมสามารถหยิบไปใช้ได้อย่างถูกต้องโดยไม่ต้องเดินมาถามเราบ่อยๆ เตรียมตัวให้พร้อมครับ!
ต้องการที่ปรึกษาและพัฒนาระบบ Web Application หรือ Frontend Architecture ให้กับธุรกิจของคุณ? ทีมงาน WP Solution พร้อมให้บริการออกแบบและพัฒนาซอฟต์แวร์แบบครบวงจร ดูรายละเอียดบริการของเราได้ที่: www.wpsolution2017.com หรือพูดคุยปรึกษาเบื้องต้นได้ที่ Line: wisit.p