ทำไมเราต้องแยกโค้ดเป็นส่วนๆ หรือ Modules
เวลาเราเขียนโปรแกรมไปเรื่อยๆ โค้ดของเราจะเริ่มยาวขึ้นจนคุมไม่อยู่ ถ้าทุกอย่างกองรวมกันในไฟล์เดียว การหาจุดผิดหรือการแก้ไขจะกลายเป็นฝันร้ายทันที Node.js Modules System (ระบบการจัดการส่วนประกอบของโค้ด) จึงถูกสร้างขึ้นมาเพื่อแก้ปัญหานี้โดยเฉพาะครับ
เปรียบเทียบง่ายๆ เหมือนการจัดบ้าน ถ้าเราเอาของทุกอย่างในบ้านมากองรวมกันในห้องเดียว เวลาจะหาของชิ้นเล็กๆ เราคงต้องรื้อทั้งกอง แต่ถ้าเราแยกของใส่กล่องติดป้ายชื่อไว้ เช่น กล่องเครื่องมือ กล่องยา กล่องหนังสือ เวลาจะใช้งานเราแค่เดินไปหยิบกล่องนั้นมาใช้
การแยกโค้ดเป็น Modules (โมดูล หรือชิ้นส่วนโค้ดที่ทำงานเฉพาะอย่าง) ช่วยให้เรานำโค้ดกลับมาใช้ซ้ำได้ง่ายขึ้น และทำให้ทีมงานหลายคนช่วยกันเขียนโปรแกรมในโปรเจกต์เดียวกันได้โดยไม่ตีกัน เพราะแต่ละคนรับผิดชอบคนละไฟล์นั่นเองครับ
รู้จักกับ CommonJS ระบบดั้งเดิมที่คุ้นเคย
CommonJS (มาตรฐานการนำเข้าโค้ดรุ่นเก่า) เป็นระบบที่อยู่คู่กับ Node.js มาตั้งแต่ยุคแรกเริ่ม ถ้าใครเคยเห็นคำสั่ง require บ่อยๆ นั่นแหละคือสัญลักษณ์ของระบบนี้ มันถูกออกแบบมาให้ทำงานบนเซิร์ฟเวอร์โดยเฉพาะ
หลักการทำงานของมันคือการใช้ module.exports เพื่อประกาศว่าไฟล์นี้อยากส่งอะไรออกไปให้ไฟล์อื่นใช้ และใช้ require เพื่อดึงของเหล่านั้นเข้ามาใช้งาน การทำแบบนี้ช่วยให้เราเชื่อมโยงไฟล์ต่างๆ เข้าด้วยกันได้อย่างเป็นระบบ
มือใหม่ส่วนใหญ่มักจะเริ่มเรียนรู้ด้วยวิธีนี้ก่อน เพราะมันเข้าใจง่ายและเป็นค่าเริ่มต้นของ Node.js ส่วนใหญ่ แต่เราต้องระวังเรื่องการใช้ชื่อไฟล์และเส้นทางโฟลเดอร์ให้ถูกต้อง เพราะถ้าพิมพ์ชื่อไฟล์ผิดแม้แต่นิดเดียว โปรแกรมจะหาไม่เจอทันที
// ไฟล์ math.js (ไฟล์สำหรับคำนวณ)
const add = (a, b) => a + b;
module.exports = { add }; // ส่งออกฟังก์ชัน add
// ไฟล์ app.js (ไฟล์หลัก)
const math = require('./math.js'); // ดึงฟังก์ชันมาจากไฟล์ math
console.log(math.add(5, 3)); // แสดงผลลัพธ์
ในไฟล์ math.js เราใช้ module.exports เพื่อเปิดเผยฟังก์ชัน add ออกไปข้างนอก ส่วนในไฟล์ app.js เราใช้ require เพื่อเรียกใช้ฟังก์ชันนั้นผ่านตัวแปร math สังเกตว่าเราต้องใส่ ./ เพื่อบอกว่าไฟล์อยู่ในโฟลเดอร์เดียวกัน ผลลัพธ์ที่ได้คือเลข 8 ปรากฏบนหน้าจอครับ
ขยับมาใช้ ES Modules มาตรฐานใหม่ของวงการ
ES Modules (มาตรฐานการนำเข้าโค้ดรูปแบบใหม่) หรือที่เรียกย่อๆ ว่า ESM คือมาตรฐานใหม่ที่ถูกนำมาใช้ในภาษา JavaScript ทั้งบนเบราว์เซอร์และ Node.js มันถูกออกแบบมาให้ทันสมัยและรองรับการทำงานที่ซับซ้อนได้ดีกว่าเดิม
จุดเด่นที่ต่างออกไปคือการใช้คำสั่ง export เพื่อส่งออก และ import เพื่อนำเข้า แทนที่แบบเดิม การใช้ระบบนี้ช่วยให้ตัวโปรแกรมทำงานได้เร็วขึ้น เพราะมันสามารถตรวจสอบโค้ดได้ตั้งแต่ก่อนเริ่มรันโปรแกรมจริงๆ
ในการเปลี่ยนมาใช้ระบบนี้ เราต้องบอกให้ Node.js รู้ก่อน โดยการตั้งค่าในไฟล์ package.json (ไฟล์บันทึกข้อมูลและตั้งค่าโปรเจกต์) ให้มีค่าเป็น "type": "module" ไม่อย่างนั้นระบบจะเข้าใจว่าเป็น CommonJS แบบเดิมครับ
// ไฟล์ math.js
export const add = (a, b) => a + b; // ส่งออกโดยตรง
// ไฟล์ app.js
import { add } from './math.js'; // นำเข้าเฉพาะสิ่งที่ต้องการ
console.log(add(5, 3));
ในตัวอย่างนี้เราใช้ export นำหน้าฟังก์ชันได้เลย และในไฟล์ app.js เราใช้เครื่องหมายปีกกา { add } เพื่อเลือกดึงเฉพาะฟังก์ชันที่ต้องการมาใช้งาน วิธีนี้ช่วยให้โค้ดสะอาดตาและอ่านง่ายขึ้นมาก ผลลัพธ์ที่ได้จากการรันคือเลข 8 เช่นเดิมครับ
ความต่างที่ต้องรู้ก่อนเริ่มเขียน
ความแตกต่างที่สำคัญที่สุดคือเรื่องของ Synchronous (การทำงานแบบทีละขั้นตอน) ใน CommonJS ที่ทำงานแบบรอให้เสร็จทีละบรรทัด ในขณะที่ ES Modules ถูกออกแบบมาให้รองรับการทำงานแบบ Asynchronous (การทำงานที่ไม่ต้องรอให้จบทีละขั้นตอน) ได้ดีกว่า
ข้อควรระวังสำหรับมือใหม่คือเรื่องของไฟล์ .js และ .mjs หากเราไม่ได้ตั้งค่าใน package.json การเปลี่ยนนามสกุลไฟล์เป็น .mjs จะช่วยให้ Node.js บังคับใช้ระบบ ES Modules ได้ทันทีโดยไม่ต้องไปแก้ไฟล์ตั้งค่า
อีกจุดที่มักจะพลาดกันคือการใช้ __dirname (ตัวแปรที่บอกที่อยู่ของโฟลเดอร์ปัจจุบัน) ซึ่งใน CommonJS เราใช้งานได้เลย แต่ใน ES Modules ตัวแปรนี้จะไม่มีอยู่ ทำให้เราต้องเขียนคำสั่งเรียกใช้ขึ้นมาเองหากจำเป็นต้องอ้างอิงตำแหน่งไฟล์ครับ
คำแนะนำในการเลือกใช้สำหรับมือใหม่
ถ้าคุณกำลังฝึกเขียนโปรเจกต์แรก ผมแนะนำให้เริ่มลองใช้ ES Modules ไปเลยครับ เพราะมันเป็นมาตรฐานที่โลกปัจจุบันหันมาใช้กันหมดแล้ว และการเรียนรู้สิ่งใหม่ที่ถูกต้องตั้งแต่ต้นจะช่วยให้คุณไม่เสียเวลามานั่งแก้โค้ดเก่าในอนาคต
อย่างไรก็ตาม การเข้าใจ CommonJS ก็ยังจำเป็นอยู่ดี เพราะโปรเจกต์งานบริษัทเก่าๆ หรือไลบรารี (ชุดคำสั่งสำเร็จรูป) จำนวนมากยังคงเขียนด้วยระบบนี้อยู่ การอ่านโค้ดสองแบบออกจะทำให้คุณได้เปรียบเวลาไปทำงานจริง
อย่ากลัวที่จะสลับไปมาในช่วงแรกครับ ถ้าเจอโปรเจกต์ที่ใช้ require ให้มองว่าเป็นเรื่องของการเรียนรู้ประวัติศาสตร์การพัฒนาซอฟต์แวร์ ส่วนโปรเจกต์ส่วนตัวที่ทำเอง ให้เน้นใช้ import เพื่อฝึกฝนทักษะที่ทันสมัยไว้เสมอครับ
สรุป: เลือกใช้ให้เป็นและปรับใช้ให้ถูกงาน
การแบ่งโมดูลไม่ใช่แค่เรื่องของคำสั่ง แต่เป็นเรื่องของการจัดระเบียบความคิด หากคุณต้องการสร้างโปรเจกต์เล็กๆ ที่ใช้ไลบรารีเก่าเยอะ CommonJS คือเพื่อนที่ดี แต่ถ้าคุณต้องการเขียนโปรเจกต์ใหม่ที่รองรับมาตรฐานสากล ES Modules คือคำตอบ
สมมติว่าคุณกำลังสร้างแอปพลิเคชันจัดการรายการสินค้า คุณควรแยกไฟล์ database.js สำหรับเชื่อมต่อฐานข้อมูล และไฟล์ product.js สำหรับจัดการข้อมูลสินค้า โดยใช้ export และ import เชื่อมต่อกัน จะทำให้โค้ดของคุณดูเป็นมืออาชีพและจัดการง่ายมากครับ
หัวใจสำคัญคือการแยกส่วนที่ทำงานต่างกันออกจากกัน ไม่ว่าคุณจะเลือกใช้ระบบไหน สิ่งที่สำคัญที่สุดคือการตั้งชื่อไฟล์และชื่อฟังก์ชันให้สื่อความหมาย เพื่อให้คุณและเพื่อนร่วมทีมอ่านโค้ดแล้วเข้าใจได้ทันทีโดยไม่ต้องถามกันบ่อยๆ ครับ