การอภิปรายล่าสุดเกี่ยวกับการค้นหาบั๊กผ่านการอ่านโค้ดอย่างรอบคอบได้จุดประกายการถกเถียงอย่างเข้มข้นในหมู่นักพัฒนาซอฟต์แวร์เกี่ยวกับแนวทางที่มีประสิทธิภาพที่สุดในการป้องกันบั๊ก โดยเฉพาะเมื่อต้องจัดการกับระบบซอฟต์แวร์ขนาดใหญ่
การสนทนานี้มีจุดศูนย์กลางอยู่ที่ว่าการอ่านโค้ดด้วยตนเองสามารถเป็นวิธีการที่เชื่อถือได้ในการค้นพบบั๊กหรือไม่ หรือแนวทางอัตโนมัติเช่น type systems และ property testing จะเป็นประโยชน์มากกว่าสำหรับสถานการณ์การพัฒนาในโลกแห่งความเป็นจริง
ขนาดสร้างความต้องการที่แตกต่าง
ชุมชนนักพัฒนาแบ่งฝ่ายกันอย่างชัดเจนเกี่ยวกับว่าเทคนิคการอ่านโค้ดจะใช้ได้ผลเกินกว่าโปรเจกต์เล็กๆ หรือไม่ ในขณะที่นักพัฒนาบางคนรายงานความสำเร็จในการค้นหาบั๊กในการใช้งานที่มี 500 บรรทัด แต่คนอื่นๆ โต้แย้งว่าแนวทางนี้กลายเป็นเรื่องที่ไม่สามารถทำได้จริงกับระบบกระจายที่มีล้านบรรทัดซึ่งสะสม technical debt มา 15 ปี ความตึงเครียดหลักอยู่ที่ระหว่างวิสัยทัศน์ในอุดมคติของโค้ดที่สร้างขึ้นอย่างรอบคอบและอ่านได้ง่าย กับความเป็นจริงที่ยุ่งเหยิงของระบบเก่าที่มี abstraction หลายชั้น
นักพัฒนาที่มีประสบการณ์หลายคนชี้ให้เห็นว่า codebase ขนาดใหญ่ต้องการกลยุทธ์ที่แตกต่างไปโดยสิ้นเชิง พวกเขาเน้นย้ำว่า type systems, invariant checks และ automated property testing กลายเป็นเครื่องมือที่จำเป็นเมื่อถึงขีดจำกัดทางปัญญาของมนุษย์
เครื่องมือป้องกันบั๊กแบบอัตโนมัติ
- ระบบประเภทข้อมูลสำหรับตรวจจับข้อผิดพลาดพื้นฐาน
- การตรวจสอบค่าคงที่และการยืนยัน
- การทดสอบคุณสมบัติแบบอัตโนมัติ
- การตรวจสอบโค้ดที่เน้นไปที่สัญญา
- การเขียนโปรแกรมแบบป้องกันพร้อมการตรวจจับข้อผิดพลาดล่วงหน้า
- นโยบายไม่มีการติดตาม stack ในบันทึกการผลิต
Mental Models เทียบกับเครื่องมือ
ส่วนสำคัญของการอภิปรายมุ่งเน้นไปที่การสร้าง mental models ของการทำงานของโค้ดเทียบกับการพึ่งพาเครื่องมืออัตโนมัติ ผู้สนับสนุนการอ่านโค้ดโต้แย้งว่าการทำความเข้าใจพฤติกรรมของโปรแกรมผ่านการวิเคราะห์อย่างรอบคอบช่วยให้นักพัฒนาเขียนโค้ดที่ดีกว่าตั้งแต่เริ่มต้น พวกเขาแนะนำให้ติดตาม control flow จาก main functions และติดตามการเปลี่ยนแปลง state ข้าม data structures หลัก
อย่างไรก็ตาม ผู้ที่สงสัยตั้งคำถามว่าแนวทางนี้จะขยายขนาดได้เกินกว่าฟังก์ชันแต่ละตัวหรือโมดูลเล็กๆ หรือไม่ พวกเขาสังเกตว่าแม้จะอ่านอย่างรอบคอบแล้ว การโต้ตอบที่ซับซ้อนระหว่างคอมโพเนนต์ของระบบมักจะซ่อนบั๊กที่ร้ายแรงที่สุด
เทคนิคการอ่านโค้ด
- ติดตามการไหลของการควบคุมเริ่มต้นจาก main() หรือจุดเริ่มต้นของระบบ
- ติดตามการเปลี่ยนแปลงสถานะในโครงสร้างข้อมูลหลัก
- มุ่งเน้นไปที่รูปแบบที่มักเกิดข้อผิดพลาด (เช่น allocators ที่มี try statements ใน Zig )
- ใช้ git blame/log เพื่อทำความเข้าใจบริบททางประวัติศาสตร์
- อ่านระบบย่อยทั้งหมดระหว่างการ code review ไม่ใช่แค่ diffs เท่านั้น
กลยุทธ์ Defensive Programming
ชุมชนยังได้เน้นแนวทางประนีประนอมที่ใช้ได้จริงซึ่งผสมผสานความเข้าใจของมนุษย์กับการป้องกันอัตโนมัติ นักพัฒนาบางคนสนับสนุนเทคนิค defensive programming เช่น การตรวจจับข้อผิดพลาดตั้งแต่เนื่องๆ พร้อมกับการ logging ที่เหมาะสม รวมกับนโยบายไม่ยอมรับ stack traces ใน production logs
เขียนโค้ดแบบป้องกัน แต่อย่าใช้เวลามากเกินไปกับการจัดการเงื่อนไขข้อผิดพลาด ยกเลิกให้เร็วที่สุดเท่าที่จะทำได้ เก็บข้อมูลเพียงพอที่จะหาตำแหน่งข้อผิดพลาดได้ในภายหลัง
คนอื่นๆ เน้นความสำคัญของการทำให้ invalid states เป็นไปไม่ได้ที่จะแสดงตั้งแต่แรก แทนที่จะพยายามจับข้อผิดพลาดหลังจากที่เกิดขึ้นแล้ว
การตรวจสอบความเป็นจริงในอุตสาหกรรม
การถกเถียงนี้เผยให้เห็นความตึงเครียดพื้นฐานระหว่างแนวปฏิบัติการพัฒนาในอุดมคติกับข้อจำกัดในอุตสาหกรรม ในขณะที่การอ่านโค้ดอย่างรอบคอบและแนวทางที่เน้นการป้องกันอาจผลิตซอฟต์แวร์ที่มีคุณภาพสูงกว่า แต่แรงกดดันทางธุรกิจมักจะชอบการพัฒนาแบบรวดเร็วและการแก้ไขบั๊กหลังเกิดเหตุ
นักพัฒนาหลายคนสังเกตว่าแนวทางที่ประสบความสำเร็จมากที่สุดน่าจะผสมผสานกลยุทธ์หลายอย่าง: สถาปัตยกรรมโค้ดที่อ่านได้สำหรับการพัฒนาใหม่, การทดสอบอัตโนมัติสำหรับการป้องกัน regression และการอ่านโค้ดเชิงกลยุทธ์สำหรับคอมโพเนนต์ระบบที่สำคัญ ข้อมูลเชิงลึกสำคัญที่เกิดขึ้นจากการอภิปรายคือเทคนิคต่างๆ ทำงานได้ดีกว่าในขนาดและขั้นตอนที่แตกต่างกันของวงจรชีวิตโปรเจกต์
การถกเถียงที่ดำเนินต่อไปนี้สะท้อนคำถามที่กว้างขึ้นเกี่ยวกับแนวปฏิบัติ software engineering ขณะที่ระบบเติบโตซับซ้อนมากขึ้นและทีมพัฒนาเผชิญแรงกดดันที่เพิ่มขึ้นในการส่งมอบฟีเจอร์อย่างรวดเร็วในขณะที่รักษาความน่าเชื่อถือของระบบ
อ้างอิง: Look Out For Bugs