IT General
น้องๆ เคยเจอปัญหาโปรเจกต์ใหญ่ๆ ที่โค้ดมันกระจัดกระจายไปหลาย Repository มั้ย? สมัยผมทำร้านเน็ตนี่คือปวดหัวมาก เวลาแก้บั๊กทีต้องไล่แก้หลายที่ แถมตอน Deploy นี่วุ่นวายสุดๆ Monorepo นี่แหละคือทางออก
Monorepo คือการเอาโค้ดทั้งหมดของโปรเจกต์ (หรือหลายโปรเจกต์ที่เกี่ยวข้องกัน) มารวมไว้ใน Repository เดียว ฟังดูน่ากลัวใช่มะ แต่จริงๆ แล้วมันช่วยให้เราจัดการโค้ดได้ง่ายขึ้นเยอะเลยนะ
Turborepo กับ Nx เนี่ย เป็น Tool ที่เข้ามาช่วยจัดการ Monorepo ให้มันง่ายและมีประสิทธิภาพมากขึ้น Turborepo นี่เน้นความเร็วในการ Build ส่วน Nx นี่ฉลาดกว่าหน่อย มันรู้ว่าโค้ดส่วนไหนเปลี่ยนแปลงไปบ้าง จะได้ Build แค่ส่วนที่จำเป็นจริงๆ
ทำไม Monorepo ถึงสำคัญ? ลองนึกภาพตามนะ สมัยก่อนเวลาเราแก้ Component ตัวนึงที่ใช้ในหลายๆ ที่ เราต้องแก้ในแต่ละ Repository แล้ว Deploy ใหม่หมด แต่ถ้าเป็น Monorepo เราแก้ที่เดียว Deploy ที่เดียวจบ! ชีวิตง่ายขึ้นเยอะ
ก่อนจะไปลุย Monorepo สิ่งที่น้องๆ ต้องรู้พื้นฐานก่อนก็คือเรื่อง Git นี่แหละ เพราะเราต้องจัดการโค้ดจำนวนมากใน Repository เดียว ถ้าไม่คล่อง Git นี่คือเหนื่อยแน่นอน
อีกเรื่องที่สำคัญคือเรื่อง Package Manager พวก npm, yarn, pnpm พวกนี้แหละ เพราะเราต้องจัดการ Dependencies ของแต่ละโปรเจกต์ย่อยใน Monorepo
สุดท้ายคือเรื่อง JavaScript/TypeScript นี่แหละ เพราะ Tool ส่วนใหญ่ที่ใช้กับ Monorepo จะเป็นภาษาเหล่านี้
เอาล่ะ มาดูวิธีเริ่มต้นใช้งาน Monorepo กันดีกว่า ผมจะยกตัวอย่างการใช้ Turborepo นะ เพราะมันง่ายดี
อันดับแรกเลย น้องๆ ต้องมี Node.js กับ npm/yarn/pnpm ติดตั้งอยู่ในเครื่องก่อนนะ
1. สร้าง Folder โปรเจกต์เปล่าๆ ขึ้นมา แล้ว Initialize npm หรือ yarn หรือ pnpm ก็ได้
mkdir my-monorepo
cd my-monorepo
yarn init -y
2. ติดตั้ง Turborepo
yarn add turbo -D
3. สร้าง Folder `packages` ขึ้นมา เอาไว้เก็บโปรเจกต์ย่อยๆ ของเรา เช่น `packages/ui` สำหรับ Component Library, `packages/api` สำหรับ Backend API
4. สร้างไฟล์ `turbo.json` ใน Root ของโปรเจกต์ กำหนด Task ที่เราต้องการให้ Turborepo Run
{
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": [".next/**", "dist/**"]
},
"lint": {},
"dev": {
"cache": false,
"persistent": true
}
}
}
5. แก้ไข `package.json` เพิ่ม Script สำหรับ Run Task ต่างๆ
{
"name": "my-monorepo",
"version": "1.0.0",
"private": true,
"workspaces": ["packages/*"],
"scripts": {
"build": "turbo run build",
"dev": "turbo run dev --parallel",
"lint": "turbo run lint",
"test": "turbo run test"
},
"devDependencies": {
"turbo": "^1.10.16"
}
}
แค่นี้เอง! น้องๆ ก็พร้อมที่จะเริ่มสร้างโปรเจกต์ใน Monorepo แล้ว ลองเข้าไปดูใน SiamCafe Blog สิ ผมเคยเขียนเรื่องนี้ไว้ละเอียดกว่านี้อีกนะ
จริงๆ แล้ว Monorepo ไม่ใช่ทางเลือกเดียวในการจัดการโค้ดนะ มันยังมีทางเลือกอื่นอีก เช่น Polyrepo ซึ่งก็คือการแยกโค้ดแต่ละส่วนออกเป็น Repository ใครใครมันไปเลย
แต่ข้อเสียของ Polyrepo ก็คือมันจัดการยาก เวลาแก้บั๊กทีต้องไล่แก้หลายที่ Deploy ก็วุ่นวายอย่างที่บอกไป Monorepo เลยเข้ามาแก้ปัญหานี้แหละ
อีกทางเลือกนึงก็คือ Modular Monolith ซึ่งก็คือการเอาโค้ดทั้งหมดมารวมไว้ในโปรเจกต์เดียว แต่แบ่งเป็น Module ย่อยๆ ข้อดีคือมันง่ายกว่า Monorepo แต่ข้อเสียคือมันอาจจะ Scale ยากกว่า
ลองดูตารางเปรียบเทียบข้อดีข้อเสียของแต่ละทางเลือกดูนะ
| ทางเลือก | ข้อดี | ข้อเสีย |
|---|---|---|
| Monorepo | จัดการ Dependencies ง่าย, แก้บั๊กง่าย, Deploy ง่าย | ซับซ้อน, ต้องใช้ Tool ช่วย |
| Polyrepo | ง่าย, ไม่ต้องใช้ Tool อะไรมาก | จัดการ Dependencies ยาก, แก้บั๊กยาก, Deploy ยาก |
| Modular Monolith | ง่ายกว่า Monorepo, ไม่ต้องใช้ Tool อะไรมาก | Scale ยากกว่า |
สรุปแล้ว Monorepo เหมาะกับโปรเจกต์ขนาดใหญ่ที่มีหลายทีมทำงานร่วมกัน หรือโปรเจกต์ที่ต้องการ Share Code ระหว่างกัน ถ้าโปรเจกต์เล็กๆ อาจจะใช้ Modular Monolith ก็ได้ แต่ถ้าโปรเจกต์ใหญ่มากๆ และต้องการความยืดหยุ่น Monorepo นี่แหละคือคำตอบ
น้องๆ ลองเอาไปปรับใช้กับโปรเจกต์ของตัวเองดูนะ ถ้าติดขัดตรงไหนก็ลองมาถามใน SiamCafe Blog ได้เลย ผมยินดีให้คำปรึกษาเสมอ :)
เอาล่ะน้องๆ หลังจากที่เราปูพื้นเรื่อง Monorepo, Turborepo, Nx กันไปแล้ว คราวนี้มาถึงของจริง "ประสบการณ์" ที่พี่บอมอยากจะแชร์ให้ฟังกันบ้าง สมัยผมทำร้านเน็ตฯ นี่คือโคตรยุ่งเลยนะ ต้องดูแลทั้ง Hardware Software แถมยังต้องมานั่งปวดหัวกับเรื่อง Network อีก ชีวิตมันไม่ง่ายเหมือนเขียนโค้ดอย่างเดียวหรอก แต่เชื่อเถอะ ทุกอย่างมันสอนเราได้
เรื่อง Monorepo เนี่ย พี่ว่ามันเหมือนกับการที่เรามีบ้านหลังใหญ่ ที่ทุกอย่างอยู่รวมกันหมด ถามว่าดีไหม? ดี! แต่ต้องจัดระเบียบให้ดีนะ ไม่งั้นบ้านรก หาอะไรก็ไม่เจอ เหมือน Codebase เรานั่นแหละ
ต่อไปนี้เป็นเทคนิคที่พี่ว่าเวิร์คจริง ลองเอาไปปรับใช้กันดูนะ
#!/bin/sh
# .git/hooks/pre-commit
echo "Running linters..."
npm run lint
echo "Running tests..."
npm run test
# If any of the above commands fail, exit with a non-zero code
if [ $? -ne 0 ]; then
echo "Commit aborted due to linting or testing errors."
exit 1
fi
ตัวอย่าง Folder Structure:
apps/
web/
src/
components/
pages/
mobile/
src/
components/
screens/
libs/
ui/
api/
// Example using a simple boolean flag
const isNewFeatureEnabled = process.env.NEW_FEATURE === 'true';
if (isNewFeatureEnabled) {
// Render the new feature
} else {
// Render the old feature
}
Monorepo เหมาะกับ Project ที่มีหลาย Packages/Applications ที่ต้องทำงานร่วมกัน หรือแชร์ Code ร่วมกัน ถ้า Project เล็กๆ อาจจะ Overkill ไปหน่อย
Turborepo เน้นเรื่อง Caching และ Parallel Execution ส่วน Nx จะมี Feature เยอะกว่า เช่น Code Generation, Dependency Graph, Automated Refactoring
ใช้ Tools อย่าง Turborepo หรือ Nx นี่แหละ! มันจะช่วย Optimize Build Time ได้เยอะมาก นอกจากนี้ก็พยายาม Optimize Code ของเราเองด้วย
ใช้ Package Manager ที่ Support Workspace อย่าง npm, yarn, pnpm จะช่วยให้ Dependency Management ง่ายขึ้นเยอะ
Monorepo เป็น Architecture ที่มีข้อดีข้อเสียของมันเอง ต้องเลือกใช้ให้เหมาะสมกับ Project ของเรา สิ่งสำคัญที่สุดคือการจัดระเบียบ Codebase ให้ดี และใช้ Tools ที่เหมาะสมมาช่วยจัดการ iCafeForex ก็เคยเจอปัญหาคล้ายๆ กันตอน Scale ระบบ พี่บอมหวังว่าบทความนี้จะเป็นประโยชน์กับน้องๆ นะ ถ้าอยากอ่านเรื่อง IT สนุกๆ อีก ก็แวะมาที่ SiamCafe Blog ได้เลย!
| หัวข้อ | คำอธิบาย |
|---|---|
| Monorepo | ที่เก็บ Code หลาย Projects ใน Repository เดียว |
| Turborepo | เครื่องมือ Build System ที่เน้น Caching และ Parallel Execution |
| Nx | เครื่องมือ Development Framework ที่มี Feature เยอะกว่า Turborepo |