เมื่อ 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

เริ่มต้นกับ Functional Programming

เริ่มต้นกับ Functional Programming

ก่อนหน้านี้ผมเจอโพสต์หนึ่งถามว่า สำหรับคนที่เคยใช้แต่ OOP จะเริ่มต้นกับ Functional Programming ควรเริ่มยังไงดี ผมชอบคำตอบที่ตัวเองตอบไป เลยอยากเอามาจดเก็บไว้ ฝันร้ายของโปรแกรมเมอร์ ก่อนจะเข้าไปใน programming แต่ละ paradigm ผมอยากเริ่มต้นที่ปัญหาก่อน หนึ่งในปัญหาที่หลอกหลอนโปรแกรมเมอร์มากที่สุด คื

By Chokchai Phatharamalai
Values ของ Framework ต่าง ๆ

Values ของ Framework ต่าง ๆ

ผมหาคุณค่า (Values) ของผมเจอจากการสังเกตความต้องการที่มักจะมาหาผมบ่อย ๆ ทั้งตอนที่มันได้รับการตอบสนองและทำให้ผมรู้สึกดีมาก ๆ รวมถึงตอนที่มันไม่ได้รับการตอบสนองและทำให้ผมปั่นป่วนมาก ๆ พอความต้องการไหนมาเคาะประตูใจผมบ่อย ๆ ผมก็เริ่มพิจารณาว่าความต้องการนี้แหละที่เป็น Value หนึ่งสำหรั

By Chokchai Phatharamalai
Accepted Responsibility

Accepted Responsibility

ช่วงนี้ผมกำลังอ่านหนังสือ Extreme Programming Explained ของ Kent Beck แล้วก็ได้เจอหัวข้อหนึ่งที่กระทบใจ คือ principle ที่เรียกว่า Accepted Responsibility Principle คืออะไร? ในหนังสืออธิบายว่า Principle คือหลักการที่ทำให้ Values ของ XP กลายเป็น Practices ได้

By Chokchai Phatharamalai
The Five Ideals

The Five Ideals

จากหนังสือ The Unicorn Project ในนั้นจะมีที่ปรึกษาเก่ง ๆ คนหนึ่งชื่อ Erik เป็นเหมือนเซ็นเซหาตัวยาก เดี๋ยวก็มา เดี๋ยวก็ไป ถ้าโชคดีก็จะเจอเค้าว่าง แล้วเค้าก็จะสอนอะไรที่สำคัญ ๆ แต่ฟังดูล้ำ ๆ และลึกซึ้ง

By Chokchai Phatharamalai