Beyond the Code
การเป็น software engineer ที่ดีไม่ได้มีแค่เรื่องของการเขียนโค้ดที่ทำงานได้ แต่ยังรวมถึงการเขียนโค้ดที่คนอื่น (รวมถึงตัวเราในอนาคต) สามารถเข้าใจ ดูแลรักษา และต่อยอดได้ด้วย มันเกี่ยวกับการสื่อสารที่ชัดเจน การมีส่วนร่วมอย่างรอบคอบ และการเป็นพลเมืองที่ดีใน ecosystem ที่เราอยู่ ไม่ว่าจะเป็น open source หรือ proprietary
การสื่อสารทางเดียว
งาน software engineering ส่วนใหญ่เกี่ยวข้องกับการเขียนให้คนที่ไม่มี context เดียวกับเราอ่าน ไม่ว่าจะเป็นเพื่อนร่วมทีมที่เข้ามาทีหลัง, maintainer ที่มารับช่วงโค้ดต่อ, หรือตัวเราเองในอีกหกเดือนข้างหน้าเมื่อลืมไปแล้วว่าทำไมถึงตัดสินใจแบบนั้น คำแนะนำสำคัญสำหรับการเขียนทุกรูปแบบแบบนี้คือ เป้าหมายของเราควรจะจับและสื่อสาร เหตุผล (why) ไม่ใช่แค่ สิ่งที่ทำ (what) เพราะ what มักจะอธิบายตัวมันเองได้อยู่แล้ว แต่ why คือความรู้ที่ได้มาอย่างยากลำบากและหายไปง่ายตามกาลเวลา
รูปแบบการสื่อสารระหว่าง engineer ที่พบบ่อยที่สุด (นอกเหนือจากตัวโค้ดเอง) คือ code comment ส่วนตัวแล้วรู้สึกว่า code comment จำนวนมากไม่ค่อยมีประโยชน์ แต่มันไม่จำเป็นต้องเป็นแบบนั้น comment ที่ดีอธิบายสิ่งที่โค้ดเองบอกไม่ได้ นั่นคือ ทำไม ถึงทำแบบนั้น ไม่ใช่ ทำงานยังไง (ซึ่งโค้ดบอกอยู่แล้ว) comment ที่ดีช่วยประหยัดเวลาหลายชั่วโมงจากความสับสน ในขณะที่ comment ที่แย่เป็นแค่ noise หรือแย่กว่านั้นคือทำให้เข้าใจผิด
ประเภทของ comment ที่คุ้มค่าเกือบทุกครั้ง:
- TODO: ทำเครื่องหมายโค้ดที่ยังไม่เสร็จหรือยังไม่สมบูรณ์ แต่ใส่ context ให้เพียงพอเพื่อให้คนอื่นเข้าใจว่ามีอะไรที่ยังค้างอยู่และทำไมถึงเลื่อนออกไป “TODO: optimize” ไม่มีประโยชน์ แต่ “TODO: this O(n²) loop is fine for
n<100, but will need indexing if we scale” นั้นนำไปใช้งานได้จริง - Reference: ลิงก์ไปยังแหล่งข้อมูลภายนอกเมื่อโค้ด implement algorithm จาก paper, ดัดแปลงโค้ดจากที่อื่น, หรือเข้ารหัสพฤติกรรมที่ระบุไว้ใน documentation ใช้ permalink เสมอ และบันทึกส่วนที่แตกต่างจาก reference ด้วย
- Correctness argument: อธิบาย ทำไม โค้ดที่ไม่ตรงไปตรงมาถึงให้ผลลัพธ์ที่ถูกต้อง โค้ดแสดงขั้นตอน แต่ comment อธิบายว่าทำไมขั้นตอนเหล่านั้นถึงทำงานได้
- บทเรียนที่ได้มาอย่างยากลำบาก: ถ้าใช้เวลา debug อะไรสักอย่าง 30 นาทีขึ้นไป แล้ววิธีแก้เป็นสิ่งที่ไม่ชัดเจน ให้ document มันไว้ ตัวเราในอดีตไม่รู้ว่ามันจำเป็น คนที่มาอ่านในอนาคตก็จะไม่รู้เช่นกัน
- เหตุผลของค่าคงที่: Magic number สมควรได้รับคำอธิบาย ทำไม 1492? ทำไม 16 bits? มันถูกเลือกแบบสุ่ม ได้มาจากการทดสอบ หรือจำเป็นเพื่อความถูกต้อง? แม้แต่ “chosen arbitrarily” ก็เป็นข้อมูลที่มีประโยชน์
- ตัวเลือกที่ส่งผลต่อความถูกต้อง: ถ้าความถูกต้องขึ้นอยู่กับรายละเอียดการ implement ที่ดูเหมือนไม่สำคัญ (เช่น “must be a BTreeSet because iteration order matters below”) ให้ระบุไว้อย่างชัดเจน
- “ทำไมถึงไม่”: เมื่อจงใจเลี่ยงวิธีที่ชัดเจน ให้อธิบายว่าทำไม ไม่งั้นจะมีคนมา “แก้ไข” มันทีหลังแล้วทำให้พัง
README (มีอยู่แล้วใช่ไหม?) เป็นอีกหนึ่งจุดสัมผัสแรกกับนักพัฒนาคนอื่นที่พบบ่อย README ที่ดีตอบสี่คำถามทันที: สิ่งนี้ทำอะไร? ทำไมควรสนใจ? ใช้งานยังไง? ติดตั้งยังไง? เรียงตามลำดับนี้ จัด structure เหมือน funnel: ใส่ one-liner และอาจจะมี visual demo ไว้ด้านบนเพื่อให้คนตัดสินใจได้ในไม่กี่วินาทีว่าสิ่งนี้แก้ปัญหาของเขาได้ไหม จากนั้นค่อยเพิ่มรายละเอียดทีละน้อย แสดงวิธีใช้งานก่อนการติดตั้ง — คนอยากเห็นก่อนว่าจะได้อะไรก่อนที่จะ commit เข้าสู่ขั้นตอน setup
Commit message เป็นอีกหนึ่งรูปแบบของ “การเขียนเพื่อคนอื่น” ที่มักถูกละเลย มักเขียนเป็น “fixed blah” หรือ “added foo” ซึ่งอาจเพียงพอในบางกรณี แต่ง่ายที่จะลืมว่ามันเป็นบันทึกประวัติศาสตร์ของ เหตุผล ที่ codebase วิวัฒนาการมาเป็นแบบนี้ เมื่อมีคน (รวมถึงตัวเราเอง!) รัน git blame เพื่อพยายามทำความเข้าใจการเปลี่ยนแปลงที่สับสน commit message ที่ดีควรให้คำตอบได้
โดยทั่วไป body ควรตอบคำถามเหล่านี้:
- ปัญหาอะไรที่บังคับให้เกิดการเปลี่ยนแปลงนี้?
- ทางเลือกอื่นที่พิจารณาแล้วมีอะไรบ้าง?
- trade-off หรือผลกระทบที่ตามมามีอะไร?
- อะไรที่อาจทำให้ผู้อ่านประหลาดใจเกี่ยวกับแนวทางนี้?
แน่นอนว่าควรปรับระดับรายละเอียดตามความซับซ้อน การแก้ typo แค่บรรทัดเดียวแค่มี subject ก็พอ แต่การแก้ race condition ที่ละเอียดอ่อนซึ่งใช้เวลา debug หลายชั่วโมง สมควรได้หลายย่อหน้าที่อธิบายทั้งปัญหาและวิธีแก้
สำหรับการเปลี่ยนแปลงที่ซับซ้อน อาจเป็นประโยชน์ที่จะใช้โครงสร้าง Problem → Solution → Implications: เริ่มจากแรงกดดันหรือข้อจำกัดที่เป็นต้นเหตุ จากนั้นอธิบายว่าเปลี่ยนอะไรไปและ design decision หลักคืออะไร แล้วก็ระบุผลที่ตามมาที่น่าสนใจ (ทั้งบวกและลบ) ส่วนสุดท้ายนี้สำคัญเป็นพิเศษ เพราะงาน engineering จริงเกี่ยวข้องกับการ balance ข้อพิจารณาต่าง ๆ และการ document ว่า trade-off นั้นเป็นสิ่งที่ตั้งใจทำ จะป้องกันไม่ให้นักพัฒนาในอนาคตคิดว่าเราพลาดปัญหานั้นไป
LLM สามารถ ช่วยเรื่องการเขียน commit message ได้ อย่างไรก็ตาม ถ้าแค่ชี้ให้ LLM ดูการเปลี่ยนแปลงแล้วขอให้เขียน commit message LLM จะเข้าถึงได้แค่ what ไม่ใช่ why และ commit message ที่ได้จะเป็นแค่คำอธิบาย (ซึ่งตรงข้ามกับสิ่งที่เราต้องการ!) ถ้าใช้ LLM ช่วยทำการเปลี่ยนแปลงตั้งแต่แรก การขอให้ LLM เขียน commit ใน session เดียวกันนั้นอาจเป็นทางเลือกที่ดีกว่ามาก เพราะบทสนทนาระหว่างเรากับ LLM เป็นแหล่ง context ที่อุดมสมบูรณ์เกี่ยวกับการเปลี่ยนแปลงนั้นโดยธรรมชาติ นอกจากนี้ หรือเพิ่มเติมจากนั้น เทคนิคที่มีประโยชน์คือบอก LLM โดยเฉพาะว่าต้องการ commit message ที่เน้นเรื่อง “why” (และรายละเอียดอื่น ๆ จากบันทึกข้างต้น) แล้ว บอกให้มันถามเราเพื่อขอ context ที่ขาดไป โดยพื้นฐานแล้ว เราทำหน้าที่เหมือน MCP “tool” ให้กับ coding agent ที่มันสามารถใช้เพื่อ “อ่าน” context
เมื่อการเปลี่ยนแปลงซับซ้อนมากขึ้น ให้แยก commit ออกเป็นส่วน ๆ อย่างมีตรรกะด้วย (git add -p เป็นเพื่อนที่ดี) แต่ละ commit ควรเป็นตัวแทนของการเปลี่ยนแปลงที่สอดคล้องกันหนึ่งอย่าง ที่สามารถเข้าใจและ review ได้อย่างอิสระ อย่าผสม refactoring กับ feature ใหม่ หรือรวม bug fix ที่ไม่เกี่ยวกัน เพราะจะทำให้เรื่องราวว่าการเปลี่ยนแปลงไหนแก้ปัญหาอะไรไม่ชัดเจน และเกือบจะแน่นอนว่าจะทำให้การ review ช้าลง นอกจากนี้ยังให้พลังพิเศษผ่าน git bisect แต่นั่นเป็นเรื่องสำหรับคราวหน้า
ข้อสังเกตหนึ่ง เมื่อเริ่มใส่ใจกับการเขียนเชิงเทคนิคมากขึ้นและใช้มันอย่างกว้างขวาง ให้เคารพผู้อ่านด้วย พอเริ่มเขียนแล้วก็ง่ายที่จะอธิบายมากเกินไป แต่ต้องอดทนไม่ทำแบบนั้น เพราะสุดท้ายผู้อ่านอาจไม่อ่านสิ่งที่เราเขียน เลย ให้อธิบาย “why” แล้วเชื่อใจให้พวกเขาหา “how” สำหรับสถานการณ์ของเขาเอง
การทำงานร่วมกัน
ในฐานะ engineer เราอาจใช้เวลาส่วนใหญ่ในการเขียนโค้ดที่คีย์บอร์ดของตัวเอง แต่เวลาจำนวนไม่น้อยก็ถูกใช้ไปกับการสื่อสารกับคนอื่นด้วย เวลาเหล่านั้นมักแบ่งเป็นการทำงานร่วมกันและการให้ความรู้ และผลตอบแทนจากการลงทุนพัฒนาทั้งสองด้านนี้มีมาก
การมีส่วนร่วม (Contributing)
ไม่ว่าจะกำลังส่ง bug report, contribute bug fix ง่าย ๆ, หรือ implement feature ขนาดใหญ่ ควรจำไว้เสมอว่าโดยปกติจำนวนผู้ใช้จะมากกว่าผู้ contribute หลายเท่าตัว และจำนวนผู้ contribute ก็มากกว่า maintainer หลายเท่าเช่นกัน ด้วยเหตุนี้ เวลาของ maintainer จึงเป็นที่ต้องการสูงมาก ถ้าต้องการเพิ่มโอกาสให้ contribution ของเราไปถึงจุดที่เกิดประโยชน์ ต้องทำให้ contribution มีอัตราส่วน signal-to-noise สูง และคุ้มค่ากับเวลาของ maintainer
ตัวอย่างเช่น bug report ที่ดีเคารพเวลาของ maintainer โดยให้ข้อมูลทุกอย่างที่จำเป็นในการเข้าใจและ reproduce ปัญหา:
- Environment: OS, หมายเลขเวอร์ชัน, configuration ที่เกี่ยวข้อง
- สิ่งที่คาดหวัง vs สิ่งที่เกิดขึ้นจริง
- ขั้นตอนในการ reproduce: ระบุให้ชัดเจน “Click the button” มีประโยชน์น้อยกว่า “Click the Submit button on the /settings page while logged in as an admin.”
- สิ่งที่ลองทำแล้ว: ช่วยป้องกันคำแนะนำซ้ำซ้อน และแสดงว่าเราได้ลองตรวจสอบมาบ้างแล้ว
ถ้าพบ security vulnerability อย่าโพสต์สาธารณะ ให้ติดต่อ maintainer เป็นการส่วนตัวก่อน และให้เวลาที่เหมาะสมในการแก้ไขก่อนเปิดเผย หลายโปรเจกต์มีไฟล์ SECURITY.md หรือคล้ายกันสำหรับเรื่องนี้
ต้องค้นหา issue ที่มีอยู่แล้วก่อนเสมอ bug หรือ feature request ของเราอาจถูกรายงานไปแล้ว และการเพิ่มข้อมูลใน discussion ที่มีอยู่ดีกว่าการสร้างซ้ำ ไม่ต้องพูดถึงว่ามันช่วยลด noise ให้ maintainer ด้วย
Minimal reproducible example มีค่ามาก ถ้าสามารถสร้างขึ้นมาได้ มันช่วยประหยัดเวลาและแรงของ maintainer ได้มหาศาล และการ reproduce bug ได้อย่างน่าเชื่อถือมักเป็นส่วนที่ยากที่สุดของการแก้ไข นอกจากนี้ ความพยายามที่ลงไปในการแยกปัญหามักช่วยให้เข้าใจมันดีขึ้นด้วย และบางครั้งนำไปสู่การค้นพบวิธีแก้ไขด้วยตัวเอง
ถ้าไม่ได้รับการตอบกลับทันที ให้จำไว้ว่า maintainer มักเป็นอาสาสมัครที่มีเวลาจำกัด ถ้ากำลังรอคำตอบจากพวกเขา การ follow up อย่างสุภาพหลังจากผ่านไปสองสามสัปดาห์ก็ไม่เป็นไร แต่การ ping ทุกวันไม่ใช่ ในทำนองเดียวกัน comment แบบ “me too” หรือ bug report ที่เป็นแค่การ copy-paste output จาก terminal มักจะส่งผลเสียมากกว่าดีในแง่ของการทำให้ issue ได้รับความสนใจ
ถ้าต้องการ contribute โค้ด ควรทำความคุ้นเคยกับ contribution guideline ด้วย หลายโปรเจกต์มี CONTRIBUTING.md — ให้ทำตามนั้น และโดยปกติควรเริ่มจากเล็ก ๆ การแก้ typo หรือปรับปรุง documentation เป็น first contribution ที่ดี เพราะช่วยให้เรียนรู้ process ของโปรเจกต์โดยไม่ต้องผ่านการ back and forth เรื่องเนื้อหามากมาย
ตรวจสอบว่าโปรเจกต์ใช้ license อะไร เพราะโค้ดที่ contribute จะอยู่ภายใต้ license เดียวกัน โดยเฉพาะอย่างยิ่ง ระวัง copyleft license (เช่น GPL) ซึ่งกำหนดให้ derivative ต้องเป็น open source เช่นกัน และอาจมีผลกระทบต่อนายจ้างถ้าเราไปยุ่งกับมัน! choosealicense.com มีข้อมูลที่มีประโยชน์เพิ่มเติม
เมื่อตัดสินใจเปิด pull request (“PR”) แล้ว ให้แยกการเปลี่ยนแปลงที่ต้องการให้ถูก accept ออกมาก่อน ถ้า PR เปลี่ยนแปลงสิ่งอื่นที่ไม่เกี่ยวข้องหลายอย่างพร้อมกัน โอกาสสูงที่ reviewer จะส่งกลับมาให้ทำความสะอาดก่อน ซึ่งก็คล้ายกับวิธีที่ควรแบ่ง git commit ออกเป็น chunk ที่เกี่ยวข้องกันทาง semantic
ในบางกรณี ถ้ามีการเปลี่ยนแปลงหลายอย่างที่ดูไม่เกี่ยวกัน แต่จำเป็นทั้งหมดเพื่อเปิดใช้ feature หนึ่ง อาจจะเปิด PR ขนาดใหญ่ที่รวมการเปลี่ยนแปลงทั้งหมดก็ได้ อย่างไรก็ตาม ในกรณีนี้ commit hygiene สำคัญเป็นพิเศษ เพื่อให้ maintainer มีตัวเลือกในการ review การเปลี่ยนแปลง “commit by commit”
ต่อมา ให้อธิบาย “why” เบื้องหลังการเปลี่ยนแปลงให้ดี อย่าแค่อธิบาย อะไร ที่เปลี่ยน — ให้อธิบาย ทำไม การเปลี่ยนแปลงนี้จึงจำเป็น และ ทำไม นี่ถึงเป็นวิธีที่ดีในการแก้ปัญหา ควรชี้ให้เห็นส่วนของการเปลี่ยนแปลงที่ต้องการความสนใจเป็นพิเศษในการ review ด้วย ถ้ามี ขึ้นอยู่กับ CONTRIBUTING.md และลักษณะของการเปลี่ยนแปลง reviewer อาจคาดหวังข้อมูลเพิ่มเติม เช่น trade-off ที่เลือก หรือวิธีทดสอบการเปลี่ยนแปลง
เราแนะนำให้ contribute กลับไปที่ upstream project แทนที่จะ “fork” โปรเจกต์ อย่างน้อยก็เป็นแนวทางแรก การ fork (ถ้า license อนุญาต) ควรสงวนไว้สำหรับกรณีที่ contribution ที่ต้องการทำอยู่นอกขอบเขตของโปรเจกต์ต้นฉบับ ถ้า fork ให้ acknowledge โปรเจกต์ต้นฉบับด้วย!
AI ทำให้การสร้างโค้ดและ PR ที่ดูน่าเชื่อถือได้อย่างรวดเร็วเป็นเรื่องง่ายมาก แต่นั่นไม่ได้ยกเว้นเราจากการเข้าใจสิ่งที่กำลัง contribute การส่งโค้ดที่สร้างโดย AI ที่ไม่สามารถอธิบายได้จะสร้างภาระให้ maintainer ในการ review และอาจต้อง maintain โค้ดที่แม้แต่ผู้เขียนเองก็ไม่เข้าใจ การใช้ AI เพื่อช่วยระบุปัญหาและสร้าง fix/feature นั้นไม่มีปัญหา ตราบใดที่ยังทำ due diligence ในการขัดเกลาให้เป็น contribution ที่คุ้มค่า แทนที่จะผลักงานนั้นไปให้ maintainer (ที่งานล้นมืออยู่แล้ว)
จำไว้ว่าสำหรับ maintainer การ accept PR หมายถึงการรับผิดชอบในระยะยาว พวกเขาจะต้อง maintain โค้ดนี้หลังจากที่ contributor ไปทำอย่างอื่นแล้ว และอาจปฏิเสธการเปลี่ยนแปลงที่มีเจตนาดีแต่ไม่สอดคล้องกับทิศทางของโปรเจกต์ เพิ่มความซับซ้อนที่ไม่ต้องการ maintain หรือกรณีที่ความจำเป็นไม่ได้ถูก document อย่างเพียงพอ เป็นหน้าที่ของ เรา ในฐานะ contributor ที่จะต้องสร้าง case ว่าทำไมการ accept contribution นี้จึงคุ้มค่ากับภาระการ maintain
เมื่อได้รับ feedback บน PR ให้จำไว้ว่าโค้ดของเราไม่ใช่ตัวเรา! Reviewer พยายามทำให้โค้ดดีขึ้น ไม่ได้วิพากษ์เราเป็นการส่วนตัว ถามคำถามเพื่อความชัดเจนถ้าไม่เห็นด้วย — เราอาจได้เรียนรู้สิ่งใหม่ หรือบางทีพวกเขาเองอาจได้เรียนรู้
การ Review
อาจคิดว่า code review เป็นสิ่งที่นักพัฒนาอาวุโสทำ แต่จริง ๆ แล้วจะถูกขอให้ review โค้ดเร็วกว่าที่คิด และมุมมองของเราก็มีคุณค่า สายตาใหม่จับสิ่งที่นักพัฒนาที่มีประสบการณ์มองข้ามได้ และคำถามจากคนที่ไม่คุ้นเคยกับโค้ดมักเผยให้เห็นสมมติฐานที่ควรถูก document หรือทำให้ง่ายขึ้น
การ review ยังเป็นหนึ่งในวิธีที่เร็วที่สุดในการเรียนรู้ จะได้เห็นว่าคนอื่นแก้ปัญหายังไง เก็บ pattern และ idiom ต่าง ๆ และพัฒนาสัญชาตญาณว่าอะไรทำให้โค้ดอ่านง่าย นอกเหนือจากการเติบโตส่วนตัว การ review จับ bug ก่อนที่จะไปถึง production กระจายความรู้ในทีม และปรับปรุงคุณภาพโค้ดผ่านการทำงานร่วมกัน มันไม่ใช่แค่ bureaucratic overhead
Code review ที่ดีเป็นทักษะที่ต้องฝึกฝนเรื่อย ๆ แต่มีเคล็ดลับบางอย่างที่ช่วยให้ดีขึ้นได้เร็วมาก:
- Review โค้ด ไม่ใช่ตัวบุคคล: “This function is confusing” vs “You wrote confusing code.”
- ให้ comment ที่ actionable: “Can you replace these globals with a config dataclass” ง่ายต่อการ address กว่า “Don’t use globals here”
- ถามคำถามแทนการสั่ง: “What happens if X is null here?” เชิญชวนให้เกิดการสนทนาได้ดีกว่า “Handle the null case.”
- อธิบาย “why”: “Consider using a constant here” มีประโยชน์น้อยกว่า “Consider using a constant here so we can easily adjust the timeout based on environment.”
- แยกแยะ blocking issue กับ suggestion: บอกให้ชัดว่าอะไรต้องเปลี่ยน กับอะไรเป็นเรื่องของ preference
- ชื่นชมสิ่งที่ดี: การชี้ให้เห็น solution ที่ฉลาดหรือ implementation ที่สะอาดเป็นกำลังใจ และช่วยให้ผู้เขียนรู้ว่าควรทำอะไรต่อไป
- รู้ว่าเมื่อไหร่ควรหยุด: Contributor มีเวลาและความอดทนจำกัด และไม่ใช่ทุก nit จะคุ้มค่าที่จะจัดการ ให้เน้นเรื่องใหญ่ และพิจารณาจัดการ nit เล็ก ๆ ด้วยตัวเองหลังจากนั้น
เครื่องมือ AI สามารถจับปัญหาบางอย่างได้ แต่ไม่สามารถทดแทนการ review โดยมนุษย์ มันพลาด context ไม่เข้าใจ product requirement และอาจแนะนำสิ่งที่ผิดอย่างมั่นใจ คุ้มค่าที่จะใช้เป็น first pass แต่ไม่ใช่สิ่งทดแทน thoughtful human review
การให้ความรู้ (Education)
เวลาที่ไม่ได้เขียนโค้ดส่วนใหญ่ของ engineer ถูกใช้ไปกับการถามหรือตอบคำถาม อาจจะทั้งสองอย่างผสมกัน ไม่ว่าจะระหว่างการทำงานร่วมกัน ในบทสนทนากับเพื่อนร่วมงาน หรือขณะพยายามเรียนรู้ การถามคำถามที่ดีเป็นทักษะที่ทำให้เราเรียนรู้จากใครก็ได้ ไม่ใช่แค่จากคนที่อธิบายเก่ง Julia Evans มีบล็อกโพสต์ที่ดีมากเกี่ยวกับ “How to ask good questions” และ “How to get useful answers to your questions” ที่ควรอ่าน
คำแนะนำที่มีคุณค่าเป็นพิเศษ:
- บอกความเข้าใจของตัวเองก่อน: พูดว่าคิดว่ารู้อะไร แล้วถามว่า “ถูกไหม?” ซึ่งช่วยให้ผู้ตอบระบุช่องว่างความรู้ที่แท้จริงได้
- ถามคำถาม yes/no: “X เป็นจริงไหม?” ป้องกันคำอธิบายที่ออกนอกเรื่อง และมักกระตุ้นให้เกิดการอธิบายเพิ่มเติมที่มีประโยชน์อยู่ดี
- ถามให้เฉพาะเจาะจง: “SQL join ทำงานยังไง?” กว้างเกินไป “LEFT JOIN รวม row ที่ตารางขวาไม่มีข้อมูลตรงกันด้วยไหม?” ตอบได้
- ยอมรับเมื่อไม่เข้าใจ: ขัดจังหวะเพื่อถามเกี่ยวกับคำศัพท์ที่ไม่คุ้นเคย สิ่งนี้สะท้อนความมั่นใจ ไม่ใช่จุดอ่อน ในทำนองเดียวกัน ถ้าพวกเขาถามคำถามที่เราไม่รู้คำตอบ ดีที่สุดคือพูดว่า “ไม่รู้” และอาจตามด้วย “แต่คิดว่า …” หรือแม้แต่ “แต่หาคำตอบให้ได้”
- อย่ายอมรับคำตอบที่ไม่สมบูรณ์: ถาม follow-up ต่อไปจนกว่าจะเข้าใจจริง ๆ
- ทำ research ก่อนบ้าง: การตรวจสอบเบื้องต้นช่วยให้ถามคำถามได้ตรงประเด็นมากขึ้น (แต่คำถามแบบ casual ระหว่างเพื่อนร่วมงานก็ไม่เป็นไร)
จำไว้ว่า: คำถามที่ถูกสร้างอย่างดีเป็นประโยชน์ต่อทั้งชุมชน มันเผยให้เห็นสมมติฐานที่ซ่อนอยู่ซึ่งคนอื่นก็ต้องเข้าใจเช่นกัน
สังเกตว่าคำแนะนำเหล่านี้ใช้ได้เช่นกันเมื่อสื่อสารกับ LLM!
มารยาทการใช้ AI
ด้วยการใช้ LLM และ AI ที่เพิ่มมากขึ้นใน software engineering บรรทัดฐานทางสังคมและวิชาชีพเกี่ยวกับเรื่องนี้ยังอยู่ในช่วงเปลี่ยนแปลง เราได้พูดถึงข้อพิจารณาเชิงปฏิบัติหลายอย่างในบท agentic coding แล้ว แต่ยังมีด้าน “ที่นุ่มนวลกว่า” ของการใช้งานที่ควรพูดถึง
อย่างแรกคือเมื่อ AI มีส่วนช่วยอย่างมีนัยสำคัญในงาน ให้เปิดเผย สิ่งนี้ไม่เกี่ยวกับความอาย — แต่เกี่ยวกับความซื่อสัตย์ การตั้ง expectation ที่เหมาะสม และการทำให้งานที่ได้ถูก review ในระดับที่เหมาะสม นอกจากนี้ยังคุ้มค่าที่จะเปิดเผยว่าใช้ AI กับ ส่วนไหน — มีความแตกต่างอย่างมีนัยสำคัญระหว่าง “ทั้งหมดนี้เป็น vibecoded” กับ “เขียน backup tool นี้เอง แล้วใช้ LLM ช่วย style web frontend” ตัวอย่างเช่น เราใช้ LLM ช่วยเขียน lecture note เหล่านี้บางส่วน รวมถึงการ proofread, brainstorm, และสร้าง first draft ของ code snippet และแบบฝึกหัด
ควรปฏิบัติตามบรรทัดฐานของทีมและโปรเจกต์ที่กำลัง contribute ด้วย บางทีมมีนโยบายเข้มงวดเกี่ยวกับการใช้ AI มากกว่าทีมอื่น (เช่น ด้วยเหตุผลด้าน compliance หรือ data residency) และไม่ควรพลาดไปละเมิดโดยไม่ตั้งใจ การเปิดเผยเกี่ยวกับการใช้งานช่วยป้องกันข้อผิดพลาดที่อาจมีค่าใช้จ่ายสูง
ถ้ามีเป้าหมายที่จะเรียนรู้เป็นส่วนหนึ่งของงานที่ทำอยู่ ให้จำไว้ว่าถ้าปล่อยให้ AI ทำงานทั้งหมดหรือส่วนใหญ่แทน อาจเป็นการเอาชนะตัวเอง เพราะจะเรียนรู้เรื่อง prompting (และอาจจะเรื่องการ review output ของ AI) มากกว่าตัวงานเอง โดยเฉพาะเมื่อกำลังเรียนรู้ สิ่งสำคัญอาจอยู่ที่การเดินทาง ไม่ใช่จุดหมายปลายทาง ดังนั้นการใช้ AI เพื่อ “ได้คำตอบเร็ว ๆ” จึงเป็น anti-goal
ข้อกังวลที่เกี่ยวข้องเกิดขึ้นในการสัมภาษณ์งานและสถานการณ์การประเมินอื่น ๆ สิ่งเหล่านี้มักมีจุดประสงค์เพื่อประเมิน ทักษะและความสามารถ ของเราโดยเฉพาะ ไม่ใช่ของ LLM บริษัทจำนวนมากขึ้นอนุญาตให้ใช้ LLM และเครื่องมือ AI ในการสัมภาษณ์ได้ ตราบใดที่ให้พวกเขาสังเกตการใช้งานเป็นส่วนหนึ่งของการสัมภาษณ์ (นั่นคือ พวกเขากำลังประเมินทักษะในการใช้เครื่องมือเหล่านั้นด้วย!) แต่บริษัทเหล่านั้นยังเป็นส่วนน้อย ถ้าไม่แน่ใจว่าการช่วยเหลือจาก AI อยู่ในขอบเขตของงานใดงานหนึ่งหรือไม่ ให้ถาม!
ไม่ต้องพูดก็รู้ว่าถ้าสถานการณ์การประเมินระบุชัดเจนว่าห้ามใช้เครื่องมือภายนอก ห้ามใช้ LLM ฯลฯ ก็ไม่ควรใช้ การพยายามทำแบบนั้นอย่างลับ ๆ โดยหวังไม่ให้ถูกจับได้ จะ กลับมาทำร้ายเราในที่สุด
แบบฝึกหัด
-
เปิดดู source code ของโปรเจกต์ที่มีชื่อเสียง (เช่น Redis หรือ curl) หาตัวอย่างของ comment ประเภทต่าง ๆ ที่กล่าวถึงในบทนี้: TODO ที่มีประโยชน์, reference ไปยัง external documentation, comment “why not” ที่อธิบายแนวทางที่เลี่ยง, หรือบทเรียนที่ได้มาอย่างยากลำบาก ถ้า comment นั้นไม่มี จะสูญเสียอะไรไป?
-
เลือกโปรเจกต์ open-source ที่สนใจแล้วดูประวัติ commit ล่าสุด (
git log) หา commit ที่มี message ดีซึ่งอธิบาย ทำไม ถึงทำการเปลี่ยนแปลง และอีกอันที่มี message อ่อนซึ่งอธิบายแค่ อะไร ที่เปลี่ยน สำหรับอันที่อ่อน ดู diff (git show <hash>) แล้วลองเขียน commit message ที่ดีกว่าโดยใช้โครงสร้าง Problem → Solution → Implications สังเกตว่าต้องใช้ความพยายามมากแค่ไหนในการรวบรวม context ที่จำเป็นหลังจากเวลาผ่านไป! -
เปรียบเทียบ README ของโปรเจกต์ GitHub สามโปรเจกต์ที่มี 1000+ ดาว ทุกอันมีประโยชน์เท่ากันไหม? มองหาสิ่งที่รู้สึกว่าเป็น noise เป็นส่วนใหญ่ เพื่อเป็นบทเรียนสำหรับ README ที่จะเขียนเองในอนาคต
-
หา open issue ในโปรเจกต์ที่ใช้อยู่ (ลองดู label “good first issue” หรือ “help wanted” ถ้ามี) ประเมิน issue นั้นตามเกณฑ์จากบทเรียน: มันดูเหมือนเคารพเวลาของ maintainer และมีข้อมูลที่จำเป็นทั้งหมดในการ debug หรือไม่ หรือคาดว่า maintainer อาจต้องถาม-ตอบกับผู้ส่งหลายรอบเพื่อไปถึงปัญหาที่แท้จริง?
-
นึกถึง bug ที่เคยพบในซอฟต์แวร์ที่ใช้ (หรือหาจาก issue tracker) ฝึกสร้าง minimal reproducible example: ตัดทุกอย่างที่ไม่เกี่ยวข้องกับ bug ออกจนเหลือ case ที่เล็กที่สุดที่ยังแสดงปัญหาได้ เขียนสรุปว่าเอาอะไรออกและทำไม
-
หา pull request ที่ถูก merge แล้วในโปรเจกต์ที่คุ้นเคย ซึ่งมี review comment ที่เป็นสาระ (ไม่ใช่แค่ “LGTM”) อ่าน review ทั้งหมด comment ทุกอันมีประสิทธิภาพเท่ากันไหม? ถ้าเราเป็นผู้เขียน PR จะรู้สึกอย่างไรกับการได้รับ comment ทั้งหมดนั้น?
-
ไปที่ Stack Overflow แล้วหาคำถามในเทคโนโลยีที่รู้จัก ที่มีคำตอบที่ได้ upvote สูง จากนั้นหาคำถามที่ถูกปิดหรือได้ downvote มาก เปรียบเทียบกับคำแนะนำจากบทเรียน คาดเดาได้ไหมว่าคำถามไหนจะได้คำตอบที่ดีกว่า?
Licensed under CC BY-NC-SA.