หลักการออกแบบ API ในภาษา Rust: รับมือกับการเปลี่ยนแปลงประเภทข้อมูลอย่างไรไม่ให้พัง
เจาะลึกเทคนิคการออกแบบ API ขั้นสูงในภาษา Rust เมื่อต้องแก้ไขประเภทข้อมูลและวิธีป้องกันไม่ให้โค้ดฝั่งผู้ใช้งานพังเสียหาย

ภาพประกอบจากคลังภาพสต็อก ไม่ใช่ภาพจากเหตุการณ์จริง
- คิดให้รอบคอบก่อนปรับเปลี่ยนอินเทอร์เฟซที่ผู้ใช้งานมองเห็นได้
- การปล่อยเวอร์ชันที่ไม่รองรับการถอยหลังบ่อยครั้งจะทำให้ผู้ใช้งานไม่พอใจ
- การจำกัดการมองเห็นของประเภทข้อมูลช่วยเพิ่มอิสระในการแก้ไขโค้ดภายหลัง
- ใช้แอตทริบิวต์ #[non_exhaustive] เพื่อรองรับการขยายโครงสร้างข้อมูลในอนาคต
การเปลี่ยนแปลงอินเทอร์เฟซในระบบซอฟต์แวร์ที่ผู้ใช้งานสามารถมองเห็นได้ถือเป็นเรื่องใหญ่ที่นักพัฒนาต้องคิดทบทวนให้ดีก่อนลงมือทำ เนื่องจากหากมีการส่งมอบการเปลี่ยนแปลงที่ไม่รองรับระบบเดิมบ่อยครั้งจนเกินไป หรือที่เรียกรวมกันว่าการปรับเลขเวอร์ชันหลัก (major version bumps) ย่อมสร้างความหงุดหงิดให้กับผู้ใช้งานระบบอย่างแน่นอน
การเปลี่ยนแปลงที่ไม่รองรับระบบเดิมบางประเภทมีความชัดเจนในตัว เช่น การเปลี่ยนชื่อประเภทข้อมูลสาธารณะ หรือการลบรายการสาธารณะออกจากประเภทข้อมูลนั้น แต่ในขณะเดียวกันก็มีบางการเปลี่ยนแปลงที่มีความซับซ้อนและแนบแน่นอยู่กับวิธีการทำงานเฉพาะตัวของภาษา Rust ซึ่งบทความนี้จะพาทุกท่านไปเจาะลึกถึงการเปลี่ยนแปลงเหล่านี้รวมถึงแนวทางที่นักพัฒนาควรวางแผนรับมือ

ภาพประกอบจากคลังภาพสต็อก ไม่ใช่ภาพจากเหตุการณ์จริง
ในกระบวนการพัฒนานี้ บางครั้งนักพัฒนาจำเป็นต้องยอมรับการประนีประนอมและความแลกเปลี่ยนระหว่างกันเพื่อรักษาความยืดหยุ่นของอินเทอร์เฟซเอาไว้ โดยตัวอย่างของการเปลี่ยนแปลงที่ไม่รองรับระบบเดิมที่เห็นได้ชัดเจนคือการลบหรือเปลี่ยนชื่อประเภทข้อมูลสาธารณะ ซึ่งจะส่งผลให้โค้ดฝั่งผู้ใช้งานเกิดข้อผิดพลาดขึ้นอย่างแน่นอน แนวทางแก้ไขเบื้องต้นคือการใช้ตัวปรับแต่งการมองเห็น (visibility modifiers) ให้มากที่สุดเท่าที่จะทำได้
- ยิ่งคุณเปิดเผยประเภทข้อมูลสาธารณะใน API น้อยเท่าไหร่ คุณก็จะมีอิสระในการเปลี่ยนแปลงมันในอนาคตมากขึ้นเท่านั้น
- อิสระในที่นี้หมายถึงการไม่ทำลายโค้ดที่มีอยู่เดิมของผู้ใช้งาน
การจำกัดการมองเห็นในภาษา Rust (เช่น การใช้โครงสร้างแบบ private หรือ restricted) เป็นหัวใจสำคัญของการรักษา API Stability นักพัฒนาสาย Rust มักใช้แนวคิด encapsulation เพื่อซ่อนโครงสร้างภายในที่ไม่จำเป็นต้องให้ภายนอกเข้าถึงโดยตรง ช่วยลดภาระในการดูแลรักษาโค้ดระยะยาวเมื่อมีการอัปเดตเวอร์ชัน
อย่างไรก็ตาม โค้ดของผู้ใช้งานไม่ได้ขึ้นอยู่กับชื่อของประเภทข้อมูลเพียงอย่างเดียว โดยมีตัวอย่างกรณีศึกษาเริ่มต้นจากการเขียนโครงสร้างข้อมูลชื่อ Unit ภายในไฟล์ lib.rs ในรูปแบบ pub struct Unit; ก่อนที่จะถูกนำไปใช้งานในไฟล์ main.rs ในรูปแบบโครงสร้างที่มีฟิลด์ข้อมูลภายใน ซึ่งทำให้โค้ดฝั่ง main.rs เกิดการเปลี่ยนแปลงตามไปด้วย
เพื่อรับมือกับสถานการณ์ลักษณะนี้ ภาษา Rust จึงได้เตรียมแอตทริบิวต์พิเศษที่เรียกว่า #[non_exhaustive] ออกมาเพื่อช่วยบรรเทาปัญหา โดยสามารถนำไปประยุกต์ใช้ได้ทั้งกับโครงสร้าง (struct) เอนัม (enum) และตัวเลือกภายในเอนัม ซึ่งแอตทริบิวต์นี้ทำหน้าที่ส่งสัญญาณบอกคอมไพเลอร์ว่าประเภทข้อมูลหรือเอนัมดังกล่าวนั้นอาจมีการเพิ่มฟิลด์หรือเพิ่มตัวเลือกใหม่ๆ เข้ามาได้ในอนาคต
ที่มา: Dev.to
พบข้อมูลผิดพลาดในบทความนี้? แจ้งปัญหาบทความนี้
ความคิดเห็น
แสดงความคิดเห็น