- ต่อให้ LLM จะยังคงเขียนโค้ดแทนเราไปเรื่อย ๆ แต่ถ้านำ
if เงื่อนไขที่ซ้ำซ้อนและการทำแบบชั่วคราวมารวมเข้าระบบตามเดิม โค้ดที่ถูกสร้างในภายหลังก็อาจทำตามแนวปฏิบัตินั้นราวกับเป็น กฎของโปรเจกต์
- หากใส่ตรรกะตรวจสอบสิทธิ์การเข้าถึงซ้ำไว้ใน route handler, background job, API endpoint, webhook ฯลฯ แม้การทดสอบจะผ่าน แต่ ภาระในการบำรุงรักษา ก็ยังคงอยู่เหมือนเดิม
- โมเดลสร้างโค้ดถัดไปจากการดูไฟล์ที่เปิดอยู่, แพตเทิร์นที่มีอยู่เดิม, และการเปลี่ยนแปลงล่าสุด ดังนั้น
if ที่ถูกคัดลอกมา 4 ชุดจึงเป็นสัญญาณเรียกสำเนาชุดที่ห้า
- ต่อให้ขอให้รีแฟกเตอร์ในภายหลัง ก็ยากจะรับประกันว่า LLM จะจัดการสำเนาเดิมทั้งหมดได้อย่างถูกต้อง และแพตเทิร์นที่ไม่ดีก็จะค่อย ๆ กลายเป็น สไตล์ของโค้ดเบส มากกว่าจะเป็นความผิดพลาดเพียงครั้งเดียว
- เมื่อ
if ซ้ำซ้อน, ฟังก์ชันแบบ “god”, และการ merge แบบ “ไว้ค่อยจัดการทีหลัง” สะสมมากขึ้น การย้อนกลับด้วยพรอมป์ตอย่างเดียวจะยิ่งยาก และสุดท้ายมนุษย์ก็ต้องลงมาแก้เอง
สิ่งที่ LLM อ้างอิงคือโค้ดเบสปัจจุบัน
- LLM ไม่ได้เขียนโค้ดใน “สุญญากาศ” แต่จะอ่านโค้ดเบสของผู้ใช้
- ไฟล์ที่เปิดอยู่
- แพตเทิร์นที่มีอยู่แล้ว
- การเปลี่ยนแปลงล่าสุด
- ทางลัดที่ถูก merge เข้าโค้ดเบสจะกลายเป็น สัญญาณการเรียนรู้ ว่า “ที่นี่ทำกันแบบนี้”
- เงื่อนไขควบคุมสิทธิ์การเข้าถึงเดียวกันอาจถูกทำซ้ำอยู่หลายจุด
if (user.isActive && user.hasPermission('read') &&
!user.isSuspended && account.status === 'open') {
// do a thing
}
- เงื่อนไขนี้สามารถแยกออกเป็น shared helper ได้ แต่เพราะโค้ดที่ LLM สร้างยังทำงานได้และการทดสอบผ่าน จึงอาจถูก merge เข้าไปทั้งแบบนั้น
- เมื่อขอ endpoint ตัวที่ห้าที่ใช้กฎเดียวกัน โมเดลก็มักมีแนวโน้มจะทำตามสำเนาเดิมที่มีอยู่ใน repository มากกว่าจะออกแบบใหม่ตั้งแต่ต้น
ความเข้าใจผิดที่คิดว่ายกงานบำรุงรักษาให้ LLM ได้
- ความคิดที่ว่า “เดี๋ยวตอนเปลี่ยนทีหลัง LLM ก็ทำให้ได้” ทำให้ปล่อยปละเรื่องความซ้ำซ้อนและ code smell ได้ง่าย
if ที่ซ้ำกันไม่กี่จุดอาจยังไม่ถึงขั้นร้ายแรง แต่ code smell แบบนี้จะสะสมต่อเนื่อง
if ซ้ำซ้อน
- ฟังก์ชันแบบ “god”
- การ merge ที่ตั้งใจว่า “ไว้ค่อยจัดการทีหลัง”
- เมื่อแพตเทิร์นที่ไม่ดีเพิ่มขึ้น ผลลัพธ์ของพรอมป์ตถัดไปก็จะได้รับผลกระทบด้วย และยากจะเชื่อได้ว่าในภายหลัง LLM จะแก้ทุกอินสแตนซ์ได้ครบโดยไม่ตกหล่น
- แม้จะคิดว่าเป็นการ outsource งานบำรุงรักษาให้ LLM แต่ในความเป็นจริง อาจกลายเป็นการทำให้มันทำซ้ำนิสัยที่แย่ลงเรื่อย ๆ
- ควรเขียนโค้ดราวกับว่าจะมีมนุษย์มาดูแลรักษามัน และต้องรักษา แพตเทิร์นโค้ด ที่ LLM จะซึมซับและสะท้อนกลับมาให้อยู่ในสภาพที่ดี
1 ความคิดเห็น
ความคิดเห็นจาก Hacker News
ควรสร้าง คำสั่ง /review เป็นไฟล์ Markdown ว่างใน
.claude/commands/review.mdแล้วใส่เช็กลิสต์ที่อยากให้เอเจนต์ตรวจไว้เมื่อต้องการรีวิวโค้ด ให้พิมพ์
/reviewแล้วมันจะดูเช็กลิสต์นั้น วางแผนรายการที่น่าจะแก้ไข จากนั้นถามกลับมาไฟล์ของผมเริ่มด้วย “เข้าสู่โหมดวางแผน ดูความแตกต่างระหว่างบรานช์นี้กับ main สิ่งที่ต้องพิจารณา: ...” และผมค่อย ๆ เพิ่มรายการที่พบระหว่างรีวิวโค้ดแล้วให้เอเจนต์แก้เข้าไปเรื่อย ๆ ตอนนี้มีราว 200 รายการแล้ว
เอเจนต์ไม่ค่อยสนใจแม้จะได้รับกำแพงฟีดแบ็กทั่วไป และจะไล่ดูทีละรายการ พอใส่ “ตรวจสอบว่าสิ่งที่สร้างขึ้นใหม่ไม่ซ้ำซ้อนกับโค้ดเดิม” เข้าไป มันก็เริ่มวางแผนงานจัดระเบียบจริง ๆ ซึ่งน่าประหลาดใจ
ตอนนี้ยังเป็นแค่การแตะผิว ๆ เท่านั้น และเราต้องให้ เครื่องมือสำหรับเครื่องมือ เพื่อให้เครื่องมือกลายเป็นเครื่องมือที่ดีกว่าเดิม
ตอนนี้ผมยังใช้คำสั่งที่ค่อนข้างเรียบง่าย แต่ Claude ก็มักฝ่าฝืนคำสั่งแรก ๆ เช่น “ห้าม commit ลง git โดยไม่ได้รับอนุญาต” หรือ “ห้ามเซ็นชื่อใน commit message”
พอถาม มันจะตอบว่า “ใช่ มีคำสั่งนั้นอยู่ แต่ฉันละเลยไป” และถ้าแก้ให้สุภาพ ๆ ในเซสชัน มันก็เข้าใจ แต่หลังจากนั้นบางครั้งกลับกลายเป็นสภาพที่ commit ไม่ได้เลย
ถ้าให้ตรวจ เช็กลิสต์ 200 รายการ มีความเป็นไปได้สูงว่ามันจะพลาดหลายรายการไปแบบเงียบ ๆ
ถ้าเป็นวิศวกรมนุษย์ เมื่อมีไลบรารี assertion ที่เทสต์เดิม 200 รายการใช้อยู่ ก็คงไม่ใช้ไลบรารีที่ต่างไปโดยสิ้นเชิงในเทสต์ใหม่ แต่ Claude ทำแบบนั้นหลายครั้ง
ดังนั้นผมจึงต้องคอยเพิ่มรายการอย่าง “ก่อนเขียน ให้ดู ธรรมเนียมปฏิบัติของเทสต์ ก่อน” เข้าไปเรื่อย ๆ
ในทางกลับกัน เรื่องพื้นฐานอย่างฟังก์ชันคืออะไร หรือเทสต์ควรครอบคลุม diff ของการเปลี่ยนแปลง ไม่จำเป็นต้องบอกก็ได้ แต่ไม่มีรายการที่ชัดเจนว่าควรบอกเรื่องไหน และเรื่องไหนปล่อยได้ จึงรู้สึกเหมือนต้องลองผิดลองถูกเพื่อสร้างวิธีที่พอใช้ได้
กรณีของผม มักจะปรับแก้โต้ตอบกับเอเจนต์ไปเรื่อย ๆ “จนกว่าจะดูโอเคในสายตาและรสนิยมของผม” แต่ยังไม่ได้ทำรายการแบบนั้นไว้
บางโปรเจกต์อาจยอมให้มีปัญหาเล็กน้อยหรือ magic number ได้ ส่วนอีกโปรเจกต์อาจบังคับให้ใช้ค่าคงที่ที่มีชื่อสื่อความหมายอย่าง
SECONDS_IN_A_DAY = 24 * 60 * 60จึงเป็นเรื่องที่ ขึ้นกับบริบทhttps://github.com/alibaba/open-code-review
https://layandreas.github.io/personal-blog/posts/beyond-vide...
เช่น ให้เลือก N บทบาทที่เหมาะสมที่สุดกับการเปลี่ยนแปลง จากรายการบทบาทยาว ๆ อย่าง Senior Engineer, Security Engineer, WCAG specialist
Claude จะรันรีวิวเหล่านั้นแบบขนาน แล้วรวมฟีดแบ็กให้
เพราะผมทำการพัฒนาแบบอิงสเปก จึงนำประเด็นที่พบไปเพิ่มในสเปก เพื่อทิ้งร่องรอยของประเด็นและการตัดสินใจไว้
ตรงนี้แปลกมากที่วิศวกรจำนวนมากยังไปใส่พรอมป์ต์เพิ่มอีก
จากประสบการณ์ของผม ยิ่งทำแบบนั้นก็ยิ่งแย่ลง มันทำ abstraction ก็จริง แต่สร้าง abstraction ที่ผิด แถมใส่คอมเมนต์มากเกินไปจนทำให้การเรียก LLM ครั้งถัด ๆ ไปสับสนด้วย
ใน codebase ที่ดีมันก็พอทำงานได้ แต่จะค่อย ๆ ทำให้โค้ดแย่ลง และถ้าใช้ต่อไปเรื่อย ๆ จนถึงจุดหนึ่งมันไม่ทำงาน ก็ต้องจ่ายราคาที่ไม่ได้สร้างมันด้วยมือตัวเองแล้วค่อยตามแก้
เวลาใส่เอเจนต์เข้าไปใน codebase ใหม่ ๆ โดยทั่วไปยังมี mental model ของโค้ดอยู่ และโค้ดก็ยังค่อนข้างกระชับ แต่เมื่อทำซ้ำสะสมไปเรื่อย ๆ ทั้งสองอย่างนั้นจะหายไป และประสิทธิภาพของ LLM ก็ลดลงด้วย
ดังนั้นผมใช้ LLM กับ การสำรวจและรีวิว ส่วนโค้ดเขียนเอง
การเขียนโค้ดไม่ได้กินเวลามากขนาดนั้น และยังเป็นส่วนที่สนุกที่สุดด้วย จึงเข้าใจยากว่าทำไมถึงพยายามเลี่ยงกัน บางครั้งลองใช้พรอมป์ต์
/bugแข่งดีบักกับ AI พร้อมกัน ก็ไม่ได้แปลว่า AI จะเร็วกว่าเสมอไปในช่วงไม่กี่ปีที่ผ่านมา งานซอฟต์แวร์เปลี่ยนจากหนึ่งในที่หลบภัยทางวิศวกรรมเชิงปฏิบัติของคนชอบประดิษฐ์ช่างสงสัยและคนติดปริศนา ไปเป็นเส้นทางอาชีพของคนฉลาดที่มุ่งเงิน เหมือนการเงิน กฎหมาย หรือการแพทย์
ตอนนี้หลายคนที่มีตำแหน่ง “software engineer” ไม่เคยสนุกกับงานนี้มาตั้งแต่แรก เพียงแต่ฉลาดและมีความรับผิดชอบพอที่จะทำเป้าหมายที่นายจ้างมอบให้สำเร็จ
คนกลุ่มนั้นเป็นคนที่อยากให้เอเจนต์ AI ช่วยกันงานออกแบบที่ต้องเคร่งครัดและงานปริศนาออกไปมากที่สุด และช่วยให้ใช้ความฉลาดตามธรรมชาติของตัวเองแบบขี้เกียจขึ้นได้
เพราะไม่ได้ซึมซับหลักการเขียนโค้ดและวิศวกรรมไว้ภายใน เมื่ออยู่ท่ามกลางเพื่อนร่วมงานที่มีกรอบคิดเดียวกัน ก็ยากจะคาดเดาว่าวิธีนี้จะก่อผลอะไรในอนาคต
ถ้าการเขียนโค้ดเองเป็นประสบการณ์ที่น่าอึดอัดและมีแรงเสียดทานสูงมากมาตั้งแต่ต้น ก็รู้สึกได้ง่ายว่า AI เร็วกว่า
แค่อ่านโค้ดอย่างเดียวไม่พอ ต้องผ่านความเจ็บปวดด้วยตัวเองถึงจะซึมซับเข้าไปได้
เอเจนต์มักจะห่อหุ้มโค้ดเก่าอย่างตั้งรับ แทนที่จะถามว่าเส้นทางเดิมยังควรมีอยู่หรือไม่ ทำให้เกิดเอฟเฟกต์ที่โค้ดป้องกันตัวปริมาณมหาศาล ซ้อนกันเป็นชั้น ๆ เหมือนตุ๊กตารัสเซีย
https://softwaredoug.com/blog/2026/07/09/write-code
Opus 4.8 เป็นจุดเปลี่ยน และโดยเฉพาะกับปัญหาซับซ้อน ตอนนี้ผมชนะ Opus 4.8 ได้ไม่มากนัก
ถ้าทุกคนใช้ Opus 4.8 ขึ้นไปกับทุกงานและทุกคำถาม บรรยากาศโดยรวมคงเปลี่ยนไปมาก และคงเหลือคนกังขา AI ไม่มากนัก
ยังเขียนโค้ดด้วยมือเอง และบางส่วนแม้ไม่ใช่ทั้งหมดก็ให้ Opus สร้าง
อาจเป็นความคิดนอกกรอบก็ได้ แต่ก็แค่ เขียนโค้ดเอง ก็พอ
ในยุค AI นี่อาจฟังดูเหมือนแนวคิดที่ไม่น่าเชื่อ แต่ถ้าเป็นโค้ดที่มนุษย์ต้องอ่านและบำรุงรักษา การเขียนเองเพื่อคนเหล่านั้นน่าจะดีกว่า
เวลาอ่านโค้ดที่ยืดยาวเกินไปและ copy-paste มา คุณจะหงุดหงิด และคนอื่นก็เหมือนกัน
ถ้าเขียนเอง คุณจะปรับแก้ด้วยตัวเอง และเขียนในแบบที่สมเหตุสมผลสำหรับให้คนอื่นบำรุงรักษา
หรือไม่ก็อาจปลอบเอเจนต์กับลูปด้วยการสร้างตาข่ายไฟล์ Markdown อันซับซ้อน เพื่อให้มันเข้าใจหน้าตาโค้ดที่ผู้ดูแลในอนาคตคาดหวัง
ระยะยาวไม่รู้ว่าเส้นทางไหนง่ายกว่า และก็อยากรู้ว่ามีใครเคยรับช่วง codebase ที่ขับเคลื่อนโดยเอเจนต์แบบวนลูป แล้วทำความเข้าใจมันได้หรือยัง
ผมไม่ค่อยแน่ใจว่าคำพูดที่ว่า “ครั้งถัดไปที่คุณขอ endpoint ที่มีกฎการเข้าถึงแบบเดียวกันจาก LLM โมเดลจะไม่ได้คิดจากศูนย์ แต่เริ่มจากสำเนาสี่ชุดที่มีอยู่แล้วใน repository” ถูกต้องแค่ไหน
ในความเป็นจริง ดูเหมือนมันมี อคติที่ฝังมาในตัว ให้ทำโครงสร้างพื้นฐานซ้ำ ๆ และพยายาม reuse หรือทำ abstraction น้อยลง
ถ้าแพตเทิร์นเดิมเป็นแบบนั้น มันก็เหมือนกำลังทำตาม แต่จริง ๆ แล้วมีโอกาสสูงที่ไม่ว่าจะทางไหนมันก็จะทำแบบนั้นอยู่ดี
ต่อให้วาง abstraction ที่เข้มงวดและตัวอย่างการใช้งานไว้ก่อน แล้วสั่งอย่างชัดเจนให้ใช้เฉพาะ API ของ abstraction นั้นและให้ลอกวิธีที่ผมเขียนด้วย LLM รุ่นใหม่ ๆ ก็มักไม่ทำทั้งสองอย่าง แต่กลับ implement โครงสร้างพื้นฐานใหม่จากด้านล่าง และเพิกเฉยต่อ abstraction บางส่วนหรือทั้งหมด
ผมไม่รู้แน่ชัดว่าทำไม แต่เดาว่าในโค้ดสำหรับฝึกมีโค้ดลักษณะนี้มากเกินไป จน weight “รู้” วิธีให้ผลลัพธ์แบบนี้ได้ดีกว่า
ถึงอย่างนั้น ผมก็ยังคิดว่าใช้ LLM เป็น implementation engine ที่รวดเร็วได้ดี
โจทย์คือทำให้โมเดลเผยการตัดสินใจด้าน implementation เหล่านี้ออกมาก่อนที่มันจะวิ่งไปผิดทาง
หลังการเปลี่ยนแปลงใหญ่ ๆ ผมได้ผลลัพธ์ดีจากพรอมป์ต์ต่อไปนี้
“ตอนนี้ให้ตรวจโค้ดขั้นสุดท้าย ทุกอย่างถูกจัดระเบียบเรียบร้อยหรือไม่ และคอมโพเนนต์ต่าง ๆ ทำตามหลัก separation of concerns หรือไม่ อยู่ในสภาพที่เข้าใจได้และบำรุงรักษาได้หรือไม่ มี assumption ใดที่อาจไม่เป็นจริงอีกต่อไปหรือไม่ มีโค้ดที่หลงเหลือจากการแก้ไขหรือการทดลองก่อนหน้านี้เข้าไปอยู่ใน codebase หรือไม่ เอกสารยังสะท้อนสถานะปัจจุบันของโค้ดอยู่หรือไม่”
แล้วมันมักจะอนุมานสิ่งที่พูดข้างบนและมากกว่านั้นได้เอง
แต่สิ่งที่ยังต้องคอยชี้ตรง ๆ คือให้ลบคอมเมนต์สำหรับ “ติดตามความคืบหน้า” ทั้งหมด และเหลือไว้เฉพาะคอมเมนต์ที่เหมาะกับการบำรุงรักษาระยะยาว
Claude จะทิ้งคอมเมนต์อย่าง “การคลิกปุ่มตอนนี้ทำให้เกิดการ save และไม่ใช้ onBlur อีกต่อไป” แต่โค้ดจริงไม่เคยใช้ onBlur เลย และมันเป็นแค่ร่องรอยของสิ่งที่ Claude พยายามทำก่อนหน้านี้ในงาน/branch เดียวกันแล้วผมสั่งให้ถอยกลับเท่านั้น
โมเดลจะตีความตามใจมันเอง แต่ถึงอย่างนั้นก็มักดีกว่าไม่ทำอะไรเลย
เป็นวิธีที่สอนทุกอย่างให้ AI แล้วถามว่ามันเรียนรู้ถูกต้องหรือไม่ ซึ่งผลลัพธ์ดีอย่างน่าประหลาดใจ
ผมกำลังทำตามขั้นตอนคล้ายกับบทความนี้
https://www.lucasfcosta.com/blog/backpressure-is-all-you-nee...
มีสุภาษิตเก่าอยู่ว่า
“จงใส่คอมเมนต์ในโค้ดโดยสมมติว่าคนที่จะมาดูแลต่อจากคุณเป็นฆาตกรโรคจิตที่รู้ว่าคุณอยู่ที่ไหน”
ช่วงหลัง ๆ ในการรีวิว PR ผมเจอแบบนี้เป็นครั้งที่เท่าไรก็ไม่รู้ แล้วก็เผลอคอมเมนต์ตอบด้วยความโมโห ซึ่งตัวเองก็ยังตกใจ
ไม่รู้มาก่อนว่าตัวเองจะมีปฏิกิริยาแบบนั้นได้
กล่าวคือ เพราะตัวโค้ดเองไม่ชัดเจนจึงต้องมีคอมเมนต์ ซึ่งก็มีกรณีแบบนั้นอยู่ แต่โดยทั่วไปผมมองว่ามีคอมเมนต์มากไปยังดีกว่าน้อยไป
โดยเฉพาะถ้ามันอธิบายว่าโค้ดเชื่อมโยงกับธุรกิจจริงหรือ requirements ของฟีเจอร์อย่างไร และไม่ได้แค่พูดซ้ำสิ่งที่โค้ดทำ ก็ยิ่งดี
เมื่อหลายปีก่อนผมเคยเขียนคอมเมนต์ก่อน
อธิบายเป้าหมายทั้งหมด แบ่งออกเป็น routine และลำดับงาน จากนั้นเมื่อพอใจแล้วจึงเติมบล็อกโค้ดลงไประหว่างคอมเมนต์
มันคล้ายกับ literate programming อยู่บ้าง แต่ผมทำแบบนี้มาตั้งแต่ก่อนรู้จักคำนี้ และใกล้เคียงกับการ prompt ตัวเองให้มุ่งไปสู่เป้าหมายมากกว่า
ข้อเสียคือคอมเมนต์มักลงเอยเป็นเพียงการอธิบายเป็นภาษาอังกฤษว่าโค้ดทำอะไร ซึ่งอาจไม่ค่อยมีประโยชน์กับผู้ดูแลในอนาคตนัก
โค้ดควรอธิบายตัวเองได้ และคอมเมนต์ควรใช้ตรงที่มีมังกรอยู่
ในทำนองเดียวกัน prompt ที่ผมชอบคือ “ช่วยตรวจทาน test ที่คุณเขียนหน่อย test นี้กำลัง test สิ่งที่ตั้งใจไว้จริงไหม? ถ้าโค้ดพัง test จะ fail ด้วยไหม?”
น่าตกใจมากว่า LLM เขียน test เปล่า ที่ไม่ได้ตรวจสอบอะไรเลยบ่อยแค่ไหน
ยังต้องมาคุยเรื่องแบบนี้กันอย่างจริงจังอีกหรือ
ถ้าได้ “ทดลอง” กับ LLM แบบนั้นแล้ว ตอนนี้ก็ควรยอมรับกันได้แล้วไม่ใช่หรือ
ผมสงสัยว่าเมื่อไรเราจะคุยเรื่องการกลับมาเขียนโค้ดด้วยมือได้โดยไม่ทำเหมือนมันเป็นเรื่องต้องห้ามอีก
LLM มีประโยชน์ในหลายทาง แต่พอเห็นผู้คนมอบหมายการพิมพ์ source code ทั้งหมดให้ agent
ก็ให้ความรู้สึกคล้ายกับการถูกบอกว่าเพราะเว็บดี เราจึงต้องมีความสุข
ผมกำลังให้หลายโมเดลรันกับ codebase ต่อเนื่อง เพื่อให้ค้นหา code smell อย่าง โค้ดซ้ำ
มันได้ผลค่อนข้างดี และถ้าไม่คอยดูแลต่อไปเรื่อย ๆ เมื่อเวลาผ่านไปมันก็น่าจะกลายเป็นก้อนรก ๆ และสะสมมากขึ้น
ใส่ไว้ใน build pipeline ได้ด้วย และไม่ใช้ token เลยแม้แต่น้อย
หรือว่ากระบวนการรีวิวกับ การรีเซ็ต context สำคัญกว่ากัน?
ผมเห็น duplication แบบนี้และสิ่งที่แย่กว่านี้อีกมาก แม้ในโค้ดที่ผู้คนดูแลกันมายี่สิบปี
พูดตรง ๆ คือส่วนใหญ่โค้ดที่มนุษย์เขียนและดูแลมักแย่กว่าสิ่งที่ LLM สร้างตอนนี้เสียอีก
บางครั้งเป็นเพราะขาดประสบการณ์ บางครั้งเป็นการละเลยโดยเจตนา แต่โดยรวมมักเป็นเพราะกำหนดการที่บีบมากและแรงกดดันว่าต้องทำให้เสร็จตอนนี้
ผู้คนรู้วิธีทำให้ดีกว่านี้ แต่ในความเป็นจริงไม่มีเวลาและงบประมาณให้ทำแบบนั้น
LLM ก็เรียนรู้สิ่งนั้นไปด้วย