ภาษาเล็กคืออนาคตของการเขียนโปรแกรม
(chreke.com)"Little Language" คืออะไร?
- "ภาษาเล็ก" คือภาษาที่ถูกสร้างขึ้นโดยมีเป้าหมายเพื่อแก้ปัญหาเฉพาะด้าน
→ SQL, RegEx, Dhall,..
→ และยังถูกเรียกว่า DSL ด้วย
ทำไมภาษาเล็กจึงจำเป็น?
- เมื่อแอปพลิเคชันซับซ้อนขึ้นมาก ซอร์สโค้ดก็ใหญ่ขึ้น แต่ก็ยิ่งทำความเข้าใจได้ยากขึ้นด้วย
- การ onboarding พนักงานใหม่ทำได้ยาก เกิดข้อผิดพลาดจากการไม่เข้าใจ dependencies และการเปลี่ยนแปลงโค้ดก็ยิ่งจัดการได้ยากขึ้นเรื่อยๆ
- ในช่วง 10 ปีที่ผ่านมา codebase มีขนาดใหญ่ขึ้น 100~500 เท่า
- Linux kernel เริ่มต้นในปี 1992 ด้วย 10,000 บรรทัด แต่ผ่านไป 20 ปีกลายเป็น 30 ล้านบรรทัด
- โค้ดเหล่านี้ไม่ได้เกิดขึ้นเพียงเพราะ "มีฟีเจอร์มากขึ้น" เท่านั้น แต่เพราะวิธีที่เราสร้างซอฟต์แวร์ได้เปลี่ยนไป
- ซอฟต์แวร์ก็เหมือนการสร้างพีระมิด เพื่อวางหินก้อนสุดท้าย เราต้องมีหินอีกจำนวนมากรองรับอยู่ด้านล่าง
เอาชนะเทรนด์นี้
- การสร้าง OS สมัยใหม่จำเป็นต้องใช้โค้ดหลายล้านบรรทัดจริงหรือ?
- Alan Kay ท้าทายสมมติฐานนี้ในโครงการ STEPS ปี 2006
-
เราคิดว่าการสร้าง "ภาษา" ที่เหมาะกับปัญหาที่ต้องแก้ จะทำให้การแก้ปัญหาง่ายขึ้น และทำให้โซลูชันเล็กลงพร้อมทั้งเข้าใจได้ง่ายขึ้น
- ใน STEPS มีการสร้างภาษาชื่อ Nile และทำให้ Cairo renderer ที่มี 44,000 บรรทัด สามารถทำงานใกล้เคียงกันได้ด้วยโค้ดราว 300 บรรทัด
แล้วทำไมภาษาแบบระดับสูงถึงไม่พอ?
- แค่สร้างภาษาทั่วไปที่มีระดับสูงขึ้นอีกไม่ได้หรือ?
- ส่วนตัวผมคิดว่าเราไปถึงจุดที่ผลตอบแทนลดลง (diminishing returns) ของพลังในการแสดงออกของภาษาทั่วไปแล้ว
- ถ้าจะเป็นภาษาที่สูงกว่านี้ หน้าตาจะเป็นอย่างไร? ถ้ายก Python เป็นตัวอย่าง มันก็มีระดับสูงมากจนดูเหมือน pseudo code อยู่แล้ว
- ปัญหาของภาษาทั่วไปคือ คุณต้องแปลปัญหาของคุณเป็นอัลกอริทึมก่อน แล้วจึงค่อยแสดงอัลกอริทึมนั้นด้วยภาษาเป้าหมาย
- ในหนังสือ Programming Pearls ของ Jon Bentley ปี 1986 เคยเชิญ Donald Knuth และ Doug McIlroy ที่มีชื่อเสียง มาลองเขียนโปรแกรมนับความถี่ของคำ โดย Don เขียนด้วย WEB ซึ่งเป็นภาษาดัดแปลงจาก Pascal ใช้โครงสร้างข้อมูลซับซ้อนยาวถึง 10 หน้า
- ส่วน Doug ทำด้วยไวยากรณ์ Unix pipe เพียง 6 บรรทัด โดยใช้
tr,sort,uniq,sort,sedเป็นต้น
ยิ่งน้อยยิ่งดี Less is More
- คำสั่ง Unix ข้างต้นแสดงให้เห็นลักษณะอีกอย่างของภาษาเล็ก
"ภาษาที่ทรงพลังน้อยกว่า แต่มี runtime ที่ทรงพลังมากกว่า" - Gonzalez พูดถึงเทรนด์นี้ไว้ใน "The end of history for programming"
- คือผลักปัญหาใน user space ไปเป็นปัญหาของ runtime
- ทำให้โปรแกรมมีลักษณะคล้ายการแสดงออกเชิงคณิตศาสตร์บริสุทธิ์มากขึ้น และเพิ่มความซับซ้อนของ runtime อย่างมาก
- คือผลักปัญหาใน user space ไปเป็นปัญหาของ runtime
- RegEx และ SQL ต่างก็ไม่สามารถแสดงอะไรได้นอกเหนือจากการค้นหาข้อความและงานฐานข้อมูลตามลำดับ
- นี่แตกต่างจากภาษาอย่าง C ที่ไม่มี runtime และสามารถแสดงทุกอย่างได้
- ภาษาเล็กยืนอยู่ที่ปลายอีกด้านหนึ่งของสเปกตรัมพลังแบบที่ C มี
- ไม่เพียงแต่สถาปัตยกรรมคอมพิวเตอร์จะถูกทำให้เป็นนามธรรม แต่ยังจำกัดชนิดของโปรแกรมที่สามารถแสดงได้ด้วย จึงถูกออกแบบให้ Turing-incomplete
- แม้จะฟังดูจำกัดมาก แต่กลับเปิดความเป็นไปได้อีกมิติสำหรับการ optimization และ static analysis
การวิเคราะห์แบบสแตติก
- ภาษาที่ทรงพลังน้อยกว่านั้นให้เหตุผลกับมันได้ง่ายกว่า และสามารถให้การรับประกันที่แข็งแรงกว่าภาษาทั่วไป
- ตัวอย่างเช่น Dhall เป็น "Total Functional Programming Language" สำหรับการสร้างไฟล์คอนฟิก
- กล่าวคือ เพื่อขจัดความเสี่ยงของการตกอยู่ในลูปไม่สิ้นสุด โปรแกรม Dhall จึง "รับประกัน" ว่า "(1) จะไม่ crash และ (2) จะจบการทำงานภายในเวลาจำกัด"
- ข้อ (1) ทำได้ด้วยการไม่ให้โยน exception คำสั่งที่อาจล้มเหลวจะคืนค่า Optional result (อาจมีค่าหรือไม่มีก็ได้)
- ข้อ (2) ทำได้ด้วยการไม่อนุญาตให้มีนิยามแบบ recursive
- ในภาษาฟังก์ชันอื่นๆ การ recursion เป็นวิธีพื้นฐานในการทำ loop แต่ Dhall ต้องพึ่งพา built-in
foldfunction - การไม่มีโครงสร้าง loop ทั่วไปหมายความว่า Dhall ไม่เป็น Turing-complete แต่ก็ไม่จำเป็น เพราะมันไม่ใช่ภาษาสำหรับงานทั่วไป
- เมื่อภาษามีขนาดเล็ก การให้เหตุผลก็ง่ายขึ้นมาก
- เช่น การตรวจว่าโปรแกรม Python ไม่มี side effect อื่นหรือไม่นั้นทำได้ยาก แต่ใน SQL แค่ตรวจว่าคิวรีเริ่มด้วย
SELECTหรือไม่ก็พอ
- เช่น การตรวจว่าโปรแกรม Python ไม่มี side effect อื่นหรือไม่นั้นทำได้ยาก แต่ใน SQL แค่ตรวจว่าคิวรีเริ่มด้วย
- สำหรับ Nile ทีม STEPS ต้องการ graphical debugger เลยสร้างขึ้นมา และดูได้ด้วยตัวเอง
- สิ่งนี้เป็นไปได้เพราะ Nile เป็นภาษาเล็กที่ให้เหตุผลง่าย
ความจำเป็นของความเร็ว
- ภาษาการเขียนโปรแกรมที่ทรงพลังมากกว่า ไม่ได้แค่เพิ่มโอกาสเกิดบั๊กเท่านั้น แต่อาจส่งผลเสียต่อประสิทธิภาพด้วย
- ตัวอย่างเช่น หากโปรแกรมไม่ได้ถูกแสดงออกมาในรูปของอัลกอริทึม runtime ก็อาจเลือกอัลกอริทึมได้เอง
- นิพจน์ที่ช้าสามารถถูกแทนที่ด้วยสิ่งที่เร็วกว่าได้ (โดยมีเงื่อนไขว่าพิสูจน์ได้ว่าให้ผลลัพธ์เหมือนกัน)
- ตัวอย่างเช่น SQL query ไม่ได้สั่งวิธีการ execute query
- database engine สามารถตัดสินใจได้อย่างอิสระว่า query plan แบบใดเหมาะสม
- จะใช้ index, composite index หรือจะ scan ตารางฐานข้อมูลทั้งหมด เป็นต้น
- database engine สมัยใหม่ยังเก็บสถิติเกี่ยวกับการกระจายค่าของแต่ละคอลัมน์ จึงสามารถเลือก query plan ที่ดีที่สุดเชิงสถิติได้แบบทันที
- ถ้าคิวรีมาในรูปอัลกอริทึม สิ่งเหล่านี้ก็จะทำไม่ได้
- database engine สามารถตัดสินใจได้อย่างอิสระว่า query plan แบบใดเหมาะสม
- หนึ่งใน "secret sauce" ที่ทำให้ภาษา Nile กระชับมาก คือ "Jitblt" ซึ่งเป็น Just-in-Time compiler สำหรับ graphics rendering
- จากการพูดคุยกันระหว่างทีม STEPS และทีม Cairo พบว่าโค้ด Cairo จำนวนมากถูกใช้ไปกับการ optimize งานผสมพิกเซลแบบทำมือ
- ตามทฤษฎีแล้ว งานนี้เป็นสิ่งที่สามารถ offload ไปให้คอมไพเลอร์ทำได้
- Dan Amelang จากทีม Cairo อาสามาสร้างคอมไพเลอร์แบบนี้ขึ้นมา ซึ่งก็คือ Jitblt
- นั่นหมายความว่างาน optimization ของ graphics pipeline สามารถแยกออกจากคำอธิบายเชิงคณิตศาสตร์ล้วนๆ ว่าจะ render อะไร
ทำให้ Nile สามารถรันได้เร็วพอๆ กับโค้ด Cairo ต้นฉบับที่ถูก optimize ด้วยมือ
Small languages, Big Potential (ภาษาเล็ก ศักยภาพใหญ่)
- แล้วสุดท้าย STEPS เป็นอย่างไร? มันสร้าง OS ที่ทำงานได้ด้วยโค้ดที่พิมพ์ลงบนเสื้อยืดได้จริงหรือไม่?
- ผลลัพธ์สุดท้ายของ STEPS คือ KSWorld
- เป็น OS ที่สมบูรณ์ มีทั้งโปรแกรมแก้ไขเอกสารและโปรแกรมแก้ไขสเปรดชีตในตัว
- มีโค้ด 17,000 บรรทัด
- อาจจะยาวเกินกว่าจะใส่บนเสื้อยืดได้ แต่ผมคิดว่านี่คือความสำเร็จ
- การเกิดขึ้นของ KSWorld แสดงให้เห็นว่า "ภาษาเล็ก" มีศักยภาพสูงมาก
- แต่ก็ยังมีคำถามที่ยังตอบไม่ได้อีกมาก
- ภาษาเหล่านี้จะคุยกันอย่างไร?
- ควรคอมไพล์ไปเป็นตัวแทนกลางแบบเดียวกันหรือไม่?
- หรือควรให้ runtime ที่ต่างกันอยู่ร่วมกันแบบขนาน แล้วสื่อสารกันด้วยโปรโตคอลมาตรฐาน (เช่น Unix pipe, TCP/IP)?
- หรือแต่ละภาษาจะเล็กพอที่จะนำไป implement ใหม่บน host language หลายแบบได้?
- หรือบางที การผสมทุกแนวทางเข้าด้วยกันอาจเป็นทิศทางที่ควรไป?
- ไม่ว่าอย่างไร ผมเชื่อว่าเราจำเป็นต้องคิดหาวิธีอื่นในการสร้างซอฟต์แวร์
- และบางที "ภาษาเล็ก" อาจเป็นส่วนหนึ่งของเรื่องนั้น
- สิ่งสำคัญคือ เราไม่ควรเอาอิฐไปกองทับเพิ่มบนของเดิมไปเรื่อยๆ จนกว่าจะมีเวลามากพอที่จะคิดสิ่งที่ดีกว่าออกมาได้
7 ความคิดเห็น
"
เราคิดว่าการสร้าง 'ภาษา' ให้เหมาะกับปัญหาที่ต้องแก้ จะทำให้การแก้ปัญหาง่ายขึ้น และทำให้โซลูชันทั้งเข้าใจง่ายและมีขนาดเล็กลง
"
สิ่งที่ผมรู้สึกหลังจากอ่านส่วนนี้คือ สุดท้ายแล้วสิ่งที่เรียกว่า 'ภาษาขนาดเล็ก' ก็น่าจะมีความหมายเดียวกับเฟรมเวิร์กไม่ใช่หรือ เช่นกรณีของ
JavaScript -> Reactที่บังคับใช้ฟังก์ชันและดีไซน์แพตเทิร์นที่ใช้บ่อย จนทำให้มันกลายเป็นไวยากรณ์ในอีกรูปแบบหนึ่งเป็นหัวข้อที่น่าสนใจนะครับ
คิดไปคิดมาแล้ว ผมเพิ่งไปเจอเครื่องมือสร้าง DSL ที่ชื่อว่า MPS(Meta Programming System) ซึ่งทำโดย JetBrains มาครับ
ดูแล้วเหมือนจะเป็นของที่มีมานานกว่าที่คิดนะครับ ผมเลยสนใจและว่าจะลองศึกษาดูเพิ่มเติม แต่ก็ผัดวันประกันพรุ่งมาเรื่อย ๆ เลยอยากถามว่า ถ้าใครเคยใช้ตัวนี้มาก่อน ผมอยากฟังรีวิวหรือประสบการณ์การใช้งานบ้างครับ
ว้าว ขอบคุณครับ
ขอบคุณที่ให้อ่านครับ
ลิสป์ยิ้มแย้ม
คิดว่าเป็นเรื่องที่น่าสนใจ เลยขอนำมาแบ่งปันครับ