2 คะแนน โดย GN⁺ 2023-11-02 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • บทความเกี่ยวกับกฎการเขียนโปรแกรม 5 ข้อของ Rob Pike ในปี 1989
  • กฎข้อ 1: อย่าคาดเดาว่าโปรแกรมจะใช้เวลาส่วนใหญ่อยู่ที่ไหน คอขวดอาจเกิดขึ้นอย่างไม่คาดคิด หลีกเลี่ยงการแฮ็กเพื่อความเร็วจนกว่าจะพิสูจน์ได้ว่ามีคอขวดจริง
  • กฎข้อ 2: วัดผลเสมอก่อนจะปรับแต่งเพื่อความเร็ว ทำการเพิ่มประสิทธิภาพเฉพาะเมื่อบางส่วนของโค้ดมีผลกระทบอย่างมีนัยสำคัญต่อส่วนที่เหลือ
  • กฎข้อ 3: เมื่อ n มีขนาดเล็ก อัลกอริทึมที่ซับซ้อนจะช้า ซึ่งเป็นกรณีส่วนใหญ่ ใช้อัลกอริทึมที่ซับซ้อนก็ต่อเมื่อ n มักมีขนาดใหญ่บ่อย ๆ และแม้ในกรณีนั้นก็ให้ใช้กฎข้อ 2 ก่อน
  • กฎข้อ 4: อัลกอริทึมและโครงสร้างข้อมูลที่เรียบง่ายเป็นสิ่งที่พึงปรารถนา เพราะมีแนวโน้มเกิดบั๊กน้อยกว่าสิ่งที่ซับซ้อนและนำไปใช้งานได้ง่ายกว่า
  • กฎข้อ 5: โครงสร้างข้อมูลที่ถูกต้องเป็นสิ่งชี้ขาดในการเขียนโปรแกรม หากจัดโครงสร้างข้อมูลได้ดี อัลกอริทึมก็จะปรากฏชัดขึ้นเอง
  • กฎข้อ 1 และ 2 ของ Pike สะท้อนคติพจน์ของ Tony Hoare ที่ว่า "การเพิ่มประสิทธิภาพก่อนเวลาอันควรคือรากเหง้าของความชั่วร้ายทั้งปวง"
  • Ken Thompson ได้เรียบเรียงกฎข้อ 3 และ 4 ของ Pike ใหม่เป็น "เมื่อไม่แน่ใจ จงใช้พลังดุจ brute force"
  • กฎข้อ 3 และ 4 เป็นการนำปรัชญาการออกแบบ KISS (Keep It Simple, Stupid) ไปใช้จริง
  • กฎข้อ 5 สอดคล้องกับคำกล่าวใน 'The Mythical Man-Month' ของ Fred Brooks ซึ่งมักย่อกันว่า "เขียนโค้ดที่โง่โดยใช้อ็อบเจ็กต์ที่ฉลาด"

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

 
GN⁺ 2023-11-02
ความคิดเห็นบน Hacker News
  • เห็นด้วยอย่างยิ่งกับคำว่า “ข้อมูลเป็นตัวกำหนด
    นั่นทำให้การสัมภาษณ์แบบ LeetCode รู้สึกแปลกอยู่เสมอ ส่วนใหญ่มักโฟกัสที่อัลกอริทึม แต่ในการทำงานจริง หลายครั้งไม่ควรเริ่มด้วยแนวทางนั้นตั้งแต่ต้น และ โครงสร้างข้อมูล ควรเป็นแกนหลักมากกว่า
    แน่นอนว่า ถ้าไม่รู้อัลกอริทึมเลย ก็อาจไม่สังเกตเห็นกรณีพิเศษหรือช่วงที่จำเป็นต้องพึ่งอัลกอริทึมบางอย่างด้วยเหตุผลเฉพาะ แต่ถึงอย่างนั้น อัลกอริทึมสอนได้ค่อนข้างเร็ว ขณะที่การจับทางให้ได้ว่าควรใช้โครงสร้างข้อมูลแบบไหน ดูเหมือนเป็นเรื่องที่ผู้คนลำบากกว่ามาก

    • จากประสบการณ์ของผมก็เห็นด้วย พอในการสัมภาษณ์ข้ามจาก การตรวจอัลกอริทึม แบบ FizzBuzz ไปคุยเรื่องโครงสร้างข้อมูล สถาปัตยกรรม และการแมปกับโดเมนทันที ผมเห็นว่าผู้สัมภาษณ์ให้ความเคารพมากขึ้นอย่างชัดเจน
      จังหวะนั้นบรรยากาศจะเปลี่ยนเป็น “อ๋อ วิศวกรอาวุโสตัวจริงเข้ามาแล้ว” แล้วก็เปิดกว้างคุยปัญหาเชิงเทคนิคมากขึ้น และท่าทีที่พยายามให้พิสูจน์ว่า “เขียนโค้ดเป็นไหม” ก็ลดลง
      ในทางกลับกัน ทีมที่ทำให้เกิดการเปลี่ยนแปลงดี ๆ บรรลุไมล์สโตน และทำงานร่วมกันได้ยากที่สุด คือทีมที่ไม่มีคนจับโครงสร้างข้อมูลและ สถาปัตยกรรมโค้ด ได้อย่างเหมาะสม ดูเหมือนมีคนจำนวนมากขึ้นที่เคยชินกับแนวคิดว่าเฟรมเวิร์กจะทำให้หมดทุกอย่าง และถ้าไม่ได้ เดี๋ยวปลั๊กอินหรือมิดเดิลแวร์ที่ใครสักคนที่ฉลาดกว่าสร้างไว้ก็จะช่วยแก้ให้
      วิศวกรที่หลีกเลี่ยงโครงสร้างข้อมูลก็เหมือนยิงเท้าตัวเอง และเป็นการละทิ้งหนึ่งในเครื่องมือที่มีประโยชน์ที่สุด ข้อจำกัดจึงปรากฏให้เห็นเป็นประจำ
    • พอได้ช่วยหลานเตรียมแข่งเขียนโปรแกรมเชิงแข่งขัน ก็พบว่าส่วนใหญ่ของการแก้โจทย์คือการแปลงข้อมูลให้เป็น โครงสร้างข้อมูล ที่เหมาะสม
      ตัวอย่างเช่น โค้ดอาจถูกใช้มากในการหาเส้นทางที่ยาวที่สุดในกราฟมีทิศทางแบบไม่มีวัฏจักร (DAG) ที่มีน้ำหนัก แต่หัวใจอยู่ที่การตระหนักว่าโจทย์สามารถแทนเป็น DAG แบบมีน้ำหนัก ได้ ถ้ามองไม่เห็นจุดนั้น ก็ยังอาจแก้ได้ แต่คำตอบจะช้ากว่าและซับซ้อนกว่ามาก
    • จริง ๆ แล้วโจทย์ LeetCode ทั่วไปก็โฟกัสที่ โครงสร้างข้อมูล อยู่แล้ว เพราะผู้สมัครต้องมีรายการโครงสร้างข้อมูลในหัวไว้หยิบออกมาใช้เมื่อจับแพตเทิร์นระหว่างโจทย์กับวิธีแก้
      ผู้สัมภาษณ์จะไม่บอกก่อนว่าต้องใช้คิวลำดับความสำคัญ เมทริกซ์ประชิด หรือ trie ถ้าติดก็อาจให้คำใบ้ได้ แต่การชี้นำมากเกินไปยากที่จะมองเป็นสัญญาณการจ้างงานที่แข็งแรง
    • “ถ้าให้ดูแผนผังการไหลแต่ซ่อนตารางไว้ ผมจะยังสับสนต่อไป ถ้าให้ดูตาราง ก็ไม่จำเป็นต้องดูแผนผังการไหล มันจะชัดเจนขึ้นเอง”
    • ถ้าต้องเลือกอย่างใดอย่างหนึ่ง ผมคิดว่าก็ควรมีความเข้าใจคร่าว ๆ ของอีกอย่างด้วยไม่ใช่หรือ ถ้าไม่รู้เลยว่าจะเข้าถึงข้อมูลอย่างไร ก็ยากจะรู้ว่าควรใช้ โครงสร้างข้อมูล แบบไหน
  • เกี่ยวกับคำว่า “อัลกอริทึมเจ๋ง ๆ จะช้าเมื่อ n เล็ก และ n มักจะเล็ก” สิ่งที่ผมรู้สึกได้จากโปรเจกต์ล่าสุดคือ n ขนาดใหญ่ อาจใหญ่กว่าที่คิดมาก
    มักคิดได้ง่ายว่า “ต้องทำงาน 100,000 ครั้ง แบบนี้ต้อง optimize แน่” แต่คอมพิวเตอร์เร็วมาก และการคูณสัก 100,000 ครั้งโดยทั่วไปอาจเร็วเกินกว่าจะต้องคิดลึกก็ได้
    ไม่ได้หมายความว่าให้ไม่คิดอะไรเลย แต่บ่อยครั้งก็ยังน่าทึ่งว่าฮาร์ดแวร์สมัยใหม่เร็วอย่างบ้าคลั่งแค่ไหน

    • ผมเห็นด้วยกับประโยคนี้อย่างแรงได้ยาก อัลกอริทึมเวลาเชิงกำลังสอง เป็นชนิดที่มักกัดเราในจังหวะที่ไม่คาดคิด
      ผมเคยเห็นระบบล่มจากโค้ดที่เผลอกลายเป็นเวลาเชิงกำลังสอง และแม้ผู้ใช้ 99% จะใช้ n เล็กเสมอ ผู้ใช้บางส่วนก็อาจเจอ n ใหญ่บ่อย ๆ และต้องใช้แอปที่ช้ามาก
      ในกรณีส่วนใหญ่ ผมอยากเลือกอัลกอริทึมที่ดีกว่าเวลาเชิงกำลังสอง แม้มันจะช้ากว่าเล็กน้อยในกรณีทั่วไปและซับซ้อนขึ้นนิดหน่อยก็ตาม เส้นทางช้าที่พบบ่อยจะถูก optimize แต่เส้นทางช้าที่พบยาก นักพัฒนาอาจไม่เคยเหยียบเองจึงพลาดไป หรือไปแตกในระบบจริง
      แน่นอนว่าถ้าอัลกอริทึมซับซ้อนเกินไป ก็อาจเลือกการ implement แบบเวลาเชิงกำลังสองที่เรียบง่ายได้ แต่ค่าเริ่มต้นของผมคือพยายามตั้งไว้ให้ ต่ำกว่ากำลังสอง ถ้าเป็นไปได้ ผมเคยเขียนบทความที่เกี่ยวข้องไว้ด้วย: https://kevincox.ca/2023/05/09/less-than-quadratic/
    • ลำดับชั้นหน่วยความจำ ก็มีผลต่อเรื่องนี้ด้วย อัลกอริทึมเจ๋ง ๆ จำนวนมากมี locality ของการอ้างอิงที่แย่และเพิ่ม branch เข้ามา
      ดังนั้นเมื่อ 40 ปีก่อน ซึ่ง CPU ไม่ได้เร็วกว่าเมโมรีขนาดนั้น และฮาร์ดแวร์ผู้บริโภคไม่ได้ใส่ใจ branch prediction miss มากนัก คำพูดนี้อาจตรงกว่านี้
    • ในโจทย์สัมภาษณ์ LeetCode ผมเห็นอยู่เรื่อย ๆ ว่ามีการวนผ่านลิสต์ขนาด 100,000 รายการหลายรอบ มันอาจไม่ใช่วิธีที่เหมาะที่สุด แต่ถ้าวัดจากเวลาทำงานจริง การวน 100,000 รายการเทียบกับ การเรียกผ่านเครือข่าย ที่ทำต่อจากนั้นแล้วแทบไม่มีความหมาย
      ทุกครั้งที่สัมภาษณ์ ผู้จัดการฝ่ายจ้างงานต้องการแบบนั้น แต่ก็เกิดกรณีที่มือใหม่ LeetCode ซึ่งยังไม่เคยมีบาดแผลจากระบบ production ปฏิเสธการตัดสินใจนั้น
    • แหล่งอ้างอิงตัวแทนของหัวข้อนี้คือ Scalability! But at what COST?
      https://www.frankmcsherry.org/assets/COST.pdf
    • ตอนเริ่มงานเขียนโปรแกรมจริงจังครั้งแรกที่บริษัทเกมช่วงต้นทศวรรษ 2000 ผู้อำนวยการฝ่ายเทคนิคแนะนำว่า “ถ้าจำนวนรายการที่จัดการอยู่ประมาณ 10,000 ก็อย่า optimize”
      เมื่อคิดถึงการพัฒนาประสิทธิภาพของคอมพิวเตอร์ตลอด 20 ปีที่ผ่านมา การยกระดับเกณฑ์นั้นเป็น 100,000 ก็ดูค่อนข้างเหมาะสม
  • คำคมดังที่ว่า “การทำ optimization เร็วเกินไปคือรากเหง้าของความชั่วร้ายทั้งหมด” จริง ๆ แล้วไม่ได้มาจาก Tony Hoare แต่มาจาก Donald Knuth และมักถูกนำไปใช้แบบหลุดบริบทเพื่อคัดค้านการทำ optimization โดยรวม
    ประโยคเต็มคือ “เราควรลืมเรื่องประสิทธิภาพเล็ก ๆ น้อย ๆ เสีย กล่าวคือใน 97% ของกรณี การทำ optimization เร็วเกินไปคือรากเหง้าของความชั่วร้ายทั้งหมด แต่เราต้องไม่พลาดโอกาสใน 3% ที่สำคัญ”
    ใจความคือให้ใช้เวลา optimization ในจุดที่มีผลกระทบจริง

    • Knuth บอกว่าเป็นคำพูดของ Hoare ส่วน Hoare ก็บอกว่าเป็นคำพูดของ Knuth จึงเป็นเรื่องว่าจะเชื่อใคร คงดีที่สุดถ้ายกเครดิตให้ทั้งคู่
      ดูเหมือนเป็นไปได้ว่า Tony พูดก่อน แล้ว Knuth นำไปขัดเกลาและตีพิมพ์ การใส่คำอ้างอิงยาว ๆ ที่ให้บริบทที่จำเป็นไว้ด้วยกันเป็นเรื่องดีเสมอ
    • อีกเรื่องที่มักถูกลืมคือคำอ้างนี้มาจากช่วงปลาย ทศวรรษ 1970 ซึ่งก็เกือบ 50 ปีก่อนแล้ว
      การเขียนโปรแกรมในตอนนั้นต่างจากตอนนี้มาก “การทำ optimization เร็วเกินไป” ในยุคนั้นไม่ได้ใกล้เคียงกับ “ใช้ไลบรารียอดนิยมที่ขยายระบบได้ดีไปเลย” แต่ใกล้กับ “ใช้อัลกอริทึมจัดการบิตที่เข้าใจไม่ได้และทำงานได้เฉพาะบนฮาร์ดแวร์นี้เท่านั้น” มากกว่า
    • ไม่คิดว่าคำอ้างยาว ๆ นั้นให้บริบทเพิ่มเติมที่มีนัยสำคัญนัก ถ้าคุณวัดและหา 3% ที่สำคัญเจอแล้ว สถานะนั้นก็ไม่ใช่ “เร็วเกินไป” อีกต่อไป
      ความหมายนั้นรวมอยู่แล้วในประโยค “การทำ optimization เร็วเกินไปคือรากเหง้าของความชั่วร้ายทั้งหมด” และคำคมนี้ไม่ได้บอกว่า “การทำ optimization คือรากเหง้าของความชั่วร้ายทั้งหมด”
    • มีคนจำนวนมากเกินไปที่รับคำนี้เป็นหลักคำสอนจนไม่เรียนรู้ วิธีที่มีประสิทธิภาพ เสียเอง
      ในการสัมภาษณ์โครงสร้างข้อมูลและอัลกอริทึมของบริษัท ผมเห็นนักพัฒนา frontend นับไม่ถ้วนที่ตอบว่า bubble sort เป็นวิธีที่ดีที่สุด ไม่จำเป็นต้องอนุมานสด ๆ ให้ได้ แค่รู้จักอยู่บ้างและบอกตัวเลือกที่ดีให้เหมาะกับปัญหาก็พอ
      ถ้าใช้ชีวิตสุดโต่งกับคำว่า “อย่าทำ optimization เร็วเกินไป” จนไม่รู้แม้แต่วิธีที่มีประสิทธิภาพ แล้วจะรู้ได้อย่างไรว่าจุดไหนสำคัญ
    • ในบริบทนี้ ดูเหมือนไม่ได้ใช้ในความหมายคัดค้านการทำ optimization โดยทั่วไป
  • คำกล่าวว่า “โครงสร้างข้อมูลคือหัวใจสำคัญ” สำคัญเป็นสองเท่าในโลกของ ฐานข้อมูล
    คนที่ใช้ DB เป็นแค่ถังเก็บบิตโง่ ๆ หรือเป็นเพียงภาพสะท้อนแบบ 1:1 ของนิยามอ็อบเจ็กต์ มักจะแปลกใจเมื่อ DB รับเรื่องนั้นเป็นการส่วนตัวแล้วทำให้ประสิทธิภาพพัง
    ถ้าต้องได้เห็นสคีมา DB ที่ ORM สร้างขึ้นอีกครั้ง ก็คงเป็นการกลับมาพบกันที่เร็วเกินไปจริง ๆ

    • ผมมองว่า ORM ส่วนใหญ่สร้างสคีมาตามที่เราขอ การใช้ ORM ไม่ได้ทำให้เกิด การออกแบบฐานข้อมูล ที่แย่กว่าการทำด้วยมือโดยอัตโนมัติ
      ปัญหาอยู่ที่นักพัฒนาบางส่วนหรือจำนวนมากไม่รู้ SQL และไม่มีความรู้ด้าน DB ที่จำเป็นต่อการใช้ ORM
      ORM เป็น abstraction ที่รั่วพอสมควร ซึ่งต้องรู้ว่าข้างใต้มันมีอะไรอยู่ ถ้าเข้าใจเรื่องนั้น ก็สามารถสร้างสคีมาที่ใช้ได้ดีด้วย ORM ส่วนใหญ่ได้
    • ตรงนี้ยังเพิ่ม กฎของ Conway ได้ด้วย หมายถึง “องค์กรที่ออกแบบระบบจะสร้างแบบออกแบบที่จำลองโครงสร้างการสื่อสารขององค์กรนั้น”
      หากต้องการจัดโครงสร้างข้อมูลให้ดี และรักษาไว้เช่นนั้นแม้การออกแบบจะเปลี่ยนไป ต้องแยกข้อมูลกับโค้ดออกจากกันในระดับองค์กร
      การออกแบบสคีมา DB, use case และ mapping ระหว่างสิ่งเหล่านี้ควรถูกแยกจาก implementation ส่วนที่เหลือ และกลุ่มนี้ควรเขียนการตรวจสอบความถูกต้องสมบูรณ์ด้วย หากโครงสร้างองค์กรไม่แยกข้อมูลกับโค้ด ก็ยากที่จะแยกโค้ดกับข้อมูลออกจากกัน
    • stored procedure ชนะ
  • กฎเพิ่มเติมของผมคือ การสิ้นเปลืองประสิทธิภาพ เล็ก ๆ น้อย ๆ เมื่อสะสมกันแล้ว แม้แต่ละอย่างจะดูไม่มาก สุดท้ายก็ทำให้โปรแกรมช้าลงได้
    ถ้าไม่มีผลต่อความซับซ้อน ความอ่านง่าย ความบำรุงรักษาได้ หรือค่าใช้จ่ายในการ implement ก็ไม่ควรปล่อยประสิทธิภาพทิ้งไปเฉย ๆ หากเงื่อนไขอื่นแทบเท่ากัน การเลือกตัวเลือกที่ช้ากว่าจากสองตัวเลือกไม่ใช่เรื่องที่โอเค
    อีกอย่าง ถ้าสมมติว่า n มีค่าน้อย แทบอะไรก็ใช้ได้ แต่ถ้าเขียนโค้ดที่ทำงานดีเมื่อ n ต่ำกว่า 100 แต่พังเมื่อเกิน 10000 เช่น O(n²) ก็ควรกำหนด limit ไปเลย ถ้าสมมติฐานเรื่อง n เล็กไม่เป็นจริง การให้ error ดัง ๆ ยังดีกว่าโดนบิล AWS ระเบิดหรือโปรแกรมค้าง

    • ตรงนี้ใช้กฎข้อ 1 และ 2 ได้
  • แนวทางจำนวนมากเหล่านี้ สุดท้ายแล้วสรุปได้ว่าเป็นกลยุทธ์ป้องกัน การออกแบบเกินจำเป็น
    จากประสบการณ์ของผม การทำ optimization เร็วเกินไปเป็นหนึ่งในกับดักที่แพงที่สุด หากหลบเลี่ยงปัญหาที่อาจเกิดขึ้นเร็วเกินไป สมมติฐานนั้นจะไม่ถูกตรวจสอบ และทีมถัดไปต้องสร้างวิธีแก้ราคาแพงเพื่อจัดการความซับซ้อนที่ไม่จำเป็น
    แนวทางที่ผมได้เรียนรู้คือแบบนี้ การทำ optimization อาศัยการประเมิน และการประเมินในช่วงต้นมักผิดบ่อย
    นอกจากนี้ยังได้รู้ว่าการทำให้คนไม่สร้างโค้ดที่ซับซ้อนเกินไปนั้น การจัดการอีโก้ และความเข้าใจด้านจิตวิทยาค่อนข้างสำคัญ

    • มักพูดกันทำนองว่า “แก้ปัญหาที่คุณมีอยู่จริง อย่าแก้ปัญหาที่คุณคิดว่าคุณมี”
    • แนวคิดนี้ยังเชื่อมโยงกับ การระบุความสูญเปล่า ใน Lean และ Six Sigma ด้วย
      การผลิตเกินมักถูกมองว่าเป็นความสูญเปล่าที่แย่ที่สุด เพราะไม่เพียงสร้างสิ่งที่ไม่จำเป็น แต่ยังใช้ความพยายามที่ควรนำไปใช้กับสิ่งที่จำเป็นจริง ๆ ไปด้วย การออกแบบเกินจำเป็นก็คล้ายกัน
    • ถ้าลึกไปอีกขั้น การออกแบบเกินจำเป็นเกิดจากความคิดว่าอาจต้องใช้ความซับซ้อนนั้นในภายหลัง และเมื่อถึงตอนนั้นการขยายระบบจะยากหรือเสี่ยงกว่า
      เช่น แม้จะมีผู้ใช้แค่ 100 คน ก็เริ่มด้วย สถาปัตยกรรมไมโครเซอร์วิส เพราะคิดว่าวันหนึ่งถ้ามีผู้ใช้ 1 ล้านคน การออกแบบโมโนลิธใหม่จะยาก
      ดังนั้นต้องเริ่มจากจัดการก่อนว่าเหตุใดโค้ดจึงยืดหยุ่นน้อยลงเมื่อเวลาผ่านไป
    • การจัดการข้อผิดพลาดไม่ต้องทำให้ดูเท่ ควร ล้มเหลวตั้งแต่เนิ่น ๆ และอย่างเรียบง่าย
  • โดยรวมเป็นกฎที่ดี แต่ในทางปฏิบัติ ข้อ 1 ไม่ได้เป็นจริงตามนั้น
    ตอนเริ่มต้นจำเป็นต้องมี สมมติฐาน ว่าอะไรจะเป็นคอขวด ไม่ใช่ว่าจะทำ XYZ ให้เสร็จแล้วค่อยวัดว่าอะไรช้าและแก้ได้เสมอไป X, Y, Z อาจเชื่อมโยงกัน จนถ้าจะทำให้ Y เร็ว ก็ต้องสร้าง X และ Z ด้วยวิธีเฉพาะ และบางครั้งเราก็รู้อยู่แล้วว่า Y จะเป็นคอขวด
    แม้ภายหลังจะวัดจนรู้ว่าอะไรช้า ก็ยังต้องเดิมพันกับแนวทางที่จะทำให้มันเร็วขึ้น ยิ่งเป็นการเดิมพันที่มีข้อมูลรองรับมากเท่าไรก็ยิ่งดี
    โปรแกรมเมอร์ที่ดีจะวัดผล แต่เพราะคาดการณ์ได้ว่าอะไรจะช้า มีบั๊กเยอะ และใช้หน่วยความจำมาก จึงต้องวนซ้ำน้อยลง ถ้าพูดเป็นกฎว่าไม่สามารถคาดการณ์พฤติกรรมด้านประสิทธิภาพได้ ก็เท่ากับมองข้ามประสบการณ์และทักษะที่โปรแกรมเมอร์ที่ดีสั่งสมมา

    • กฎข้อ 1 เป็นกฎเหล็กสำหรับคนที่ไม่เชื่อ และเป็นแนวทางหลวม ๆ สำหรับคนที่เชื่อ
      เพราะกระบวนการทำตามข้อ 1 นั่นเองคือวิธีที่ดีที่สุดในการได้ประสบการณ์และพื้นฐานเชิงประจักษ์ที่จำเป็นต่อ สัญชาตญาณที่ดี ในการคาดเดาคอขวด
    • อัลกอริทึมที่ดูเหมือนจะช้า สามารถตรวจสอบได้ด้วย spike implementation โดยทั่วไปอัลกอริทึมที่ช้ามักเขียนและทดสอบได้ง่าย
      ถ้าคาดการณ์ความเร็วผิด ก็จะต้องแบกโค้ดที่ซับซ้อนโดยไม่จำเป็นไปตลอดอายุโครงการ
      ผู้คนมักคาดเดาความเร็วของอัลกอริทึมผิดอยู่บ่อย ๆ ถ้าคอมพิวเตอร์ใช้เวลา 99% ไปกับการดึง n จาก DB server ก็มีหลายครั้งที่ O(n) กับ O(n²) ดูเหมือนใช้เวลาจริงเท่ากัน
      บางครั้งอัลกอริทึมที่เขียนด้วย C ก็ช้ากว่าโค้ด Python ที่เทียบเท่ากันได้ เพราะ bytecode compiler อาจทำอะไรที่ฉลาดไว้
      เคยทำงานเร่งความเร็วโค้ด legacy มามาก โดยปกติมันง่ายกว่าที่คิดมาก และช้าด้วยเหตุผลที่คนเขียนเดิมอาจมองไม่เห็น ในความเป็นจริง หลายครั้งมันช้าเพราะ codebase ซับซ้อนเกินไปจนผู้เขียนเดิมไม่สามารถให้เหตุผลกับมันได้อีกแล้ว สำหรับผมมีตัวอย่างเฉพาะของสิ่งที่ “ช้าเกินไป” อยู่ จึงรันแล้วสังเกตจุดที่ช้าเพื่อดีบักได้ง่าย
    • ดูเหมือนไม่ใช่การตอบสนองต่อเนื้อหาต้นฉบับทั้งหมด ในนั้นบอกว่าอย่าใส่ speed hack จนกว่าจะรู้คอขวด ซึ่งต่างจากสถานการณ์ที่อธิบายมา
      ถ้ากำลังทำวิดีโอเกมที่มีวัตถุฟิสิกส์จำนวนมาก และจากประสบการณ์รู้แน่ชัดว่า collision detection จะเป็นปัญหาใหญ่ การออกแบบเกมและระบบโดยยึดสิ่งนั้นเป็นศูนย์กลางไม่ใช่ speed hack
      ถ้าเป็นงานที่รู้ว่าประสิทธิภาพจะเป็นประเด็นสำคัญ ก็แน่นอนว่าควรวัดผล ไม่ใช่วัดเพื่อดูว่ามันเป็นประเด็นหรือไม่ แต่เพื่อดูว่ากำลังรับมือกับประเด็นนั้นได้ดีแค่ไหน
    • อยากเห็นตัวอย่างที่เป็นรูปธรรม ในกรณีส่วนใหญ่สงสัยว่ามันต่างกันจริงหรือไม่
      ถ้าสร้างระบบใหม่ตาม requirement ใหม่ หลายครั้งก็น่าจะเริ่มทำไปก่อนได้ สร้าง ทดสอบและวัดผล ทิ้งหรือ refactor แล้ววนซ้ำ
      ถ้ายก Rust เป็นตัวอย่าง ก็เริ่มจากภาษาแบบร่างและ compiler ที่ทำด้วย OCaml แล้วค่อยวนซ้ำไปเรื่อย ๆ แม้จะรู้ว่าสักวันหนึ่งจะย้ายจาก OCaml ไปเป็น self-hosting ได้ ก็ไม่แน่ใจว่ามันทำให้ต่างไปมากหรือไม่
    • ถ้านักพัฒนาคาดการณ์ได้ดีขนาดนั้นว่าอะไรจะช้า อัตราความสำเร็จของ startup ที่ขับเคลื่อนโดยนักพัฒนาก็น่าจะเป็น 100% ไม่ใช่หรือ
      ถ้าไม่มีผู้ใช้ ฟังก์ชันที่ใช้เวลาหลายชั่วโมงก็ยังเร็วพอ เมื่อเทียบกับฟังก์ชันที่ถ้า optimize แล้วจะเหลือมิลลิวินาที ไม่แน่ใจว่ามีใครพิสูจน์ได้หรือยังว่าสามารถคาดการณ์แบบนั้นได้อย่างแม่นยำ
  • ในฐานะข้อโต้แย้งต่อข้อ 5 อัลกอริทึมที่ซับซ้อน บนข้อมูลที่เรียบง่าย อาจให้ผลด้านประสิทธิภาพอย่างมาก ขจัดอุปสรรค และกลับทำให้เรียบง่ายขึ้นได้ด้วย
    ตัวอย่างเช่น ถ้าใช้ binary search บน array ที่เรียงลำดับแล้วแทน BinaryTree object การ merge ก็ง่ายขึ้นเป็น concat แล้ว sort ไม่มี pointer จึง serialize ได้ง่าย และในบางกรณีก็ไม่จำเป็นต้อง serialize เลย array สามารถอยู่บน disk หรือ memory หรืออยู่ทั้งสองที่ผ่าน mmap ได้ จัดการข้อมูลที่ใหญ่กว่า RAM ได้ และยังทำ cold start โดยชี้ไปที่ไฟล์หรือ mapping แล้วรันทันทีได้ด้วย มีคุณสมบัติ cache-oblivious ด้วย
    Huffman coding ก็เป็นตัวอย่าง ที่มหาวิทยาลัยมักเรียนเป็นอัลกอริทึมแบบ tree-based ที่มี complexity O(n log n) แต่ไม่รู้มาก่อนว่ามีวิธีสร้าง Huffman tree แบบ in-place array-based ได้ในเวลาเชิงเส้น
    แน่นอนว่า 99% ของเวลาเราสร้าง backend microservice และใช้ data structure ของ collection มาตรฐาน แต่ถ้าทำงานกับ big data ในที่ทำงาน ผมชอบประมวลผลบนเครื่องเดียวที่มีดิสก์ขนาดใหญ่ในเครื่อง มากกว่าจะนำตระกูล MapReduce ที่กำลังนิยมในตอนนั้นมาใช้

    • ผมไม่ถือว่า binary search เป็นอัลกอริทึมที่เจ๋ง อันที่เจ๋งคือฟังก์ชัน sort สมัยใหม่ และมันอาจมีบั๊กละเอียดอ่อนได้ จึงไม่ควรให้ developer ทั่วไปเขียนเอง แม้แต่ quicksort ก็มีหลุมพราง
      ถ้าเป็น Rob Pike เขาน่าจะบอกให้ profile โค้ดก่อน แล้วค่อยดูว่าโค้ดที่เจ๋งหรือ data structure ทางเลือกนั้นเร็วขึ้นจริงหรือไม่
    • นี่ดูไม่เหมือนข้อโต้แย้ง จากมุมมองคำแนะนำของ Pike “binary search บน array ที่เรียงลำดับแล้ว” กับ “BinaryTree object” เป็นเพียง implementation ต่างแบบของ data structure เดียวกัน
    • อย่าลืมว่า 99% ของเวลา developer คือทรัพยากรที่แพงที่สุด maintainability และความเร็วในการออกสู่ตลาดมักสำคัญกว่ามาก
  • ผมอ่านบทความนี้ครั้งแรกที่ cat-v เมื่อกว่า 10 ปีก่อน และมันส่งผลต่อวิธีที่ผมเข้าหาและคิดเรื่องการออกแบบกับความซับซ้อนอย่างลบไม่ออก
    http://doc.cat-v.org/bell_labs/pikestyle

  • ไม่เข้าใจว่าจากกฎดั้งเดิมที่ว่า “data structure คือหัวใจสำคัญ” กลายเป็น “เขียนโค้ดโง่ ๆ ที่ใช้ object อัจฉริยะ” ได้อย่างไร
    วลี “smart objects” แย่มาก และกฎดั้งเดิมแม้จะยาวกว่าก็ดีกว่ามาก

    • Rob Pike ก็น่าจะเห็นด้วยว่า “smart objects” เป็นวิธีคิดที่ผิด: https://commandcenter.blogspot.com/2012/06/less-is-exponenti...
    • การย้าย logic ที่ “smart” ขึ้นไปอยู่ระดับที่สูงกว่า จะทำให้เข้าใจ ทดสอบ และเปลี่ยนแปลงได้ง่ายกว่า ผมมองว่า smart objects ทำให้สร้างความสอดประสานกันได้ยากกว่ามาก
    • ให้มองว่าเป็นการเขียนโค้ดที่ไหลออกมาอย่างเป็นธรรมชาติจาก object ที่มีโครงสร้างดี