- กฎข้อ 1: ไม่มีทางคาดเดาได้ว่าโปรแกรมจะใช้เวลาไปกับส่วนไหน คอขวดมักเกิดขึ้นในจุดที่คาดไม่ถึง ดังนั้น อย่าพยายามปรับปรุงความเร็วจนกว่าจะพิสูจน์ได้จริงว่าเป็นคอขวด
- กฎข้อ 2: ต้องวัดผลก่อน การปรับแต่งความเร็วควรทำหลังจากวัดผลเท่านั้น และควรพิจารณาการทำ optimization เฉพาะเมื่อโค้ดบางส่วนครอบงำเวลาทำงานทั้งหมด
- กฎข้อ 3: อัลกอริทึมที่ซับซ้อนจะช้าเมื่อ n ยังเล็ก อัลกอริทึมที่ซับซ้อนมีค่าคงที่สูง ดังนั้นถ้า n ไม่ได้โตบ่อย ๆ ก็ควรใช้วิธีที่เรียบง่ายกว่า แม้ n จะโตขึ้น ก็ควรใช้กฎข้อ 2 ก่อน
- กฎข้อ 4: อัลกอริทึมที่ซับซ้อนมีบั๊กมากและนำไปใช้งานได้ยาก การใช้อัลกอริทึมที่เรียบง่ายและโครงสร้างข้อมูลที่เรียบง่ายจึงเป็นทางเลือกที่พึงประสงค์
- กฎข้อ 5: ข้อมูลคือหัวใจสำคัญ หากเลือกโครงสร้างข้อมูลที่ถูกต้องและจัดระเบียบได้ดี อัลกอริทึมก็แทบจะปรากฏออกมาเองอย่างชัดเจน แกนกลางของการเขียนโปรแกรมไม่ใช่อัลกอริทึม แต่คือโครงสร้างข้อมูล
ปรัชญาและคำกล่าวที่เกี่ยวข้อง
- กฎข้อ 1 และ 2 มีความหมายเดียวกับคำกล่าวของ Tony Hoare ที่ว่า “การทำ optimization ตั้งแต่เนิ่น ๆ คือรากเหง้าของความชั่วร้ายทั้งปวง”
- Ken Thompson ตีความกฎข้อ 3 และ 4 ใหม่เป็น “ถ้ายังไม่แน่ใจ ให้ใช้วิธีง่าย ๆ (Brute Force)”
- กฎข้อ 3 และ 4 เป็นตัวอย่างของปรัชญาการออกแบบแบบ KISS(Keep It Simple, Stupid)
- กฎข้อ 5 เป็นสิ่งที่ Fred Brooks ได้กล่าวไว้แล้วใน 『The Mythical Man-Month』 โดย
มักถูกสรุปว่า “เขียนโค้ดที่เรียบง่ายโดยใช้อ็อบเจ็กต์ที่ชาญฉลาด”
1 ความคิดเห็น
ความคิดเห็นจาก Hacker News
ทำให้นึกถึงบรรยายของ Jonathan Blow
เขาเข้าหาจากมุมมองของประสิทธิภาพในการทำงาน ช่วงแรกของการพัฒนา Braid เขาทำแทบทุกอย่างด้วยอาร์เรย์แบบเรียบง่าย และค่อยแก้เมื่อเกิดคอขวดเท่านั้น
ประโยคที่น่าประทับใจคือ “สิ่งที่สำคัญกว่าความเร็วหรือหน่วยความจำ คือเวลาชีวิตของคนที่ต้องใช้เพื่อสร้างโปรแกรมหนึ่งขึ้นมา”
ถ้ายอมรับ Rule 1 อย่างจริงจัง Rule 3~5 ก็จะตามมาเองอย่างเป็นธรรมชาติ
เมื่อยอมรับสมมติฐานว่าคาดเดาคอขวดไม่ได้ การเขียนโค้ดแบบเรียบง่ายและวัดผลจึงเป็นกลยุทธ์เดียวที่สมเหตุสมผล
ในทางปฏิบัติ สิ่งที่ล้มเหลวบ่อยที่สุดไม่ใช่การทำ optimization เร็วเกินไป แต่คือการทำ abstraction เร็วเกินไป สร้างชั้นความซับซ้อนเพื่อความยืดหยุ่นที่ยังไม่จำเป็น และสุดท้ายกลับเพิ่มภาระการดูแลรักษา
ผมเคยมีประสบการณ์ต้องทำฟีเจอร์ค้นหาชุดข้อมูลตอนตี 2 ในยุค 90
ตอนนั้นเหนื่อยมากเลยทำแบบการค้นหาเชิงเส้นไปก่อนแล้วค่อยคิดว่าจะกลับมาแก้ทีหลัง แต่ในความเป็นจริงมันต่างกันแค่ 6 วินาทีจากการทดสอบที่กินเวลา 4 ชั่วโมง
สุดท้ายก็แก้อยู่ดี แต่แทบไม่มีความต่างที่มีนัยสำคัญ
เห็นด้วยกับ Rule 5 แบบเต็มร้อย
ยิ่งปัญหายากเท่าไร ก็ยิ่งแก้ได้ด้วยการปรับปรุงโครงสร้างข้อมูลและ API แบบวนซ้ำ เมื่อโครงสร้างลงตัวแล้ว control flow จะเป็นธรรมชาติเอง
LLM ไม่ค่อยเก่งกับการคิดเชิงโครงสร้างแบบนี้ มันเสนอ control flow ที่ซับซ้อนได้ดี แต่ไม่ค่อยถนัดการออกแบบโครงสร้างข้อมูลที่นำมาประกอบต่อกันได้
ผมมาจากสายวิศวกรรมไฟฟ้า (E.E.) และช่วงต้นอาชีพก็แทบไม่มีปัญหาใหญ่เพราะRule 3
แต่ภายหลังเมื่อย้ายไปทำระบบขนาดใหญ่ n ก็โตขึ้น และความซับซ้อนก็กลายเป็นสิ่งสำคัญจริง ๆ
‘big iron’ ในยุคที่ Rob Pike พูดถึงนั้น คล้ายกับสภาพแวดล้อมแบบ embeddedในปัจจุบัน
ถ้าอัลกอริทึมสองแบบมีความยากในการ implement พอ ๆ กัน ผมจะเลือกตัวที่เร็วกว่าเมื่อ input ใหญ่
บทความที่เกี่ยวข้อง: Less Than Quadratic
หลายครั้งผู้คนเลือกวิธี O(n²) ที่ง่ายเกินไปแล้วต้องเจอกับการระเบิดตอนรันจริง
ผมคิดว่ากฎของ Pike ดีกว่าสุภาษิตเดิม ๆ
ประโยคอย่าง “optimization ที่เร็วเกินไปคือรากเหง้าของความชั่วร้ายทั้งมวล” พอขาดบริบทแล้วก็มักถูกเข้าใจผิดได้ง่าย
เวอร์ชันของ Pike ชัดเจนและเอาไปใช้ผิดได้ยากกว่า
เคยมีคำสรุปเก่าว่า “Rule 5 คือ ‘ให้โค้ดโง่ ๆ ใช้อ็อบเจ็กต์ฉลาด ๆ’” แต่
ในยุค object-oriented มันกลับบิดเบี้ยวกลายเป็นความเชื่อผิด ๆ ที่ซ่อนความซับซ้อน
หลังจากดูแล codebase เดิมมานานกว่าสิบปี ผมซึมซับกฎของ Pike เข้าไปเต็มที่แล้ว
การยึดหลักKISS/DRY และรักษาเทคโนโลยีที่พิสูจน์แล้วแทนการวิ่งตามของใหม่ เป็นสิ่งที่มั่นคงกว่าในระยะยาว
จริง ๆ แล้วเอกสารหลักการพัฒนาของทีมเราก็แทบเหมือนกับกฎของ Pikeทุกประการ
ในยุค C++ ช่วงต้นทศวรรษ 1990 ผมเคยเปลี่ยนจากdoubly linked listมาใช้การขยายอาร์เรย์ธรรมดาแทน
ไม่เพียงแต่บั๊กหายไป แต่ยังเร็วขึ้นอีกด้วย
ผมได้เรียนรู้ว่าการทำ operation ที่แพงให้น้อยครั้งลงเป็นกลยุทธ์ที่ดี
เมื่อนำกฎ “อย่าปรับแต่งโดยไม่วัดผล” ไปเทียบกับ Latency Numbers Every Programmer Should Know ของ Jeff Dean ก็ชวนให้คิด
Dean บอกว่าเราสามารถคาดเดาประสิทธิภาพได้จากความรู้ล่วงหน้า
สุดท้ายสองมุมมองนี้ก็อยู่ร่วมกันได้ — ในขั้นออกแบบให้เลือกโครงสร้างที่ดูเร็วโดยสัญชาตญาณ และหลัง implement แล้วค่อยปรับละเอียดโดยอิงการวัดผล
Rule 1 และ 2 เป็นกฎแบบสัมบูรณ์เฉพาะตอนรับมือกับปัญหาใหม่เท่านั้น
ถ้าสร้างระบบในโดเมนเดิมซ้ำ ๆ ก็จะสามารถคาดเดาจุดคอขวดล่วงหน้าได้
นักพัฒนาที่มีประสบการณ์มักมีเซนส์ด้านประสิทธิภาพคร่าว ๆ ตั้งแต่ก่อนเริ่มออกแบบ