การเดินทางของนักพัฒนาคนหนึ่งในการค้นหาภาษาโปรแกรมมิ่งที่สมบูรณ์แบบสำหรับสร้างแอปพลิเคชันเดสก์ท็อปแบบ native ได้จุดประกายการถกเถียงอย่างรุนแรงเกี่ยวกับความซับซ้อนของภาษา การจัดการหน่วยความจำ และความหมายที่แท้จริงของความเรียบง่ายในการเขียนโปรแกรม นักพัฒนาคนนี้ซึ่งใช้ TypeScript เป็นหลัก ต้องการสร้างตัวแทนของ xfdesktop ที่มีพื้นหลังแบบเคลื่อนไหว แต่กลับพบว่าตัวเองตั้งคำถามว่าภาษาที่ชื่นชอบจะสามารถผลิตไบนารีแบบ native ที่แข็งแกร่งได้จริงหรือไม่
การคัดออกภาษาโปรแกรมมิ่งครั้งใหญ่
กระบวนการคัดออกของนักพัฒนาเผยให้เห็นการแลกเปลี่ยนแบบคลาสสิกในภาษาโปรแกรมมิ่งสมัยใหม่ TypeScript แม้จะเสนอระดับการแยกแยะที่สมบูรณ์แบบ แต่ก็มีข้อจำกัดเมื่อต้องผลิตไฟล์ปฏิบัติการแบบ native แม้ว่าเครื่องมืออย่าง Bun และ Deno สามารถคอมไพล์ TypeScript เป็นไบนารีได้ แต่ไฟล์ที่ได้มักมีขนาด 60MB หรือใหญ่กว่า ซึ่งแทบจะไม่รู้สึกแข็งแกร่งสำหรับแอปพลิเคชันเดสก์ท็อป
C++ ถูกปฏิเสธอย่างรวดเร็วแม้จะมีพลัง นักพัฒนาอธิบายว่าใช้เวลาหนึ่งปีเดินไปรอบๆ ในความตื่นตาตื่นใจของ std::vector และ RAII ก่อนจะตระหนักว่าตัวเองกำลังสร้างความซับซ้อนที่ไม่เกี่ยวข้องกับปัญหาที่ต้องแก้ไข ความรู้สึกนี้สะท้อนกับโปรแกรมเมอร์หลายคนที่พบว่าสภาพแวดล้อมที่เต็มไปด้วยฟีเจอร์ของ C++ นั้นท่วมท้นสำหรับการพัฒนาในทางปฏิบัติ
การเปรียบเทียบขนาดไฟล์ Binary สำหรับการ Compile TypeScript
- ไฟล์ Binary ที่ Compile ด้วย Bun : ขนาดขั้นต่ำ ~60MB + source code
- ไฟล์ Binary ที่ Compile ด้วย Deno : มีข้อจำกัดด้านขนาดในลักษณะเดียวกัน
- ภาษาโปรแกรมแบบ Native แบบดั้งเดิม ( C / Rust / Go ): โดยทั่วไปมีขนาด <10MB สำหรับแอปพลิเคชันที่คล้ายกัน
การถกเถียงเรื่องความเรียบง่ายเริ่มร้อนแรง
การอ้างของบทความที่ว่า C เสนอความเรียบง่ายในการตรวจสอบโค้ดที่เหนือกว่าได้จุดประกายการต่อต้านอย่างรุนแรงจากชุมชนโปรแกรมเมอร์ ผู้วิพากษ์วิจารณ์ชี้ให้เห็นว่าความเรียบง่ายที่เห็นได้ชัดของ C นั้นส่วนใหญ่เป็นเพียงผิวเผิน ซ่อนความซับซ้อนที่อันตรายอย่าง race conditions การแพร่กระจายของ null pointer และ undefined behavior ที่สามารถทำให้เกิดปฏิกิริยาแปลกๆ จากระยะไกล
แล้ว race conditions, null pointers ที่แพร่กระจายทางอ้อมเข้าไปในฟังก์ชันที่ไม่คาดหวัง null, aliased pointers ที่แพร่กระจายทางอ้อมเข้าไปในฟังก์ชัน restrict และสาเหตุ UB แบบ non-local อื่นๆ ล่ะ?
ชุมชนโต้แย้งว่าแม้ syntax ของ C อาจเรียบง่าย แต่ภาระทางความคิดในการรับประกันความปลอดภัยของหน่วยความจำและการหลีกเลี่ยง undefined behavior ทำให้มันไม่เรียบง่ายในทางปฏิบัติ ภาษาสมัยใหม่อย่าง Rust ผลักดันความซับซ้อนนี้เข้าไปในระบบประเภท ซึ่งคอมไพเลอร์สามารถจับข้อผิดพลาดก่อนที่จะกลายเป็นหายนะในขณะรันไทม์
การจัดการหน่วยความจำ: ขอบเขตสุดท้าย
การเลือก Rust ในที่สุดของนักพัฒนา แม้จะชอบการจัดการหน่วยความจำแบบอัตโนมัติ เน้นย้ำถึงความเข้าใจผิดที่สำคัญเกี่ยวกับวิธีการทำงานของ Rust จริงๆ ไม่เหมือน C หรือ C++, Rust ไม่ต้องการการจัดการหน่วยความจำแบบแมนนวลในความหมายแบบดั้งเดิม แต่ใช้การวิเคราะห์ในเวลาคอมไพล์เพื่อรับประกันความปลอดภัยของหน่วยความจำ โดยคอมไพเลอร์จัดการงานหนัก
นักพัฒนา Rust ที่มีประสบการณ์หลายคนเน้นย้ำว่าแอปพลิเคชันส่วนใหญ่ไม่ค่อยต้องการ lifetime annotations ที่ชัดเจนหรือการจัดการหน่วยความจำที่ซับซ้อน ภาษานี้มีช่องทางหลบหนีอย่าง Arc (atomic reference counting) และ RefCell สำหรับกรณีที่กฎของ borrow checker เข้มงวดเกินไป ทำให้นักพัฒนาสามารถเลือกใช้การตรวจสอบในขณะรันไทม์เมื่อจำเป็น
ตารางเปรียบเทียบภาษาโปรแกรม
ภาษา | การคอมไพล์แบบ Native | การแยกแยะระดับสูง | การจัดการหน่วยความจำอัตโนมัติ |
---|---|---|---|
C | ✓ | ✗ | ✗ |
Go | ✓ | ✗ | ✓ |
TypeScript | ✗ | ✓ | ✓ |
Rust | ✓ | ✓ | ✗* |
การตรวจสอบความเป็นจริงของระบบนิเวศ
การอภิปรายเผยให้เห็นข้อมูลเชิงลึกที่น่าสนใจเกี่ยวกับระบบนิเวศของภาษาและความเป็นผู้ใหญ่ของพวกมัน แม้ว่าบางคนจะแนะนำทางเลือกอื่นอย่าง OCaml, Swift หรือ Nim ที่อาจเหมาะกับเกณฑ์ของนักพัฒนามากกว่า แต่ภาษาเหล่านี้มักขาดระบบนิเวศที่แข็งแกร่งและเครื่องมือที่ Rust สร้างขึ้นมาในช่วงทศวรรษที่ผ่านมา
ชุมชนยังเน้นย้ำว่าภาษาต่างๆ เก่งในโดเมนที่แตกต่างกัน ความเรียบง่ายของ Go ทำให้เหมาะสำหรับแอปพลิเคชันเซิร์ฟเวอร์ ในขณะที่การรับประกันความปลอดภัยของ Rust ทำให้เหมาะสำหรับการเขียนโปรแกรมระบบ TypeScript ยังคงไม่มีใครเทียบได้สำหรับการพัฒนาเว็บ แต่ดิ้นรนเมื่อประสิทธิภาพแบบ native กลายเป็นสิ่งสำคัญ
ภาษาทางเลือกที่ชุมชนแนะนำ
- OCaml: การคอมไพล์แบบ native, การเขียนโปรแกรมเชิงฟังก์ชัน, การจัดการหน่วยความจำอัตโนมัติ
- Swift: รองรับการทำงานข้ามแพลตฟอร์ม, ความปลอดภัยของหน่วยความจำ, การผสานรวมกับระบบนิเวศ Apple
- Nim: คอมไพล์เป็น C/C++/JavaScript, ไวยากรณ์คล้าย Python
- Zig: ระดับต่ำกว่า Rust, ตัวจัดสรรหน่วยความจำที่ชัดเจน, ความสามารถในการทำงานร่วมกับ C
บทสรุป
กระบวนการเลือกภาษาของนักพัฒนาคนนี้แสดงให้เห็นวิวัฒนาการที่กำลังดำเนินอยู่ในการออกแบบภาษาโปรแกรมมิ่ง การแลกเปลี่ยนแบบดั้งเดิมระหว่างความปลอดภัย ประสิทธิภาพ และความง่ายในการใช้งานกำลังถูกท้าทายโดยภาษาอย่าง Rust ที่พยายามให้ทั้งสามอย่าง แม้ว่าเส้นโค้งการเรียนรู้อาจชันแต่ฉันทามติของชุมชนที่เติบโตขึ้นแสดงให้เห็นว่าแนวทางของ Rust ในการย้ายความซับซ้อนจากรันไทม์ไปยังคอมไพล์ไทม์แสดงถึงการปรับปรุงพื้นฐานในวิธีที่เราคิดเกี่ยวกับการเขียนโปรแกรมระบบ
การถกเถียงยังเผยให้เห็นว่าความเข้าใจของเราเกี่ยวกับความเรียบง่ายในการเขียนโปรแกรมยังคงพัฒนาต่อไป ความเรียบง่ายที่แท้จริงอาจไม่ใช่การมีฟีเจอร์ของภาษาน้อยลง แต่เป็นการมีวิธีที่สิ่งต่างๆ จะผิดพลาดในการผลิตน้อยลง
อ้างอิง: A Rust shaped hole