Tuple: ปรัชญาของการปูเสื่อ และศิลปะแห่งการไม่ตั้งชื่อ
ในโลกของการเขียนโปรแกรม เรามักถูกสอนให้เป็น “นักจัดระเบียบ” เราสร้างคลาส สร้าง Struct ตั้งชื่อตัวแปรให้สื่อความหมาย (Clean Code) แต่บางครั้ง ความเคร่งครัดที่มากเกินไปอาจกลายเป็นพันธนาการที่ทำให้ Code ของเราอุ้ยอ้ายโดยไม่จำเป็น
1. Naming Fatigue: ภาระของการมีตัวตน
ลองนึกภาพคุณได้รับโจทย์ง่ายๆ อย่างการ “เรียงลำดับลูกค้าตามยอดใช้จ่าย”
ในหัวของคุณจะเริ่มทำงานทันที:
- ฉันมีก้อนข้อมูลลูกค้า (
Customer) - ฉันคำนวณยอดซื้อออกมาได้เป็นตัวเลข (
TotalSpend) - ฉันต้องเอาสองอย่างนี้มา “มัดรวมกัน” เพื่อส่งไปให้ฟังก์ชัน Sort
วินาทีนั้นเองที่ Naming Fatigue หรือการตั้งชื่อจะเริ่มทำงานและทำให้คุณเหนื่อยล้า คุณจะเริ่มตั้งคำถามว่า “ฉันต้องตั้งชื่อ Struct นี้ว่าอะไรดี? CustomerWithSpend? SortedCustomerWrapper? หรือ SpendingResult?"
นักคณิตศาสตร์มองเหตุการณ์นี้ต่างออกไปครับ เขาจะบอกว่า “คุณจะเหนื่อยตั้งชื่อไปทำไม ในเมื่อความสัมพันธ์นี้มันเกิดขึ้นเพียงแค่เสี้ยววินาทีตอนที่คุณจะ Sort เท่านั้น พอ Sort เสร็จ ข้อมูลก้อนนี้ก็ต้องถูกสลายร่างทิ้งไปอยู่ดี”
นี่คือสิ่งที่ผมเรียกว่า “สถานการณ์นัดบอด” ความสัมพันธ์บางอย่างใน Code ถูกออกแบบมาเพื่อ “พบกันชั่วคราวเพื่อทำภารกิจบางอย่างให้สำเร็จ” แล้วแยกย้าย การฝืนสร้าง Struct ถาวรขึ้นมา ไม่ต่างอะไรกับการเดินไปซื้อน้ำเปล่าหนึ่งขวด แล้วร้านบังคับให้คุณจดทะเบียนบริษัทร่วมทุนเพียงเพื่อจะรับเงินทอน มันคือ Definition Overhead ที่ทำให้ระบบหนักอึ้งเกินความจำเป็น
2. Structural Meaning: เมื่อ “ลำดับ” คือนิยาม
หลายคนอาจเถียงว่า “แต่มันดูไม่รู้เรื่องนะ! ถ้าเห็น (10, “Water”) ผมจะรู้ได้ไงว่า 10 คือราคาหรือจำนวน?”
แต่ถ้าเป็นตัวอย่างเช่น (TotalSpend, Customer) ความอึดอัดจะหายไปทันที
ทำไมล่ะครับ? ทั้งที่เป็น Tuple เหมือนกัน?
นั่นเป็นเพราะในทางคณิตศาสตร์ “ลำดับ” (Position) คือ “นิยาม” รูปแบบหนึ่ง เราเรียกว่า Structural Meaning
- ลองนึกถึงพิกัดทางแผนที่ (x,y) โลกตกลงกันแล้วว่าตัวแรกคือแนวนอน ตัวหลังคือแนวตั้ง
- ถ้าเราต้องเขียน
Location { x_axis: 10, y_axis: 20 }ทุกครั้งที่คำนวณสมการฟิสิกส์ล้านบรรทัด "ชื่อ" จะกลายเป็น Visual Noise (ขยะทางสายตา) ที่บดบังใจความสำคัญของสูตรไปจนหมด
ในภาษาอย่าง Rust การใช้ Tuple คือการบอกว่า “ความหมายสมบูรณ์ในโครงสร้างแล้ว” เมื่อเราเห็น (u64, Customer) ในบริบทการจัดลำดับ เราไม่ต้องถามชื่อ Field เพราะเรารู้ว่าตัวแรกคือ "ค่าที่ใช้เปรียบเทียบ"
3. ปรัชญาของการปูเสื่อ vs. การสร้างบ้าน
ผมขอสรุปเชิงเปรียบเทียบเรื่องข้อมูลกับที่อยู่อาศัยไว้แบบนี้ครับ:
- Struct คือการสร้าง “บ้านที่มีเลขที่บ้าน” (ถาวร, ชัดเจน, ส่งต่อให้คนอื่นได้)
- Tuple คือการ “ปูเสื่อนั่งในสวนสาธารณะ” (ชั่วคราว, ไร้ร่องรอย, จบแล้วแยกย้าย)
ถ้าชีวิตเราต้องสร้างบ้านรองรับทุกกิจกรรม สวนสาธารณะคงเต็มไปด้วยตึกร้างที่ไม่มีคนอยู่ ใน Code ก็เช่นกันครับ ฟังก์ชันอย่าง split_at(n) ที่หั่น String ออกเป็นสองส่วน ถ้าส่งกลับมาเป็น Struct อย่าง SplitResult คุณจะเอาชื่อนี้ไปใช้ที่ไหนต่อไหม? ส่วนใหญ่คือ "ไม่" ครับ
let (left, right) = s.split_at(5);
การใช้ Tuple ตรงนี้คือความสง่างาม มันทำหน้าที่เป็น “ถาดคืนของ” ที่ส่งของให้คุณแล้วหายไป ไม่ทิ้งรอยนิยามใดๆ ไว้ให้รกสมองเพื่อนร่วมทีม
บทสรุป: หาจุดสมดุล (The Balance)
Tuple ไม่ใช่ศัตรูของระเบียบ และไม่ใช่เครื่องมือของคนขี้เกียจ แต่มันคือเครื่องมือของคนที่เข้าใจว่า “ไม่ใช่ทุกอย่างในจักรวาลที่คู่ควรกับการมีชื่อเรียก”
ในฐานะ Software Architect/ Software Engineer หน้าที่ของเราคือการหา Balance:
- Core Logic ที่ต้องสื่อสารกับคนจำนวนมาก: จงสร้างบ้าน (Struct)
- Intermediate Step ที่เกิดขึ้นชั่วคราวเพื่อประมวลผล: จงปูเสื่อ (Tuple)
อย่าให้ “ความเคร่งครัด” กลายเป็น “พันธนาการ” ที่ทำให้ Code ของคุณเคลื่อนที่ช้าลง บางครั้ง… การปล่อยให้ข้อมูลมันลื่นไหลไปตามโครงสร้างของมันเอง ก็คือระเบียบที่สง่างามที่สุดเท่าที่มนุษย์จะออกแบบได้ครับ
หากบทความนี้มีประโยชน์
คุณสามารถติดตาม Late Night with Uncle Quin ได้ทาง
ที่ที่เราคุยกันเรื่อง software, engineering mindset และอนาคตของ developer
แบบไม่ต้องใส่สูท
แต่ใส่ความจริงของวงการเข้าไปเต็ม ๆ