1 คะแนน โดย GN⁺ 2023-11-16 | 1 ความคิดเห็น | แชร์ทาง WhatsApp

การย้ายเงื่อนไขในฟังก์ชันขึ้นไป

  • หากมีเงื่อนไข if อยู่ภายในฟังก์ชัน ให้พิจารณาย้ายมันไปยังฝั่งผู้เรียก (caller)
  • แทนที่ฟังก์ชันจะตรวจสอบเงื่อนไขเบื้องต้นภายในแล้ว "ไม่ทำอะไรเลย" เมื่อเงื่อนไขไม่เป็นจริง ควรให้ผู้เรียกเป็นผู้ตรวจสอบเงื่อนไขเบื้องต้น เพื่อให้มั่นใจผ่านระบบชนิดข้อมูลได้ว่าเงื่อนไขนั้นเป็นจริงแล้ว
  • โดยเฉพาะเมื่อ "ย้ายขึ้น" เงื่อนไขเบื้องต้น อาจช่วยลดงานตรวจสอบโดยรวมได้ และนี่คือหนึ่งในแรงจูงใจของกฎข้อนี้

การย้ายลูปลงไป

  • เป็นกฎที่มาจากแนวคิดแบบ data-oriented โดยนำแนวคิดเรื่อง 'batch' ของอ็อบเจ็กต์เข้ามา และถือให้งานแบบ batch เป็นกรณีพื้นฐาน ส่วนเวอร์ชัน scalar เป็นเพียงกรณีพิเศษของเวอร์ชัน batch
  • ประโยชน์หลักคือการเพิ่มประสิทธิภาพ โดยสามารถกระจายต้นทุนเริ่มต้นและมีความยืดหยุ่นต่อ ลำดับการประมวลผล
  • ตัวอย่างเช่น การคูณพหุนามด้วย FFT อาจประเมินพหุนามหลายจุดพร้อมกันได้เร็วกว่า การประเมินแยกทีละจุด

ความเห็นของ GN⁺

  • ประเด็นสำคัญที่สุดของบทความนี้คือกฎการเขียนโปรแกรมสองข้อเพื่อปรับปรุงประสิทธิภาพและความชัดเจนของโค้ดในการพัฒนาซอฟต์แวร์ ได้แก่ 'การย้ายเงื่อนไขขึ้น' และ 'การย้ายลูปลง'
  • กฎเหล่านี้ช่วยเพิ่มความอ่านง่ายของโค้ด ปรับแต่งประสิทธิภาพ และลดโอกาสเกิดบั๊ก
  • บทความนี้น่าสนใจและมีประโยชน์สำหรับนักพัฒนาจำนวนมาก เพราะให้มุมมองต่อการจัดการความซับซ้อนของวิศวกรรมซอฟต์แวร์และการเขียนโค้ดอย่างมีประสิทธิภาพ

1 ความคิดเห็น

 
GN⁺ 2023-11-16
ความคิดเห็นจาก Hacker News
  • มีความเห็นว่าน่าประหลาดใจกับกระแสต่อต้านคำแนะนำเกี่ยวกับการออกแบบแบบ data-oriented ผู้ใช้ฟอรัมส่วนใหญ่มักเขียนเว็บแอปพลิเคชัน จึงอาจมองว่าคำแนะนำนี้ไม่มีความหมาย หากในงานประจำวันคุณไม่จำเป็นต้องคิดเรื่อง instruction cache ก็ควรละเลยคำแนะนำนี้ไป การดู "Typical C++ Bullshit" ของ Mike Acton อาจช่วยให้เข้าใจความสำคัญของคำแนะนำนี้ได้
  • มีความเห็นว่าโปรแกรมเมอร์ใส่ใจกับการทำให้โค้ดดูสวยงามใน "หน่วยเล็ก ๆ" แต่กลับไม่ใส่ใจกับการออกแบบโค้ดเบสโดยรวมอย่างเพียงพอ ถ้าฟังก์ชันตั้งชื่อได้ดี มีอินเทอร์เฟซที่ดี มีจุดประสงค์ชัดเจน มีเอกสารกำกับเหมาะสม และไม่ได้ใช้ผลข้างเคียงมากเกินไป ก็ไม่ควรกังวลมากนักว่าภายในฟังก์ชันจะดูรกหรือมีการจัดวาง if กับ for อย่างไร
  • มีความเห็นจากคนที่เริ่มเขียนโปรแกรมในสายวิทยาศาสตร์ว่าการเพิ่มประสิทธิภาพเล็ก ๆ น้อย ๆ นั้นสำคัญ หากใช้ลำดับของ for loop ผิด เวลารันซิมูเลชันอาจลดจาก 1 สัปดาห์เหลือ 1 ชั่วโมงได้ คนที่มีพื้นฐานแบบนี้จึงมักจัดลำดับของ for และ if ให้เหมาะสมโดยสัญชาตญาณ
  • มีความเห็นว่าเมื่อมี "container" อยู่ ก็ควรเขียนฟังก์ชันให้กับ "Thing" ระดับโดเมนที่อยู่ใน container นั้น แทนที่จะเขียนฟังก์ชันสำหรับตัว container เอง วิธีนี้ทำให้โค้ดยืดหยุ่นมากขึ้น และแยกความสนใจของโดเมนหลักออกจากความสนใจของแอปพลิเคชันได้ชัดเจนขึ้น
  • มีข้อเสียของการย้าย "if" ขึ้นไปไว้ด้านบน คือทำให้มองไม่เห็น precondition และ postcondition ของฟังก์ชันได้โดยตรงจากตัวนิยามฟังก์ชัน ในโปรเจ็กต์ขนาดใหญ่ ฟังก์ชันเหล่านี้อาจถูกนำกลับมาใช้ซ้ำนอกบริบทที่ตั้งใจไว้และก่อให้เกิดบั๊กได้ การใช้ contract framework อาจเป็นทางออกหนึ่ง แต่ก็ทำให้ต้องเขียนเงื่อนไขซ้ำทั้งใน contract และในโค้ด
  • ในตัวอย่างที่ใช้ภาษา Rust มีความเห็นว่าระบบชนิดข้อมูลที่แข็งแรงของ Rust ช่วยป้องกันการเขียน defensive programming ที่จำเป็นในภาษาอื่น การที่โปรแกรมเมอร์ C ไม่ตรวจสอบความถูกต้องของพอยน์เตอร์ที่ส่งเข้าไปในฟังก์ชันและทำให้เกิดการอ้างอิง NULL นั้นไม่ใช่สิ่งที่พึงประสงค์ บาง if ควรอยู่ด้านบนของฟังก์ชัน ไม่ใช่ด้านล่าง และข้อผิดพลาดควรถูกส่งต่ออย่างเหมาะสม
  • มีความเห็นว่าบทความดูเหมือนจะพาไปสู่ตัวอย่างโค้ดเฉพาะเจาะจง แต่สุดท้ายกลับไม่เป็นเช่นนั้น จึงมีการยกตัวอย่างอื่นแทนตัวอย่างโค้ดที่คาดไว้
  • หากไม่มีบริบทที่เหมาะสม คำแนะนำนี้อาจดูแปลกและอาจถึงขั้นเป็นคำแนะนำที่ไม่ดีได้ ทั้ง for loop และ if statement ต่างก็เป็นการดำเนินการควบคุมการไหลของโปรแกรมเหมือนกัน ดังนั้นบางข้ออ้างในบทความจึงดูไม่มีความหมาย ข้ออ้างด้านประสิทธิภาพดูแข็งแรงที่สุด แต่สำหรับคำแนะนำทั่วไปแล้วควรถูกพิจารณาเป็นเรื่องท้าย ๆ
  • มีความเห็นว่าไม่แน่ใจว่ากฎทั่วไปแบบนี้จะนำไปใช้กับโค้ดจริงได้หรือไม่ หลายครั้งกฎลักษณะนี้ถูกมองเป็น dogma ที่ผิด และโปรแกรมเมอร์อายุน้อยอาจรับไปใช้อย่างผิด ๆ จนเขียนโค้ดแย่ลงได้ โดยเฉพาะเมื่อเงื่อนไขมักพึ่งพา walrus จึงไม่สามารถย้าย if ขึ้นไปด้านบนได้
  • มีความเห็นว่าการย้าย precondition if ไปให้ผู้เรียกตรวจสอบเองเป็นความคิดที่แย่มาก แม้ในกรณีพิเศษอาจเป็นความคิดที่ดี แต่โดยทั่วไปแล้วไม่ควรทำ ในไลบรารีควรตรวจสอบ precondition ที่ขอบเขตภายนอก เพื่อให้การทำงานภายในดำเนินต่อไปได้โดยไม่ต้องพึ่งสมมติฐานภายใน การพึ่งให้ผู้เรียกเป็นฝ่ายตรวจสอบทำให้จุดประสงค์นั้นหมดความหมาย