- วิศวกรซอฟต์แวร์ที่มีประสิทธิภาพจะสร้างและคงไว้ซึ่ง แบบจำลองทางความคิดที่ชัดเจน เกี่ยวกับข้อกำหนดและโค้ด และทำงานเป็นลูปของการเปรียบเทียบ·อัปเดตสิ่งเหล่านี้ซ้ำ ๆ
- LLM สามารถเขียนและแก้ไขโค้ด เขียนเทสต์ และดีบักได้ แต่ขาดความสามารถในการ คงไว้ซึ่งแบบจำลองทางความคิดที่แม่นยำ จึงเกิดความสับสนเมื่อเจองานที่ซับซ้อน
- ปัจจุบัน LLM มีข้อจำกัดในการระบุความต่างระหว่างโค้ดกับข้อกำหนดอย่างแม่นยำและแก้ไขได้อย่างเหมาะสม เนื่องจากปัญหา การตกหล่นของบริบท, อคติต่อข้อมูลล่าสุด, และ อาการหลอน
- มนุษย์สามารถสลับวิธีคิดได้อย่างยืดหยุ่นตามสถานการณ์ เช่น เก็บบริบททั้งหมดไว้ชั่วคราว หรือซ่อนรายละเอียดบางส่วนไว้ชั่วคราวเพื่อมองภาพรวม แต่ LLM ยังทำสิ่งนี้ไม่ได้
- LLM มีประโยชน์กับงานที่ข้อกำหนดเรียบง่าย แต่ในการพัฒนาซอฟต์แวร์ที่ซับซ้อน สุดท้ายแล้ว วิศวกรซอฟต์แวร์ ยังต้องรับผิดชอบโดยตรงต่อความชัดเจนของข้อกำหนดและการทำงานของโค้ด และ LLM มีบทบาทเป็น เครื่องมือช่วย
ลูปวิศวกรรมซอฟต์แวร์
- วิศวกรที่ชำนาญจะทำงานโดยวนซ้ำตามขั้นตอนต่อไปนี้
1. สร้างแบบจำลองทางความคิดของข้อกำหนด
2. เขียนโค้ดให้สอดคล้องกับแบบจำลองนั้น
3. ทำความเข้าใจว่าโค้ดที่เขียนขึ้นทำอะไรจริง ๆ
4. ระบุความแตกต่างแล้วแก้ไขโค้ดหรือข้อกำหนด - หัวใจสำคัญของลูปนี้คือความสามารถในการมี แบบจำลองทางความคิดที่แม่นยำและคงสภาพได้
ข้อจำกัดของ LLM
- LLM สามารถทำงานอย่างการเขียนโค้ด ระบุปัญหาแล้วแก้ไข เขียน·รันเทสต์ เพิ่มล็อก และใช้ดีบักเกอร์ได้
- แต่เนื่องจากไม่สามารถ คงไว้ซึ่งแบบจำลองทางความคิด จึงเกิดปัญหาดังต่อไปนี้
- สมมติว่าโค้ดที่ตัวเองเขียนทำงานได้ดี
- เมื่อเทสต์ล้มเหลว จะอาศัยการเดาว่าควรแก้โค้ดหรือแก้เทสต์
- เมื่อเกิดความสับสน จะลบโค้ดทั้งหมดแล้วเขียนใหม่ตั้งแต่ต้น
- ต่างจากมนุษย์ เมื่อเทสต์ล้มเหลว มนุษย์จะตรวจสอบแบบจำลองเพื่อกำหนดทิศทางการแก้ไข หรือเมื่อรู้สึกติดขัดก็มีความยืดหยุ่นในการคลี่คลายปัญหาผ่านการสนทนา
- วิศวกรซอฟต์แวร์จะรัน เทสต์ระหว่างทำงาน และเมื่อเกิดปัญหาก็สามารถตัดสินได้อย่างชัดเจนว่าควรแก้ส่วนใด
- บางครั้งแม้จะเริ่มงานทั้งหมดใหม่ ก็ยังนำไปสู่ผลลัพธ์ที่มี ความเข้าใจต่อปัญหา ลึกซึ้งยิ่งขึ้น
ความเป็นไปได้ในอนาคต
- ในอนาคตเมื่อโมเดลพัฒนาขึ้น สถานการณ์อาจเปลี่ยนไปได้ แต่ วิศวกรรมซอฟต์แวร์ ต้องการมากกว่าการสร้างโค้ดอย่างเดียว
- มนุษย์เมื่อแก้ปัญหาสำคัญจะสามารถดึงบริบททั้งหมดออกมาจากความทรงจำชั่วคราวเพื่อใช้งาน และเลือกโฟกัสที่ประเด็นหรือมองภาพใหญ่ได้
- สิ่งสำคัญไม่ใช่การเพิ่มข้อมูลในคอนเท็กซ์ไปเรื่อย ๆ แต่คือวิธีคิดที่จัดการเฉพาะข้อมูลที่จำเป็นอย่างเลือกสรร
- LLM ยังขาดความสามารถในการเก็บ·กู้คืนบริบทชั่วคราวแบบมนุษย์ หรือคิดสลับไปมาระหว่างภาพใหญ่กับรายละเอียด
- ข้อจำกัดหลักของ LLM ในปัจจุบัน
- การตกหล่นของบริบท(Context omission): หาไม่เก่งว่าข้อมูลที่จำเป็นหายไปตรงไหน
- อคติต่อข้อมูลล่าสุด(Recency bias): ให้น้ำหนักกับข้อมูลล่าสุดในหน้าต่างบริบทมากเกินไป
- อาการหลอน(Hallucination): สร้างรายละเอียดที่ไม่มีอยู่จริงขึ้นมา
- หากเพิ่มความสามารถด้านหน่วยความจำเข้าไป อาจช่วยให้ดีขึ้นบางส่วน แต่เมื่อความซับซ้อนเกินระดับหนึ่ง ก็ยังล้มเหลวในการ เข้าใจบริบทและคงไว้ซึ่งแบบจำลอง
- ยังขาดความสามารถในการรักษา แบบจำลองทางความคิด ที่คล้ายกันสองชุดพร้อมกันเพื่อวิเคราะห์ความแตกต่าง และตัดสินใจว่าควรแก้ข้อกำหนดหรือโค้ดตรงไหน
บทบาทและการใช้งานในปัจจุบัน
- LLM มีจุดแข็งด้านการสร้างโค้ดอย่างรวดเร็วและการรวมข้อกำหนด·เอกสาร จึงใช้งานได้ดีพอกับงานที่เรียบง่ายและชัดเจน
- แต่สำหรับปัญหาที่ไม่เรียบง่าย การคงไว้ซึ่งบริบทที่เพียงพอและการปรับปรุงแบบวนซ้ำยังทำได้ยาก
- ดังนั้นเรื่องอย่าง การทำให้ข้อกำหนดชัดเจน, การตรวจสอบโค้ด ยังคงเป็นความรับผิดชอบของวิศวกรซอฟต์แวร์
- แม้จะมุ่งไปสู่สภาพแวดล้อมที่ มนุษย์และเอเจนต์(LLM) สร้างซอฟต์แวร์ร่วมกัน แต่ ณ เวลานี้ วิศวกรต้องเป็นผู้นำ และใช้ LLM เป็นเครื่องมือ
2 ความคิดเห็น
ทำไม LLM ใน "ปัจจุบัน" ถึง...
ความเห็นใน Hacker News
เราไม่ได้แก้ปัญหาด้วยการยัดคำเข้าไปใน context window ให้มากขึ้นเรื่อย ๆ ไม่งั้นคงเสียสติกันพอดี
และเวลาเกิดปัญหา เราก็ไม่ได้มองปัญหาผ่านตัวอักษรเพียงอย่างเดียว
เราไม่ได้แก้แบบคิดว่า ถ้าใน debugger มี auth error ก็ "งั้นลบการตรวจสอบโทเคนออกจากโค้ดไปเลยดีไหม?"
แต่เราจะถอยออกมามองภาพรวมทั้งระบบเพื่อหาต้นตอที่แท้จริงของปัญหา
ตัวอย่างเช่น ถ้ามี auth error เราจะกลับไปทบทวนทั้งกระบวนการตรวจสอบโทเคนและสิทธิ์ของผู้ใช้ที่เรียกใช้งาน แล้วอาจพบว่าจริง ๆ แล้วตัวทดสอบเองต่างหากที่ผิด
ระหว่างทางก็จะพบด้วยว่า สิ่งที่ต้องทำไม่ใช่แค่กำจัด error ทิ้ง แต่ต้องแยกแยะให้ละเอียดขึ้นด้วย เช่น "401 เกิดจากยังไม่ได้ยืนยันตัวตนจริง ๆ หรือเกิดจากสิทธิ์ไม่พอ"
ดู Grugbrain.dev
ผมคิดว่างานของโปรแกรมเมอร์คือการแปลกฎธุรกิจให้เป็นรูปแบบที่เข้มงวดจนคอมพิวเตอร์เข้าใจได้
กระบวนการแปลนี้ไม่ได้ง่ายเสมอไป เพราะต้องเข้าใจทั้งความหมายของกฎ และเข้าใจว่าคอมพิวเตอร์ (หรือเฟรมเวิร์กกับชั้น abstraction ที่ใช้อยู่) ทำงานอย่างไร
โดยเฉพาะเมื่อ requirement ใหม่มาทำลายสมมติฐานเดิมทั้งหมด หรือขัดแย้งกันเอง ก็แทบเลี่ยงไม่ได้ที่จะต้องกลับไปแก้หลายรอบ
แม้แต่การแปลภาษาระหว่างคนด้วยกันเองก็ยังกำกวมและซับซ้อนอยู่แล้ว ยิ่งคอมพิวเตอร์ทำตามที่สั่งแบบเป๊ะ ๆ ความผิดพลาดเล็กน้อยก็เลยกลายเป็นปัญหาใหญ่ได้
โดยส่วนตัวผมคิดว่าแนวทางที่ให้มนุษย์เข้ามาเกี่ยวข้องแบบวนซ้ำตลอดเป็นวิธีที่สมจริงที่สุด
วิธีนี้ช่วยให้ทำงานได้เร็วขึ้นและคุณภาพดีขึ้น ผมก็เลยยังใช้แนวทางนี้ต่อไป
ส่วนตัวแล้วผมสามารถเก็บ context จำนวนมากไว้ในหัวได้ทั้งหมด
ตัวข้อความของโค้ดจะถูกทิ้งไปเกือบจะทันที แล้วสมองผมจะ parse มันเป็นโครงสร้างคล้าย AST (abstract syntax tree) หรือไปไกลกว่านั้นคือเป็นกราฟเชิงพื้นที่
ผมสร้างแบบจำลองเชิงตรรกะของตัวโปรแกรมขึ้นมา และรับรู้มันเป็นโครงสร้างที่แยกขาดจากตัวข้อความโดยสิ้นเชิง
ถ้ามองจากมุมนี้ LLM เข้าใจโครงสร้างซอฟต์แวร์ไม่ได้ เพราะมันจดจ่ออยู่กับข้อความ แต่ไม่ได้สร้างแบบจำลองเชิงตรรกะของโปรแกรม
การออกแบบสถาปัตยกรรมระบบขนาดใหญ่ที่ต้องอาศัยความคิดเชิงนามธรรมต้องใช้พลังสมองมหาศาลมาก แต่ LLM ยังขาดความสามารถด้าน abstraction แบบนี้
วิธีของผมคือแบบนี้
เมื่อมีรายงานว่าเทสต์ล้มเหลว ผมจะระบุคอมโพเนนต์ที่เกี่ยวข้องก่อน แล้ววิเคราะห์อย่างลึกว่าคอมโพเนนต์นั้นมีไว้เพื่ออะไร มี control flow ภายในอย่างไร มีการเปลี่ยนสถานะอะไรบ้าง และมีสมมติฐานอะไรต่อ context รอบข้าง จากนั้นสรุปเป็นมาร์กดาวน์ไว้ (<ชื่อคอมโพเนนต์>-mental-model.md)
หลังจากนั้นทุกครั้งที่จัดการปัญหาเทสต์ ผมจะอ้างอิง mind model นี้เสมอ
ถ้าเอาการวิเคราะห์นี้ไปแปะในพรอมป์ของ Claude ก็ช่วยให้ LLM ให้ผลลัพธ์ดีขึ้นได้
กระทั่ง mind model ที่ LLM สร้างขึ้น ผมก็ยังอ่านและแก้ไขได้โดยตรง
AI อาจแนะนำได้ว่า ถ้าเป็นกรณีสิทธิ์ไม่พอควรใช้ 403 แทน 401
ดูเหมือนผู้เขียนต้นฉบับจะยังไม่ค่อยเข้าใจความสามารถปัจจุบันของ LLM และเครื่องมือช่วยเขียนโค้ด
ข้ออ้างที่ว่าเวลาเทสต์ล้ม LLM ทำได้แค่เดาว่าโค้ดผิดหรือเทสต์ผิด แล้วพอหงุดหงิดก็ลบโค้ดทิ้งหมดนั้นไม่ตรงกับสิ่งที่ผมเจอจริง
วิศวกรซอฟต์แวร์จะคอยวิเคราะห์อย่างเจาะจงอยู่เสมอว่าเทสต์ล้มเพราะอะไร โดยเทียบกับแบบจำลองในหัวของตัวเอง
ผมใช้ Cline กับ Anthropic Sonnet 3.7 ทำ TDD บน Rails โดยสั่งให้ LLM เขียนเทสต์ก่อนเสมอ แล้วค่อยให้เขียนโค้ด
พอแตกงานเป็นชิ้นเล็ก ๆ จนผมรีวิวได้ทีละส่วน มันก็ค่อนข้างอนุมานได้ดีว่าเวลาล้มเหลวควรแก้ตรงไหน และมักแก้ได้ถูก
LLM ไม่ได้สมบูรณ์แบบ แต่หลายครั้งก็ให้ผลลัพธ์ระดับใกล้เคียงหรือดีกว่าวิศวกรจูเนียร์ที่เป็นมนุษย์ด้วยซ้ำ
บางครั้งมันก็แก้บั๊กไม่ได้ แต่เอาจริงนักพัฒนามือใหม่ที่เป็นมนุษย์ก็เป็นเหมือนกัน
LLM ทำงานได้ดีมากโดยเฉพาะกับงาน CRUD บนเฟรมเวิร์กที่พิสูจน์ตัวเองมาแล้วอย่าง Rails
แต่พอตอนผมลองทำแอป native บน Windows ด้วย Direct2D และ Rust มันกลับแย่มาก
เลยอยากให้มีการประเมินแบบเปิดกว้างกับหลายกรณีมากกว่านี้
เป็นเรื่องที่รู้กันดีมากอยู่แล้วว่าโมเดลชอบใช้ทางลัดและลูกเล่นต่าง ๆ (เช่น hardcode) เพื่อพยายามทำให้เทสต์ที่ล้มผ่านให้ได้
จากประสบการณ์ของผม มันต่างกันมากตามภาษา แพลตฟอร์ม และโดเมน
ช่วงหลังผมเองก็ไม่ได้จับ Ruby แล้ว เลยยังไม่ได้ทดลองกับ Rails แต่สาย Rails มีวัฒนธรรมการเขียนโปรแกรมที่ค่อนข้างสม่ำเสมอมาก LLM เลยน่าจะทำได้ดีพอสมควร
ในทางกลับกัน Python มักมีสไตล์การเขียนหลายแบบปะปนกัน LLM เลยชอบจับแพตเทิร์นมาปนกันจนเทสต์ไม่นิ่งอยู่บ่อย ๆ
ต้องคอยเปลี่ยนโค้ดวนไปวนมา และบางทีก็ได้ผลลัพธ์ประหลาด เช่น ปัญหาจริงคือ "ลืม sort ผลลัพธ์ของ query" แต่ LLM กลับแนะนำให้เลิกใช้ SqlAlchemy แล้วย้ายไป Django
ส่วนภาษา R แค่จะได้โค้ดที่ทำงานตรงตามสเปกก็นับว่ายากแล้ว
ถ้าจำกัดความว่า LLM อยู่ระดับวิศวกรจูเนียร์ มันจะเก่งมากเวลาจัดการปัญหาที่เคยเห็นมาก่อน เพราะหาวิธีแก้และนำมาใช้ได้เร็วมาก
แต่ถ้าเป็นปัญหาที่ไม่เคยเห็น มันต้องการคำอธิบายหรือคำชี้นำเพิ่ม ซึ่งในกรณีนั้นบทบาทของผมก็กลายเป็นแค่เมนเทอร์
ทีมของเรากำลังใช้ LLM หนักมากในงานที่รู้แบบแผนดีอยู่แล้วและทำซ้ำได้ เช่น รีแฟกเตอร์เล็ก ๆ ที่ค้างอยู่ใน backlog มานาน หรือระบบวิเคราะห์ลำดับรอง ในสไตล์ ‘claude-code’
ส่วนตัวผมชอบลากคลุมโค้ดบล็อกแล้วถามว่า "อธิบายให้เด็กห้าขวบฟังหน่อย" หรือ "ช่วยหาว่ามีความเสี่ยงเรื่อง race condition ไหม"
โค้ดที่สร้างขึ้นมามักต้องให้ผมแก้สไตล์เอง เพราะมักไม่สอดคล้องกับโค้ดและแนวทางที่มีอยู่เดิม
ช่วงนี้ถึงขั้นมีคนพูดกันว่า 'เขียนโค้ดให้ AI อ่านง่าย' แต่สำหรับผม ประโยชน์ที่ได้ยังไม่มากพอเมื่อเทียบกับภาระเพิ่มที่ตามมา
กับคำกล่าวว่า "LLM บางครั้งก็ใกล้เคียงหรือดีกว่าจูเนียร์ได้" ผมกลับคิดว่าหรือว่านี่สะท้อนระดับการจ้างนักพัฒนาในช่วงนี้กันแน่
ถ้าผมรับจูเนียร์ที่แย่กว่า Sonnet 3.7 มาได้จริง ผมคงผิดหวังมาก
คำวิจารณ์ LLM ส่วนใหญ่อาจถูกต้อง แต่จากประสบการณ์ลงทุนหลายปี ผมได้เรียนรู้ว่าควรจับตาเทคโนโลยีหรือบริษัทที่ "ยังไม่ค่อยดีแต่เติบโตต่อเนื่อง"
ช่วงต้นถึงกลางยุค 90 อินเทอร์เน็ตก็โดนบ่นเยอะ แต่คนก็ยังใช้ต่อ และ Twitter ก็ล่มบ่อยแต่สุดท้ายก็กลายเป็นแพลตฟอร์มข่าว
รถยนต์ไฟฟ้า สมาร์ตโฟน และของอีกหลายอย่างก็เคยใช้งานไม่สะดวก แต่เพราะมันมีคุณค่า ผู้คนจึงปรับปรุงมันต่อไปเรื่อย ๆ
แม้ตอนนี้ LLM จะยังไม่สมบูรณ์ในหลายงาน แต่ถ้าเทียบกับปี 2022 ตอนนี้มันพัฒนาขึ้นมาแล้วราว 10 เท่า และผมคิดว่าภายใน 5 ปี ปัญหาส่วนใหญ่ที่พูดถึงกันตอนนี้ก็น่าจะถูกแก้ได้
แต่ทุกตัวอย่างที่ยกมาก่อนหน้านี้ก็เคยมีกรณีที่ความคาดหวังไม่ตรงกับความจริงเช่นกัน
อินเทอร์เน็ตเร็วขึ้นก็จริง แต่ metaverse ก็ไม่เคยกลายเป็นกระแสหลัก และข้อจำกัดทางกายภาพอย่างอาการเมา VR ก็ยังแก้ไม่ได้
ตอนนั้นก็ไม่ได้มีใครบ่นกันนักว่าโทรศัพท์ช้า เพราะสิ่งที่คาดหวังให้มันทำได้ต่างหากที่ต่างกัน
แค่เห็นเส้นทางการพัฒนาของเทคโนโลยีอื่น ก็ไม่ได้แปลว่า LLM จะต้องวิวัฒน์ตามแพตเทิร์นเดียวกันเสมอไป
ควรเผื่อใจไว้ด้วยว่าเทคโนโลยีใหม่อื่นอาจนำเสนอคำตอบที่ดีกว่า
ปีที่แล้วขอบเขตการใช้งานมันกว้างขึ้นจริง แต่ยังไม่มีจุดทะลุที่เรียกได้ว่าเป็นนวัตกรรมพลิกเกม
ต่อให้มือถือยุคก่อนจะช้าและกล้องคุณภาพต่ำ แต่แค่การใช้งานหลักในเวลานั้นคือ "ติดต่อกันได้ทุกที่ทุกเวลา" ก็ทำให้มันกลายเป็นสิ่งจำเป็นอยู่แล้ว
การพัฒนาแบบก้าวกระโดดที่ตามมาจึงเป็นเหมือน 'โบนัส' มากกว่า ไม่ใช่ว่าผู้คนรอแล้วถามกันว่า "เมื่อไหร่โทรศัพท์นี้จะดีขึ้นนะ"
ผมคิดว่ามีการบิดเบือนความทรงจำอยู่เหมือนกัน
ต่างจากความรู้สึกว่าคนทั่วไปบ่นเรื่องอินเทอร์เน็ตในยุค 90 มากมาย ความจริงคือผู้ใช้ยังมีน้อย และกว่าจะกลายเป็นกระแสหลักก็อีกนานมาก
แทบไม่มีหลักฐานว่ามีมวลชนจำนวนมากออกมาบ่นเพราะอินเทอร์เน็ตช้า
เรามักจำได้แต่สินค้าส่วนน้อยที่ประสบความสำเร็จและพัฒนาต่อไป แต่ส่วนใหญ่ถูกลืมไปอย่างรวดเร็วหรือหายไปโดยไม่เคยดีขึ้น
ผมเลยเลือกตัดสินจากสภาพปัจจุบัน มากกว่าจะคาดหวังล่วงหน้าว่าเทคโนโลยีจะดีขึ้นเอง
ผมไม่ค่อยเห็นด้วยกับตรรกะง่าย ๆ ที่ว่า การพัฒนาแบบก้าวกระโดดของ LLM ในช่วงไม่กี่ปีที่ผ่านมาจะดำเนินต่อไปแบบเดิมในอนาคต
มันอาจกำลังเข้าใกล้ขีดจำกัดของการเติบโต และโดยเฉพาะอย่างยิ่ง การขาดความสามารถในการค้นพบความรู้ใหม่หรือให้เหตุผลกับข้อมูลที่ไม่รู้มาก่อนนั้นดูเป็นข้อจำกัดชี้ขาดของ LLM
ไม่ได้จะบอกว่าเป็นเครื่องมือไร้ประโยชน์ แต่ผมก็ไม่พร้อมร่วมวงกับความคาดหวังที่สูงเกินไป
การคาดหวังว่าแค่บอก LLM ไม่กี่ประโยคแล้วมันจะไปเขียนโค้ดต้นแบบให้จบได้ทันทีนั้นไม่สมจริงตั้งแต่แรก
ถ้าสั่งทีมพัฒนามนุษย์แบบนี้ก็คงสร้างของดี ๆ ไม่ได้เหมือนกัน เลยสงสัยว่าทำไมถึงคาดหวังกับ LLM แบบนั้น
ถ้าอยากยกระดับคุณภาพผลลัพธ์การพัฒนาซอฟต์แวร์ด้วย LLM อย่างมาก ก็ต้องดึงกระบวนการและเครื่องมือที่ทีมพัฒนาใช้อยู่เดิมมาใช้ด้วยอย่างจริงจัง
บทความ autonomous-software
ผมเริ่มโปรเจกต์ชื่อ steadytext ที่ปล่อยให้เขียนโค้ดแบบอัตโนมัติเต็มตัวและเน้น vibe ล้วน ๆ ปรากฏว่า LLM เขียนโปรเจกต์ซับซ้อนยาว 7,000 บรรทัดได้เอง (เป็นทั้ง Python library, CLI และ Postgres extension) รวมถึงจัดการ issue และ feature request เองด้วย
ผมแทบไม่เคยอ่านโค้ดตรง ๆ ถึง 90% ของทั้งหมดเลย แต่ทั้ง test coverage, การผ่าน CI และการใช้งานจริงใน production ก็ไม่มีปัญหา
สิ่งที่จำเป็นคือต้องมีแผนที่ละเอียดมากใน
CLAUDE.mdพร้อม issue และ request ที่ชัดเจนเจาะจง แต่ถ้าเตรียมสิ่งเหล่านี้ไว้ดี มันก็ทำงานได้การจัดการให้ coding agent มาบริหารหรือเขียนโค้ดอย่างมีประสิทธิภาพไม่ใช่เรื่องง่าย แต่ประสบการณ์ของผมออกมาในทางบวก
steadytext บน GitHub
ผมยอมรับมุมมองเชิงวิจารณ์ได้ แต่การแก้ปัญหาคลุมเครือ สุดท้ายหัวใจสำคัญคือทั้งทีมต้องแชร์ context กันเยอะมาก
แม้แต่ทางออกที่สร้างสรรค์ที่สุดก็ยังเกิดจากข้อจำกัดทั้งแบบชัดเจนและแบบแฝง
LLM ไม่มีความสามารถในการมองออกถึงข้อจำกัดเหล่านี้ หรือออกแบบวิธีแก้ใหม่ภายใต้ข้อจำกัดที่ยังนิยามไม่ชัด
มนุษย์ต้องเป็นคนกำหนดปัญหา กำหนดขอบเขต และทำความเข้าใจเงื่อนไขจำกัดก่อน แล้ว LLM จึงค่อยมาเป็นเครื่องมือช่วยลงมือทำ
ณ ตอนนี้ มันก็แค่เป็นอีกหนึ่งตัวเลือกในระดับ "จะใช้เครื่องมืออะไรให้โค้ดเสร็จ" เท่านั้น
ผมคิดว่าการผลักการถกเถียงนี้ให้กลายเป็นคำตอบเดียวแบบ all or nothing เสียยิ่งกว่าที่ไม่สมจริง
จริง ๆ แล้วในสถานการณ์แบบนี้ก็ยังมีวิศวกรมนุษย์จำนวนมากที่ทำงานได้ดีพอสมควร
ถ้าการสั่ง LLM ให้ทำงานไม่ใช่เรื่องง่ายนัก ก็อดสงสัยไม่ได้ว่าคุณค่าการมีอยู่ของมันคืออะไร
Kiro กำลังใช้แนวทางนี้อยู่ แม้ยังอยู่ช่วงต้นและยังไม่สมบูรณ์ แต่ถ้าใช้งานตามที่มันตั้งใจไว้ก็ค่อนข้างโอเค
ยิ่งใช้ claude code ผมยิ่งหงุดหงิดกับประเด็นที่ว่า "LLM สร้าง mind model ที่ชัดเจนไม่ได้"
ผมไม่แน่ใจว่า LLM ที่ยึดกับข้อความจะสามารถแก้ปัญหานี้ได้จริงหรือเปล่า
มันทำให้นึกถึงกรณีของ Google Genie 3 ที่ดูเหมือนจะสูญเสีย state ภายในภายในเวลาประมาณ 1 นาที
ผมมีลางสังหรณ์ว่าปัญหานี้คงต้องอาศัยสถาปัตยกรรมใหม่ระดับเหนือกว่า transformer ถึงจะทำให้มีทั้ง context ระยะสั้น ระยะยาว และการปรับน้ำหนักกับตัวเองได้ (คล้ายการเลียนแบบการเรียนรู้)
ดู: การอภิปรายที่เกี่ยวข้อง
ช่วงนี้ผมเริ่มคิดว่าโครงสร้าง agent แบบลำดับชั้นอาจเป็นทางเลือกที่สมจริงกว่า
ถ้า agent ระดับบนสุดคอยเก็บเฉพาะ mind model ทั้งหมดไว้ แล้วให้ agent ชั้นล่างแบ่งงานกันทำ น่าจะดี
แม้ตอนนี้ก็น่าจะพอทำคล้าย ๆ กันได้ด้วยฟีเจอร์ agent ของเครื่องมือ Code อยู่แล้ว เลยอยากรู้ว่ามีใครยินดีแชร์กลยุทธ์เรื่องนี้บ้างไหม
ผมลองใช้ claude-code-requirements-builder แล้วดีขึ้นนิดหน่อย แต่ก็ยังไม่ถึงกับพอใจ
ในโลกการทำงานจริง นักพัฒนาจูเนียร์ 'โดยเฉลี่ย' ก็ไม่ได้ต่างจากที่เล่ามาข้างล่างมากนัก
มักคิดว่าโค้ดที่ตัวเองทำมาถูกต้องแน่นอน พอเทสต์ล้มก็ทำอะไรไม่ถูก ถ้าหาทางต่อไม่ได้จริง ๆ แย่สุดก็คือลบโค้ดทิ้งหมดแล้วเริ่มใหม่
มีทั้งการก๊อปปี้จาก StackOverflow โทษคอมไพเลอร์ หรือหนักถึงขั้นโทษว่าเป็นเพราะ 'รังสีคอสมิกของจักรวาล'
ยิ่งใช้ LLM ผมก็ยิ่งรู้สึกด้วยตัวเองว่าสุดท้ายผมต้องเป็นคนถือการวางแผนและการออกแบบอยู่ดี
แต่ก็ชอบตรงที่ผมมอบงานซ้ำ ๆ ระดับล่างและเทสต์ให้ LLM ทำแทนได้ ทำให้มีเวลาไปคิดภาพใหญ่กว่าเดิม
เพียงแต่อยากให้การรีวิวผลลัพธ์ของ LLM และการเสนอการเปลี่ยนแปลงต่าง ๆ ดีขึ้นในเชิงปฏิสัมพันธ์มากกว่านี้
ผมคิดว่าทิศทางของสตาร์ตอัป AI คือหัวใจของปัญหานี้ในตอนนี้
สิ่งที่ต้องการไม่ใช่แค่แชตอินเทอร์เฟซธรรมดา แต่เป็น AI workflow ที่ผสานเข้าไปใน IDE อย่างเป็นธรรมชาติ
นี่กำลังเป็นเทรนด์ในทิศทางเดียวกับที่เห็นใน Visual Studio, InteliJ และ Android Studio
ผมอยากได้เครื่องมือที่ใกล้เคียงโปรแกรมเมอร์จริง ๆ คือสั่งงานด้วยเสียงในภาษาของตัวเองได้ AI เข้าใจบริบททั้งโปรเจกต์ แล้วครอบคลุมทั้งรีแฟกเตอร์ การวิเคราะห์แบบ static การให้ฟีดแบ็กจาก AI สเก็ตช์เป็น UI เขียนโค้ดจากลายมือ ไปจนถึงสร้าง commit message จากการเปลี่ยนโค้ด
ผมเห็นด้วยว่า LLM มีประโยชน์มากพอสมควรกับงานระดับจูเนียร์
ช่วงหลังผมกลับมาคิดใหม่กับคำพูดเก่า ๆ ที่ว่า 'ความเร็วในการพิมพ์ไม่ค่อยสำคัญ'
แต่ก่อนเราคิดว่าความเร็วในการเขียนโค้ดไม่สำคัญเท่าการออกแบบและการจัดโครงสร้างระบบอยู่แล้ว เวลาที่ใช้พิมพ์จริงจึงไม่ได้มีสัดส่วนมาก
แต่พอได้ใช้ Claude ผมกลับรู้สึกว่าสิ่งที่ต่างออกไปคือ มันทำให้การเปลี่ยนโค้ดที่เมื่อก่อนน่ารำคาญจนไม่ค่อยอยากทำ กลายเป็นเรื่องที่ทำได้ง่ายโดยไม่ต้องใช้สมาธิมาก
เมื่อก่อนถ้าจะเพิ่มค่า enum แค่ตัวเดียว ก็ต้องไล่แก้ทุกจุดที่ match กันอย่างระมัดระวัง แต่ LLM ช่วยแก้จุดเหล่านั้นให้ได้อัตโนมัติ
งานน่ารำคาญอย่างการไล่แก้ compile error ทีละจุด ก็แค่สั่ง Claude ให้แก้วนไปเรื่อย ๆ
พอมี agent หลายตัวช่วยกันแตะโค้ดหลายส่วนพร้อมกัน เวลานั้นผมก็เอาไปคิดโครงสร้างใหญ่ ๆ หรือแม้แต่มาเขียนโพสต์ใน HN ได้
พูดอีกแบบคือ พอไม่ต้องเสียเวลาแก้ compile error เอง ก็ทำการเปลี่ยนแปลงได้มากขึ้นและเร็วขึ้น และงานที่เมื่อก่อนจูเนียร์ต้องใช้เวลาทั้งวัน ตอนนี้อาจจบได้รวดเดียว
เพราะอย่างนั้นผมจึงโฟกัสกับสถาปัตยกรรมโดยรวมได้มากขึ้น และยังจัดการงานจุกจิกที่ดองไว้นานได้หมด ซึ่งช่วยเพิ่มแรงจูงใจได้มาก
ผมเห็นด้วยกับคำพูดที่ว่า "ถึงจะพิมพ์เร็วขึ้น ก็ไม่ได้แปลว่าจะถึงเป้าหมายเร็วขึ้นเสมอไป เพราะคอขวดอยู่ที่การออกแบบ"
LLM นั้นแย่มากในการวางดีไซน์ที่ดี และแม้แต่ในระดับฟังก์ชันเล็ก ๆ ก็ยังต้องรีแฟกเตอร์แทบตลอด
มันช่วยเพิ่มผลิตภาพในขั้นลงมือทำจริงก็จริง แต่ก็เป็นเพียงระดับการทำให้ไอเดียที่มีอยู่แล้วในหัวหรือในเอกสารกลายเป็นรูปธรรม
ถ้าใช้ระดมความคิดก็พอใช้ได้
อย่างเวลายัดทั้งโค้ดและเทสต์ให้แล้วถามว่า "มี edge case อะไรที่พลาดไปไหม" ใน 10 ครั้งก็อาจมีสัก 1-2 ครั้งที่ได้คำแนะนำมีประโยชน์จริง
การแก้ให้ใช้การได้ในระยะสั้น กับความเป็นเลิศเชิงโครงสร้างในระยะยาว เป็นปัญหาคนละแบบกันมาก เลยยังไม่รู้ว่า LLM จะตามมาทันอย่างหลังได้หรือไม่
เรื่องที่ว่า "มีสิ่งที่อยากทำกับ codebase อีกเพียบ" สำหรับผมกลับรู้สึกว่าคอขวดจริง ๆ คือการรีวิว มากกว่าการแก้โค้ดเอง
ถ้าสิ่งที่ว่า "LLM ทำงานที่จูเนียร์ต้องใช้เวลาทั้งวันได้อย่างรวดเร็ว" นำไปสู่การลดโอกาสการเรียนรู้ของคนรุ่นใหม่และทำให้การจ้างงานหดตัวลง ผมก็อดกังวลไม่ได้ว่าแล้วใครจะเป็นคนปั้นพวกเขาให้เติบโต
สำหรับอาการที่ว่า "พอเทสต์ล้มแล้วมันตัดสินใจไม่ได้ว่าจะต้องแก้โค้ดหรือแก้เทสต์"
การใช้ภาษาของ "Red-Green-Refactor" ช่วยได้
ตอนนี้ผมจะสื่อกับ LLM ให้ชัดว่ากำลังอยู่ในขั้น RED (เทสต์ล้มเป็นเรื่องปกติ), ขั้น GREEN (ทำให้ผ่านด้วยโค้ดน้อยที่สุด) หรือขั้น REFACTOR (ปรับปรุงโค้ดโดยไม่ให้เทสต์พัง)
แบบนี้ LLM จะไม่ได้มองว่าเป็นแค่การ "ซ่อมโค้ดที่พัง" แต่จะรับรู้ mind model ของ TDD ได้
ผมคิดว่าชัดเจนอยู่แล้วว่า LLM ยังไม่ถึงระดับที่บอกว่า "ช่วยสร้าง Facebook ของฉันขึ้นมาใหม่ทั้งระบบ" ได้
แต่ถ้าเป็นงานละเอียดระดับ "เพิ่ม modal แบบนี้ให้หน่อย แล้วอิงสไตล์จากโค้ดเดิมด้วย" ผมเคยได้ผลลัพธ์ตรงใจอยู่หลายครั้ง
ถ้าแตกปัญหาเป็นหน่วยเล็ก ๆ แล้วส่งให้ทีละอย่าง ผลลัพธ์จะดีกว่ามาก
ถ้าเป็นแค่การก๊อปโค้ดเดิมแล้วแก้ให้ตรงที่ต้องการ ผมทำเองได้อยู่แล้ว
system clipboard ของผมทำงานแบบกำหนดผลได้แน่นอนเสมอ ไม่เหมือน LLM ที่ชอบสร้างปัญหาใหม่แบบคาดไม่ถึงได้ไม่รู้จบ
ผมก็สงสัยเหมือนกันว่าเครื่องมือเกิดใหม่อย่าง v0 จะรับมือกับคำขอแบบนี้อย่างไร
ผมรู้สึกว่ากระบวนการ 4 ขั้นตอนที่เกริ่นไว้ตอนต้นบทความ คล้ายกับแนวคิดใน "The Beginning of Infinity" ของ Deutsch มาก
ทฤษฎีของเราเริ่มจาก 'การคาดเดา' และความรู้เกิดขึ้นจาก 'วงจรของการคาดเดาและการวิพากษ์'
การเขียนโค้ดคือรูปแบบหนึ่งของ 'การคาดเดา' และการสร้างเทสต์คือ 'การวิพากษ์' ต่อการคาดเดานั้น
ทั้งสองอย่างคือความพยายามที่จะเข้าใกล้คำอธิบายในหัวของเรา (อุดมคติแบบเพลโต) ให้มากขึ้น