เมื่อ Rust’s Default Trait พบกับปรัชญา Essentialism

Share
เมื่อ Rust’s Default Trait พบกับปรัชญา Essentialism
Photo by Isaac Quesada on Unsplash

ในฐานะโปรแกรมเมอร์ เรามักหมกมุ่นอยู่กับการเปลี่ยนแปลง (Mutation) เราสนใจว่า State จะไหลจาก A ไป B อย่างไร แต่เรามักลืมตั้งคำถามที่สำคัญที่สุดคำถามหนึ่ง:

“ก่อนที่สิ่งนี้จะกลายเป็นสิ่งนั้น… มัน ‘เป็น’ อะไรมาก่อน?”

นี่ไม่ใช่แค่คำถามเชิงตรรกะ แต่มันคือคำถามเชิงปรัชญาที่ลึกซึ้ง และในภาษา Rust คำตอบของคำถามนี้มักจะถูกซ่อนไว้ใน Default trait

สุนทรียศาสตร์ของความว่างเปล่า: นิยามของ ‘แก่นสาร’

ในโลกของปรัชญาตะวันตก มีแนวคิดที่เรียกว่า “Essentialism” ซึ่งเชื่อว่าสรรพสิ่งมี “แก่นสาร” (Essence) ที่ทำให้มันเป็นสิ่งนั้น หากขาดแก่นสารนี้ไป สิ่งนั้นจะสูญเสียอัตลักษณ์ของมันทันที

ลองจินตนาการถึง “เครื่องดื่ม” (Type Drink) แก่นสารของมันคืออะไร? การเป็นของเหลว? การมีรสชาติ? หรือการถูกใช้เพื่อดับกระหาย? ถ้าผมสั่ง "เครื่องดื่ม" จากบาร์เทนเดอร์โดยไม่ระบุเจตจำนง ผมกำลังเรียกหาแก่นสารที่พื้นฐานที่สุดของ Type นั้น

ใน Rust, Default trait ทำหน้าที่แบบเดียวกัน มันคือการประกาศก้องว่า "นี่คือสภาวะพื้นฐานที่สุดที่ฉันดำรงอยู่ได้"

เมื่อคุณเขียนโค้ดนี้:

impl Default for Drink {
fn default() -> Self {
Self {
name: String::from("เหล้าขม"),
cost: 0,
}
}
}

คุณไม่ได้แค่เขียน Function เพื่อคืนค่าเริ่มต้น แต่คุณกำลังนิยามว่า “เครื่องดื่มจำลองในบาร์แห่งนี้มีแก่นแท้คือความขมขื่นที่ราคาถูกที่สุด”

ภัยร้ายของการมีตัวตนโดยบังเอิญ

ความมักง่ายมักนำไปสู่จุดจบที่ไม่สวยงาม นักพัฒนารุ่นใหม่หลายคนเผลอใช้ #[derive(Default)]แปะไว้บนหัว Struct โดยไม่คิดถึงแก่นสารของมัน

#[derive(Default)]
struct User {
id: u64,
name: String,
role: String,
}

ถ้าตาม Default ของ Rust ค่า id จะเป็น 0, name จะเป็น "" (String ว่าง), และ roleก็จะเป็น "" ... นี่คือการสร้าง "มนุษย์ไร้วิญญาณ" ขึ้นมาในระบบของคุณ User คนนี้ดำรงอยู่ได้โดยไม่มี ID ไม่มีชื่อ ไม่มีบทบาท มันคือขยะ (Garbage Data) ที่ถูกต้องตามกฎของ Type System แต่ผิดต่อกฎของความเป็นจริง

Essentialism สอนให้เราแยกแยะระหว่าง “สิ่งที่ติดตัวมาแต่กำเนิด” กับ “สิ่งที่โลกปรุงแต่งทีหลัง” หากสิ่งใดต้องรอ Input จากภายนอก สิ่งนั้นไม่ใช่แก่นสาร

Option และ None: แก่นสารของความไม่แน่นอน

Rust ออกแบบมาอย่างชาญฉลาดในเรื่องนี้ ลองดูที่ Option<T> แก่นสารของมันคืออะไร? ไม่ใช่ค่า Some ที่ห่อหุ้มข้อมูลมหาศาลไว้ แต่มันคือ None ความว่างเปล่าคือจุดเริ่มต้นของมัน

impl Default for Option<T> คืนค่า None เสมอ... นี่คือสภาวะพื้นฐานที่ปลอดภัยที่สุด มันคือการยอมรับว่า "ในจุดเริ่มต้น ฉันคือความไม่แน่นอน"

เช่นเดียวกับ Vec<T> แก่นสารของมันไม่ใช่ List ที่เต็มไปด้วยข้อมูลหมื่นแถว แต่มันคือ Vec::new() คือพื้นที่ว่างที่พร้อมจะรับข้อมูล การกำหนด Default แบบนี้คือการพา Type นั้นกลับไปที่ "จุดศูนย์" (Zero Point) เพื่อยืนยันว่า ต่อให้ไม่มี Input ใดๆ เลย ฉันก็ยังมีที่ยืนในหน่วยความจำ

สู่การออกแบบที่ชัดเจน

ดังนั้น ครั้งต่อไปที่คุณกำลังออกแบบ Domain Model ใน Rust ขอให้หยุดคิดสักนิด:

  1. อย่าปล่อยให้ Machine กำหนดแก่นสารแทนคุณ: จงหลีกเลี่ยงการใช้ #[derive(Default)] สำหรับ Struct ที่มี Logic ซับซ้อน ถ้าคุณต้องการ Default จง impl Default ด้วยมือของคุณเอง (Manual Implementation)
  2. ถามคำถามสุดท้าย: ก่อนที่คุณจะสั่ง ..Default::default() เพื่อเติมเต็มช่องว่างใน Struct ให้ถามตัวเองว่า "ถ้าโลกนี้ล่มสลายเหลือเพียงค่านี้ ค่านี้ยังนิยามสิ่งที่ฉันสร้างได้อยู่ไหม?" หากคำตอบคือไม่ สิ่งนั้นไม่ควรมี Default
  3. เคารพความบริสุทธิ์: ถ้า Type ของคุณไม่มีสภาวะเริ่มต้นที่สมเหตุสมผล ก็อย่าพยายามสร้างมันขึ้นมา เพียงเพื่อให้โค้ดเขียนง่ายขึ้น มันคือการบิดเบือนแก่นสาร และนั่นคือจุดเริ่มต้นของ Bug ที่แก้ยากที่สุด

ในโลกที่ซับซ้อนและเต็มไปด้วยความผิดพลาด… การมี “แก่นสาร” ที่ชัดเจนและปลอดภัย คือสิ่งเดียวที่ช่วยให้สถาปัตยกรรมของคุณรอดพ้นจากความโกลาหล

ขอให้ 0 ของคุณ คือศูนย์ที่มีความหมาย

เกี่ยวกับผู้เขียน: Uncle Quin — Software Engineer ผู้หลงใหลในการเชื่อมโยงวิศวกรรมซอฟต์แวร์เข้ากับปรัชญา


หากบทความนี้มีประโยชน์

คุณสามารถติดตาม Late Night with Uncle Quin ได้ทาง

ที่ที่เราคุยกันเรื่อง software, engineering mindset และอนาคตของ developer

แบบไม่ต้องใส่สูท

แต่ใส่ความจริงของวงการเข้าไปเต็ม ๆ

Read more

Distributed Decision Making

Distributed Decision Making

ในองค์กรใหญ่ ๆ อะไร ๆ ก็ช้าลงไปหมด และสิ่งที่ช้าที่สุดคือการตัดสินใจนี่แหละครับ การตัดสินใจกระจายอยู่ในทุก ๆ อณูขององค์กร องค์กรที่มีบรรยากาศสบาย ๆ ทุกคนรู้สึกปลอดภัย ใคร ๆ ก็จะกล้าตัดสินใจและกล้าออกความเห็น แต่พอองค์กรใหญ่

By Chokchai Phatharamalai
Risk Management: The Hard Test

Risk Management: The Hard Test

ท้ายหนังสือ Slack: Getting Past Burnout, Busywork, and the Myth of Total Efficiency ของ Tom DeMarco ได้ให้เทคนิคใหม่ในการจัดการความเสี่ยงกับผม ทอมสอนว่าในการทำงานยุคปัจจุบัน งานมีความเสี่ยงกระจายอยู่เต็มไปหมด ซึ่งในความเสี่ยงนั้น เรามีโอกาสโชคดีและมีโอกาสโชคร้าย การจัดการความเสี่ยงเป็นสิ

By Chokchai Phatharamalai
วิธีปรับเวลาการนอน

วิธีปรับเวลาการนอน

ผมเดินทางกลับมาจาก Conference ของ Berkeley ที่ซานฟรานซิสโก เครื่องลงที่สนามบินสุวรรณภูมิประมาณ 22:30 น. กว่าจะถึงบ้านก็เกือบเที่ยงคืน ยังดีที่ขากลับไม่เหนื่อยเท่าขาไป เพราะลองซื้อหมอนรองคอจาก Duty Free ที่ซานฟรานซิสโกมาใช้ดู หมอนเป็นลายการ์ตูน มีรูปสะพาน

By Chokchai Phatharamalai
เร็วแค่ไหนก็ไร้ค่า ถ้าไปผิดทาง

เร็วแค่ไหนก็ไร้ค่า ถ้าไปผิดทาง

อีกบทเรียนที่ผมได้จากหนังสือ Slack: Getting Past Burnout, Busywork, and the Myth of Total Efficiency ของ Tom DeMarco คือ ทำไมองค์กรใหญ่ ๆ ถึงยึดมั่นกับ Efficiency กันนัก Efficiency คืออะไร? Efficiency แปลว่า "ประสิทธิภาพ" ยกตัวอย่างเช่น

By Chokchai Phatharamalai