- แนวทางการเขียนโปรแกรมจากซ้ายไปขวา ทำให้โปรแกรมยังคงอยู่ในสถานะที่ถูกต้องทันทีที่พิมพ์โค้ดลงไป ส่งผลให้ การรองรับจากเครื่องมือ อย่างการเติมโค้ดอัตโนมัติของเอดิเตอร์ทำงานได้เต็มประสิทธิภาพ
- list comprehension ของ Python รบกวนการทำงานของการเติมโค้ดอัตโนมัติ เนื่องจากมีตัวแปรที่ยังไม่ได้ประกาศและไม่มีการอนุมานชนิดข้อมูล
- Rust และ JavaScript สามารถประกอบโปรแกรมจากซ้ายไปขวาได้อย่างเป็นธรรมชาติ ทำให้การใช้งานตัวแปรและการสำรวจเมธอดทำได้ตรงไปตรงมามากกว่า
- สไตล์แบบฟังก์ชันใน C และ Python ทำให้ชื่อฟังก์ชันหรือโครงสร้างค้นพบได้ยาก จนลดทอนประสบการณ์การเขียนโค้ดอย่างมีประสิทธิภาพ
- สำหรับ ลอจิกที่มีความซับซ้อนสูง โค้ดที่คลี่ออกจากซ้ายไปขวาจะอ่านง่ายกว่า และมีข้อได้เปรียบด้านการบำรุงรักษาและการขยายต่อ
การเขียนโปรแกรมจากซ้ายไปขวา
โค้ดควรถูกต้องทันทีที่พิมพ์ลงไป
ข้อจำกัดของ Python list comprehension
- ไวยากรณ์ list comprehension ของ Python อย่าง
words_on_lines = [line.split() for line in text.splitlines()] มีปัญหาเพราะต้องเข้าถึงตัวแปร (line) ที่ยังไม่ได้ประกาศ ทำให้เอดิเตอร์ไม่สามารถให้ การเติมโค้ดอัตโนมัติ หรือการอนุมานชนิดข้อมูลได้อย่างเหมาะสม
- ระหว่างกระบวนการพิมพ์โค้ดทีละส่วน
- หากพิมพ์เป็น
words_on_lines = [line.sp เอดิเตอร์จะไม่รู้ชนิดของ line จึงไม่สามารถแนะนำเมธอดได้
- ยังตรวจจับข้อผิดพลาดที่อาจเกิดขึ้น เช่น การพิมพ์ชื่อตัวแปรผิด (
lime เป็นต้น) ได้ยาก
- หากต้องการรับคำแนะนำที่ถูกต้อง ผู้ใช้กลับต้องเขียนโค้ดที่ยังไม่เสร็จให้ครบในระดับหนึ่ง ซึ่งเป็นกระบวนการที่ ไม่เป็นธรรมชาติและไม่สะดวก
การประกอบจากซ้ายไปขวาใน Rust
- ตัวอย่างใน Rust (
let words_on_lines = text.lines().map(|line| line.split_whitespace());) แสดงให้เห็นว่า
- เมื่อมีการประกาศฟังก์ชันนิรนาม ตัวแปร (
line) ที่ปรากฏขึ้นครั้งแรกจะถือว่าเป็นการประกาศทันที จึงสามารถใช้ การเติมโค้ดอัตโนมัติและคำแนะนำเมธอด ได้ในทันที
- เมธอด
split_whitespace เองก็ถูกค้นพบได้ง่ายเพราะมีระบบแนะนำอัตโนมัติ
- วิธีนี้ทำให้โปรแกรมยังคงอยู่ใน สถานะที่ถูกต้องอย่างน้อยบางส่วนเสมอ ดังนั้น IDE หรือเอดิเตอร์จึงช่วยรองรับการเขียนโค้ดแบบเรียลไทม์ได้
การเปิดเผยแบบค่อยเป็นค่อยไป (Progressive Disclosure) และการใช้งาน API
- การเปิดเผยแบบค่อยเป็นค่อยไป (Progressive Disclosure) คือหลักการออกแบบที่ให้ผู้ใช้พบความซับซ้อนเท่าที่จำเป็น และสามารถนำมาใช้กับการเขียนโปรแกรมได้
- ตัวอย่าง: คล้ายกับ UX ของโปรแกรมประมวลผลคำที่จะแสดงตัวเลือกที่เกี่ยวข้องเฉพาะเมื่อเพิ่มรูปภาพ
- ภาษา C ขาดการรองรับลักษณะนี้
- ฟังก์ชันทั้งหมดที่เกี่ยวข้องกับ
FILE *file ไม่ได้ถูกสำรวจผ่าน file. จึงต้องจำรูปแบบชื่อฟังก์ชันอย่าง fread, fclose เป็นต้น และยากต่อการค้นพบความสามารถต่าง ๆ
- ในทางกลับกัน หากเป็นภาษาที่ออกแบบได้เหมาะสม ผู้ใช้ควรค้นพบความสามารถที่เกี่ยวข้องได้แบบ ค่อยเป็นค่อยไป ผ่านคำแนะนำเมธอดจาก
file.
ความแตกต่างด้านการค้นพบได้ของฟังก์ชันและเมธอด
- เปรียบเทียบตัวอย่าง
map(len, text.split()) ของ Python กับ text.split(" ").map(word => word.length) ของ JavaScript
- ใน Python ชื่อฟังก์ชันอย่าง
len, length, size คาดเดาได้ยาก จึงอาจต้องลองหลายครั้งกว่าจะรู้ว่าคำสั่งใดใช้ได้จริง
- ใน JavaScript เพียงพิมพ์
word. แล้วตามด้วย .l เอดิเตอร์ก็สามารถเสนอ length และเมธอดอื่น ๆ ได้ จึงมี ความสามารถในการค้นพบสูงกว่า
- แม้แต่ฟังก์ชันระดับสูงอย่าง
map ก็ยังทำให้ค่าที่ส่งกลับและชนิดข้อมูลที่เกี่ยวข้องปรากฏชัดได้ทันที
ยิ่งลอจิกซับซ้อน ยิ่งเห็นข้อดีของการเขียนแบบมีโครงสร้าง
- ในกรณีของลอจิกที่มีความซับซ้อนสูง (เช่น โค้ด Python ยาว ๆ ที่มี
filter และ lambda ซ้อนกัน)
- ผู้เขียนต้องคอยย้อนดูจุดเริ่มต้นและจุดสิ้นสุดของโค้ดซ้ำไปมา และเกิด ปัญหาด้านความอ่านง่าย รวมถึงความยากในการทำความเข้าใจจากเงื่อนไขหรือการจับคู่วงเล็บ
- แต่ในเวอร์ชัน JavaScript ของลอจิกเดียวกัน สามารถ อ่านและทำความเข้าใจอย่างเป็นลำดับ ได้จากบนลงล่างและจากซ้ายไปขวา
หลักการสำคัญ
โค้ดควรถูกต้องในทุกขณะที่พิมพ์
- แม้พิมพ์เพียง
text โปรแกรมก็ยังคงอยู่ในสถานะที่ถูกต้อง
- เมื่อเขียนถึง
text.split(" ") แล้ว และพิมพ์ต่อเป็น .map(word => word.length) สถานะระหว่างทางทั้งหมดก็ยัง คงความถูกต้องอยู่เสมอ
- รูปแบบการเขียนโค้ดเช่นนี้ช่วยเพิ่มโอกาสให้เอดิเตอร์ รองรับแบบเรียลไทม์ ได้ดีขึ้น และในสภาพแวดล้อม REPL ก็สามารถเห็นผลลัพธ์ได้ทันที
บทสรุป
- การออกแบบภาษาและ API ควรสนับสนุนให้ผู้ใช้พิมพ์โค้ดจากซ้ายไปขวาได้อย่างเป็นธรรมชาติ และทำให้ทุกขั้นตอนระหว่างทางเป็น โปรแกรมที่ถูกต้อง
- การออกแบบ API ที่ดีคือหัวใจสำคัญของการยกระดับประสบการณ์การเขียนโค้ดในลักษณะนี้
ยังไม่มีความคิดเห็น