- การเขียนโปรแกรมเชิงวรรณกรรม (Literate Programming) ซึ่งร้อยเรียงโค้ดและคำอธิบายภาษาธรรมชาติให้เป็นเรื่องเล่าเดียวกัน ไม่ได้รับการใช้อย่างแพร่หลายเพราะมีภาระในการดูแลทั้งโค้ดและคำอธิบายควบคู่กันไป แต่ AI coding agent อาจเข้ามากำจัดงานหลักส่วนนี้ได้
- ผ่าน
org-babel ของ Emacs Org Mode จึงสามารถทำ literate programming แบบหลายภาษาได้ แต่ในโปรเจกต์ขนาดใหญ่ ความยุ่งยากของกระบวนการดึงซอร์สโค้ดออกมาใช้ (tangling) เป็นข้อจำกัด
- หากสั่งให้เอเจนต์เขียน runbook บนพื้นฐานไฟล์ Org ก็จะเกิดเวิร์กโฟลว์ที่สามารถอธิบายเจตนาเป็นข้อความ รันโค้ดบล็อกแบบโต้ตอบได้ และบันทึกผลลัพธ์ไว้ในเอกสาร
- เอเจนต์สามารถ จัดการการซิงก์ระหว่างคำอธิบายกับโค้ดและทำ tangling อัตโนมัติ ทำให้หมดภาระต้องเขียนคำอธิบายใหม่ทุกครั้งที่โค้ดเปลี่ยน และใช้ความสามารถด้านการแปลและสรุปความที่ LLM ถนัดที่สุด
- ในกระแสที่บทบาทของวิศวกรกำลังเปลี่ยนจากการเขียนโค้ดไปสู่การ อ่านโค้ดเป็นหลัก ความเป็นไปได้ในการใช้งานจริงของ codebase แบบบรรยายที่เอเจนต์ช่วยดูแลจึงกลายเป็นคำถามสำคัญ
แนวคิดและข้อจำกัดของการเขียนโปรแกรมเชิงวรรณกรรม
- การเขียนโปรแกรมเชิงวรรณกรรม (Literate Programming) คือแนวคิดที่ผสมโค้ดกับคำอธิบายภาษาธรรมชาติเข้าด้วยกัน เพื่อให้ผู้อ่านที่ไม่มีความรู้ล่วงหน้าก็สามารถอ่าน codebase เป็นเรื่องเล่าและเข้าใจวิธีการทำงานได้
- เป็นแนวคิดที่น่าสนใจ แต่ในทางปฏิบัติกลับมีภาระในการต้องดูแล เรื่องเล่าคู่ขนานสองชุด คือโค้ดกับคำอธิบาย และนี่คือสาเหตุพื้นฐานที่ทำให้การนำไปใช้ถูกจำกัด
- รูปแบบที่พบได้บ่อยที่สุดในงานจริงคือ Jupyter Notebook ของชุมชน data science ซึ่งแสดงคำอธิบาย การคำนวณ และผลลัพธ์ร่วมกันในเว็บเบราว์เซอร์
Emacs Org Mode กับการเขียนโปรแกรมเชิงวรรณกรรม
- Emacs Org Mode รองรับ การเขียนโปรแกรมเชิงวรรณกรรมแบบหลายภาษา ผ่านแพ็กเกจ
org-babel โดยสามารถรันภาษาใดก็ได้และจับผลลัพธ์เก็บไว้ในเอกสาร
- อย่างไรก็ตาม วิธีนี้ยังคงเป็น รูปแบบเฉพาะกลุ่ม ที่เหลืออยู่ในหมู่ผู้ใช้สายฮาร์ดคอร์เพียงบางส่วน
- หากใช้ไฟล์ Org เป็น source of truth ของซอฟต์แวร์โปรเจกต์ขนาดใหญ่ ซอร์สโค้ดก็จะกลายเป็นผลลัพธ์ที่ถูกคอมไพล์ออกมาโดยพฤตินัย และหลังการแก้ไขแต่ละครั้งต้องดึงโค้ดออกมา ("tangle") แล้วนำไปวางยังปลายทาง
- แม้จะทำให้อัตโนมัติได้ แต่ก็มักเกิดปัญหาที่ผู้ใช้หรือเอเจนต์ไปแก้ซอร์สจริง แล้วถูก เขียนทับ ในการ tangle ครั้งถัดไปได้ง่าย
รูปแบบการใช้งานก่อนยุคเอเจนต์
- การใช้การเขียนโปรแกรมเชิงวรรณกรรมกับการจัดการการตั้งค่าส่วนตัว (bookkeeping personal configuration) ให้ผลดีพอสมควร จึงยังไม่ละทิ้งแนวคิดนี้แม้ก่อนยุค LLM
- รูปแบบการใช้ Org Mode สำหรับการทดสอบแบบแมนนวลและการจดโน้ต: เขียนและรันคำสั่ง ในเอดิเตอร์แทนบนบรรทัดคำสั่ง แล้วแก้ไขจนแต่ละขั้นตอนถูกต้อง ก่อนจะบันทึกผลไว้ตรงตำแหน่งนั้น
- "ถ้ารวมการจดโน้ตเข้ากับการรันทดสอบ พอทดสอบเสร็จก็จะได้โน้ตมาแบบฟรี ๆ"
เวิร์กโฟลว์ใหม่ร่วมกับเอเจนต์
- coding agent อย่าง Claude, Kimi ฯลฯ เข้าใจไวยากรณ์ของ Org Mode ได้ดี และ Org เป็นภาษามาร์กอัปที่ยืดหยุ่น จึงเป็นสิ่งที่ LLM จัดการได้ดีมาก
- ไวยากรณ์จำนวนมากของ Org Mode อาจเป็นข้อเสียสำหรับมนุษย์ แต่ ไม่ใช่ปัญหาสำหรับโมเดลภาษา
- เมื่อทดสอบฟีเจอร์ หากให้เอเจนต์ เขียน Org runbook ก็จะสามารถทำสิ่งต่อไปนี้ได้:
- คำอธิบายจะบรรจุการไตร่ตรองของโมเดลเกี่ยวกับเจตนาของแต่ละขั้นตอน
- โค้ดบล็อกสามารถตรวจทานก่อน แล้ว รันแบบโต้ตอบทีละบล็อกหรือทั้งหมดเหมือนสคริปต์ ได้
- ผลลัพธ์จะถูกเก็บไว้ใต้โค้ดเหมือน Jupyter Notebook
- สามารถแก้ไขคำอธิบายแล้วขอให้โมเดลอัปเดตโค้ด หรือแก้ไขโค้ดแล้วให้โมเดลสะท้อนความหมายลงในคำอธิบาย หรือให้เอเจนต์ แก้ทั้งสองฝั่งพร้อมกัน ก็ได้
- ปัญหาการดูแลเรื่องเล่าคู่ขนานจึงหายไป
งานหลักที่เอเจนต์ช่วยกำจัดออกไป
- หากมอบหมายให้เอเจนต์จัดการ tangling ก็จะ แก้ปัญหาการดึงโค้ดออกมาใช้ ได้ด้วย
- ผ่านไฟล์
AGENTS.md สามารถสั่งเอเจนต์ให้ถือว่าไฟล์ Org เป็น source of truth ต้องเขียนคำอธิบายเสมอ และต้องทำ tangle ก่อนรันได้
- เอเจนต์ทำงานทั้งหมดนี้ได้ดี และ ไม่มีวันเหนื่อย กับการเขียนคำอธิบายใหม่หลังแก้โค้ด
- เอเจนต์ช่วยกำจัดงานส่วนเกินพื้นฐานที่ทำให้การเขียนโปรแกรมเชิงวรรณกรรมไม่แพร่หลาย และนี่คือการใช้ความสามารถด้าน การแปลและการสรุป ที่ LLM ทำได้ดีที่สุด
ประโยชน์ที่คาดหวัง
- สามารถ ส่งออก (export) codebase ไปเป็นหลายฟอร์แมตเพื่อให้อ่านได้สะดวก
- ยิ่งสำคัญหากบทบาทหลักของวิศวกรกำลังเปลี่ยนจากการเขียนไปเป็น การอ่าน
- แม้ยังไม่มีข้อมูลยืนยัน แต่มีการคาดว่า คุณภาพของโค้ดที่สร้างขึ้นอาจดีขึ้น เพราะเรื่องเล่าที่อธิบายเจตนาของแต่ละโค้ดบล็อกจะปรากฏร่วมอยู่ในคอนเท็กซ์พร้อมกับโค้ด
- จนถึงตอนนี้ยังไม่สามารถลองใช้กับ codebase ขนาดใหญ่และจริงจังได้ และกำลังใช้กับเวิร์กโฟลว์การทดสอบและ การทำเอกสารกระบวนการแบบแมนนวล อยู่
ข้อจำกัดของ Org Mode และทางเลือก
- ฟอร์แมต Org ผูกติดกับ Emacs อย่างใกล้ชิด จึงเป็นปัจจัยจำกัด และมีความเชื่อมายาวนานว่า Org ควรออกมานอก Emacs ได้แล้ว
- อยากแนะนำ Markdown เป็นทางเลือก แต่ Markdown ขาดความสามารถในการบรรจุเมทาดาทา
- แนวคิด Properties ของ Org Mode ทำให้สามารถจัดการเอกสารแบบเป็นโปรแกรมด้วย Emacs Lisp ได้ และตอนนี้ LLM ยังช่วยเขียนฟังก์ชันเฉพาะสำหรับเอกสารนั้น ด้วย Emacs Lisp ในส่วน file variables ได้อีกด้วย
- Markdown ไม่มีฟีเจอร์อย่าง header arguments ของ Org Mode ที่ใช้ระบุรายละเอียดการรันโค้ดบล็อก เช่น จะรันที่ไหน หรือบนเครื่องระยะไกลใด
- สิ่งที่น่าตื่นเต้นไม่ใช่รายละเอียดการติดตั้งใช้งานของ Emacs แต่คือ ตัวแนวคิดเอง
คำถามสำคัญ
- "ผ่านเอเจนต์ เราจะทำให้การมี codebase ขนาดใหญ่ที่อ่านได้เหมือนเรื่องเล่า และมีเครื่องจักรที่ไม่รู้จักเหน็ดเหนื่อยคอยรักษา การเปลี่ยนแปลงโค้ดกับคำอธิบายให้ซิงก์กัน กลายเป็นสิ่งที่ใช้งานได้จริงหรือไม่?"
2 ความคิดเห็น
ความเห็นจาก Hacker News
คิดว่าวิธีที่ง่ายที่สุดคือ ให้ LLM เขียนคอมเมนต์ของตัวเองทิ้งไว้โดยตรง
แบบนี้เวลา LLM กลับมาอ่านโค้ดอีกครั้งภายหลัง ก็จะอ้างอิงคอมเมนต์ของตัวเองได้ จึงทำหน้าที่คล้าย หน่วยความจำระยะยาวแบบ just-in-time
ให้เขียนสรุปไว้ใน
<summary>, ใส่เหตุผลและบริบทไว้ใน<remarks>, และใส่ข้อจำกัดไว้ใน<params>โดยลดการใช้คอมเมนต์แบบ inline ให้เหลือน้อยที่สุดแบบนี้ตอนรีวิว PR ก็สามารถดูแนวคิดของ LLM ได้โดยตรงจาก
<remarks>ทำให้จับได้ง่ายว่ามีส่วนไหนที่มันเข้าใจไม่ตรงกับเจตนาหรือไม่สุดท้ายกลับทำให้บริบทของตัวเองปนเปื้อนด้วยข้อมูลที่ไม่จำเป็น จนความสามารถในการทำความเข้าใจยิ่งแย่ลง
ตอนนี้ก็ยังห่างไกลจาก literacy ในระดับมนุษย์อยู่มาก
แต่เวลาที่ LLM กลับมาอ่านโค้ดเดิมอีกครั้ง สิ่งที่มันสะดุดกลับเป็นคอมเมนต์พวกนี้ จึงอาจเป็นข้อมูลที่มีคุณค่าก็ได้
เพราะแบบนี้คอมเมนต์ลักษณะนี้จึงช่วยเก็บรักษาความจำนั้นไว้ได้
คิดว่าภาษาโปรแกรมเกิดขึ้นมาเพราะภาษาธรรมชาติมี ความกำกวม
เพราะฉะนั้นคอมเมนต์ในโค้ดก็ย่อมกำกวมตามไปด้วย และเพราะมันไม่ถูกรัน มันจึงล้าสมัยอย่างรวดเร็ว
LLM เก่งในการแปลโค้ด แต่ยังรู้สึกว่าการแปลงพรอมป์ต์ภาษาธรรมชาติให้เป็นโค้ดยังคงยากอยู่
โค้ดที่ดีควรแสดงเจตนาได้อย่างชัดเจน และการมีคอมเมนต์เยอะอาจเป็นสัญญาณว่าโค้ดคุณภาพต่ำก็ได้
แต่ซอฟต์แวร์ที่ดีควรรวมถึง documentation ที่ดีด้วย
literate programming คือการเขียนที่เน้นคำอธิบายมากกว่ารายละเอียดการติดตั้งใช้งาน
โค้ดนิยามคำว่า “อย่างไร” แบบแคบ ๆ แต่ภาษาธรรมชาติสามารถเน้น “อะไร” ได้ ทำให้ LLM ยังมีพื้นที่ในการเสนอวิธีที่ดีกว่า
ต้องมีข้อมูลซ้ำกันเพื่อให้ตรวจจับและแก้ไขข้อผิดพลาดได้
มันแค่มีชุดกฎที่ลดอิสระในการตีความลง
บางครั้งการใช้อุปมาหรือความกำกวมกลับเป็นรูปแบบการแสดงออกที่เหมาะสมกว่า
ถ้าให้ตัวอย่างโค้ดและเอกสารเป็นเทมเพลต ก็จะช่วยลด hallucination ได้
มีงานวิจัยว่าคอมเมนต์แบบ literate programming ช่วยให้มนุษย์เข้าใจโค้ดได้ดีขึ้น
นักวิจัยของ Google ได้ทดลองว่า LLM สามารถอัปเดตคอมเมนต์แบบนี้ได้หรือไม่ และมันช่วยให้มนุษย์เข้าใจมากขึ้นหรือไม่
ข้อสรุปคือ คอมเมนต์ระดับบล็อกที่อธิบายเจตนา มีประสิทธิภาพที่สุด
(อ้างอิง: บทความ arXiv ปี 2024 "Natural Language Outlines for Code")
ปรากฏการณ์ที่น่าสนใจในช่วงหลังคือ เมื่อก่อนคนมักขี้เกียจเขียน README หรือเอกสารสถาปัตยกรรม เพื่อมนุษย์
แต่ตอนนี้ถ้าบอกว่าเขียนเพื่อ LLM คนกลับกระตือรือร้นมากกว่าอย่างเห็นได้ชัด
แต่ LLM อ้างอิงเอกสารทุกครั้งที่ทำงาน จึงทำให้ แรงจูงใจในการทำเอกสาร สูงขึ้นมาก
บันทึกอย่างข้อความ commit หรือ ADR มนุษย์อาจไม่อ่าน แต่ LLM อ่านหมด
สุดท้ายแล้วนิสัยเหล่านี้ก็กลับมาช่วยคนที่เพิ่งเข้าทีมด้วยเช่นกัน
ว่าคนที่มัวแต่เรียนรู้วิธีคุยกับคอมพิวเตอร์จนลืมวิธีคุยกับมนุษย์ พอเรียนจบแล้วกลับตามหลังคนอื่นมากกว่า
เพราะโค้ดทำงานได้โดยไม่ต้องอาศัยความถูกต้องของเอกสาร
เลยทำให้บ่อยครั้งรู้สึกว่าดูโค้ดตรง ๆ ยังดีกว่าอ่านเอกสาร
ฉันมองว่าการจับคู่ระหว่าง literate programming แบบเบา ๆ กับ ภาษาที่ขับเคลื่อนด้วยธรรมเนียมปฏิบัติ เหมาะกับยุคของเอเจนต์มาก
ภาษาที่มีการคอมไพล์เร็วและมี style guide ชัดเจนอย่าง Go นั้นดีมาก
ถ้าให้เอเจนต์อ้างอิง Google Go Style Guide เวลาเขียนโค้ด ก็ได้ผลลัพธ์ที่ค่อนข้างดี
(อ้างอิง: เกร็ดเกี่ยวกับ Rob Pike)
LLM เป็นโมเดลภาษา ดังนั้นการลงทุนกับ การเขียนที่ชัดเจน จึงคุ้มค่าอย่างมาก
ไม่จำเป็นต้องถึงขั้น literate programming เสมอไป แต่ ชื่อที่ดี, docstring, type signature, และคอมเมนต์ที่อธิบายว่า “ทำไม” ล้วนสำคัญ
สุดท้ายแล้วประเด็นหลักคือการสร้าง รูปแบบการสื่อสาร ที่ใช้ได้ทั้งกับมนุษย์และ LLM
เอกสารที่อธิบายโครงสร้างระดับสูงในระดับไฟล์ ไดเรกทอรี และโปรเจกต์นั้นสำคัญเป็นพิเศษ
แต่แนวคิดพวกนี้มักครอบคลุมหลายไฟล์ จึงมีปัญหาตลอดว่าจะเขียนไว้ที่ไหนและจะ ซิงก์เอกสารกับโค้ด อย่างไร
ตลอด 10 ปีที่ผ่านมา ฉันเขียนโค้ดแทบทั้งหมดในรูปแบบ literate programming
ฉันสร้าง nbdev ขึ้นมาเพื่อจัดการโค้ด เอกสาร และการทดสอบร่วมกันบนพื้นฐานของโน้ตบุ๊ก
ช่วงหลังยังสร้างเครื่องมือชื่อ Solveit ที่รวม LLM เข้าด้วยกัน และกำลังใช้งานอยู่ทั่วทั้งบริษัท
(ลิงก์ Solveit)
literate programming มีประโยชน์แม้แต่งานที่อยู่นอกเหนือจากการเขียนโปรแกรม
ถ้าเพิ่ม เดโมสั้น ๆ หรือภาพหน้าจอ น่าจะดีกว่า
ไอเดียการใช้ LLM เพื่อตรวจจับ ความไม่สอดคล้องกันระหว่างคอมเมนต์กับโค้ด แบบอัตโนมัตินั้นน่าสนใจมาก
เอกสารย่อมคลาดเคลื่อนจากโค้ดเมื่อเวลาผ่านไปเสมอ และถ้าตรวจจับสิ่งนี้ได้อัตโนมัติ ก็จะมีคุณค่ามาก
น่าจะเอาไปทำเป็น สตาร์ทอัป ได้เลยด้วยซ้ำ
การเปลี่ยนแปลงเริ่มจาก PR ของเอกสาร แล้วนักพัฒนาค่อยสะท้อนมันลงในโค้ด
ตอนรีวิวก็แสดงเอกสารกับโค้ดแบบคู่ขนานเพื่อให้ตรวจสอบได้
และออกแบบให้สามารถสำรวจ บริบท ได้ผ่านลิงก์ระหว่างเอกสาร
เช่น GitHub gh-aw, Continue.dev
โครงสร้างแบบจับคู่ระหว่าง test code กับ production code มีประโยชน์คล้ายการทำบัญชีคู่ในงานบัญชี
test ช่วยอธิบายเจตนาของโค้ด และโค้ดก็ช่วยเติมความหมายให้ test
ตอนรีวิว ถ้าฝั่งหนึ่งทำให้งง ก็ไปดูอีกฝั่งได้
ข้อเสียคือปริมาณโค้ดเพิ่มขึ้น แต่ ความสามารถในการอ่าน ที่ดีขึ้นก็คุ้มค่ากับต้นทุนนี้
ฉันเองก็เพิ่งเขียนเรื่อง intent-based coding ไปไม่นานนี้ ซึ่งเชื่อมโยงกับการถกเถียงนี้
(ลิงก์บล็อก)
สิ่งสำคัญคือเราสามารถแปลงโค้ดเบสให้อยู่ในรูปแบบต่าง ๆ ที่ อ่านง่ายกว่า ได้
ต่อไปคนที่ไม่ได้เรียนสายนี้มาก็จะเข้าใกล้โค้ดได้มากขึ้น และการ รวมภาษาธรรมชาติ เข้าไปจะช่วยทั้งด้านประสิทธิภาพการทำงานและการเรียนรู้ของพวกเขาอย่างมาก
Wikipedia - การเขียนโปรแกรมเชิงวรรณกรรม
> การเขียนโปรแกรมเชิงวรรณกรรม (literate programming) เป็นหนึ่งในวิธีวิทยาการเขียนโปรแกรม โดยเป็นแนวทางที่ให้ความสำคัญกับการสร้างโค้ดที่มนุษย์เข้าใจได้ง่าย มากกว่าการสร้างโค้ดที่คอมไพล์ได้สำหรับคอมพิวเตอร์เพียงอย่างเดียว กล่าวอีกนัยหนึ่ง เป้าหมายคือการเขียนโปรแกรมเสมือนกำลังสร้างเอกสารเพื่อให้มนุษย์อ่านและเข้าใจได้ เป้าหมายคือ 'ทำให้การเขียนโปรแกรมสามารถอ่านได้ราวกับกำลังอ่านงานวรรณกรรม' จึงได้ชื่อว่า 'การเขียนโปรแกรมเชิงวรรณกรรม'