14 คะแนน โดย GN⁺ 2025-06-26 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • ในปี 1982 ทีมซอฟต์แวร์ Lisa ของ Apple ได้นำนโยบายติดตาม จำนวนบรรทัดของโค้ด รายสัปดาห์ของนักพัฒนาแต่ละคนมาใช้เพื่อเตรียมออกซอฟต์แวร์
  • Bill Atkinson เห็นว่าจำนวนบรรทัดของโค้ดเป็นตัวชี้วัดผลิตภาพซอฟต์แวร์ที่ผิดพลาด
  • เขาเขียน เอนจินคำนวณรีเจียนของ Quickdraw ขึ้นใหม่ทั้งหมด โดยลดโค้ดลงได้ราว 2,000 บรรทัด และเพิ่มประสิทธิภาพได้ 6 เท่า
  • Atkinson กรอกค่า -2000 ลงในแบบฟอร์มการจัดการที่ใช้รายงานจำนวนโค้ด
  • ในที่สุดผู้จัดการก็ไม่ขอให้ Bill ส่งแบบฟอร์มอีกต่อไป

ทีมซอฟต์แวร์ Lisa ในปี 1982 และนโยบายติดตามจำนวนบรรทัดของโค้ด

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

มุมมองของ Bill Atkinson ต่อเกณฑ์วัดผลิตภาพ

  • Bill Atkinson ผู้ออกแบบ Quickdraw และส่วนติดต่อผู้ใช้ มองว่าจำนวนบรรทัดของโค้ดไม่อาจใช้เป็นเกณฑ์วัดผลิตภาพซอฟต์แวร์ได้
  • เขาเน้นว่าเป้าหมายคือการทำให้โปรแกรม เล็กและเร็วที่สุดเท่าที่เป็นไปได้
  • เขาตระหนักว่าการวัดจำนวนบรรทัดของโค้ดอาจยิ่งส่งเสริมให้เกิด โค้ดที่รกและไม่มีประสิทธิภาพ

การรีแฟกเตอร์และปรับแต่งเอนจินรีเจียนของ Quickdraw

  • Atkinson เพิ่งเขียน เอนจินคำนวณรีเจียนของ Quickdraw ใหม่ทั้งหมดด้วยอัลกอริทึมที่เรียบง่ายและใช้งานได้ทั่วไปมากขึ้น
  • ผลจากการปรับแต่งทำให้ ความเร็วของการทำงานกับรีเจียนเพิ่มขึ้นได้ถึง 6 เท่า
  • ระหว่างกระบวนการนี้ โค้ดราว 2,000 บรรทัด ก็ลดลงไปโดยธรรมชาติ

รายงานว่าเขียนโค้ด -2000 บรรทัด และปฏิกิริยาของผู้จัดการ

  • ระหว่างกรอกแบบฟอร์มผู้บริหารในสัปดาห์แรก Atkinson เขียนค่า -2000 ลงในช่องจำนวนบรรทัดของโค้ด
  • ไม่แน่ชัดว่าผู้จัดการตอบสนองต่อเลขนี้อย่างไร
  • หลายสัปดาห์ต่อมา Bill ถูกบอกว่าไม่ต้องส่งแบบฟอร์มอีก และเขาก็ยินดีอย่างมาก

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

 
GN⁺ 2025-06-26
ความคิดเห็นบน Hacker News
  • คอมมิตที่ผมจำได้ว่าเป็นคอมมิตที่ดีที่สุดคือการลบโค้ดไปราว 60,000 บรรทัด แล้วแทนที่ “เซิร์ฟเวอร์” ทั้งก้อนที่เคยเก็บสถานะทั้งหมดไว้ในหน่วยความจำ ด้วยลอจิกเบา ๆ ประมาณ 5,000 บรรทัด

    • ผมมองว่านี่เป็นความสำเร็จด้านอัลกอริทึม เพราะโค้ดนี้เบาพอที่จะผนวกรวมเข้ากับบริการอื่นได้อย่างเป็นธรรมชาติ และไม่ต้องพึ่งสถานะในหน่วยความจำอีกต่อไป
    • ตอนนั้นค้นพบว่าสามารถแก้ปัญหา guided subgraph isomorphism สำหรับต้นไม้แบบเฉพาะได้ และด้วยเหตุนี้จึงสามารถสร้างกราฟผลลัพธ์ (ต้นไม้) โดยเดินกราฟ directed acyclic graph ทั่วไปเพียงรอบเดียว พร้อมติดตามเฉพาะเส้นทางจากรากที่เริ่มต้นด้วยสแตกขนาดเล็ก
    • คอมมิต “-60,000 บรรทัด” เป็นช่วงเวลาที่ลืมไม่ลงจริง ๆ และหลังจากนั้นผมก็ยังไม่เคยทำอะไรที่น่าประทับใจเชิงอัลกอริทึมได้เท่านี้อีกเลย
      • ผมเป็นโปรแกรมเมอร์งานอดิเรกที่เขียนสคริปต์ในงานค่อนข้างเยอะ และก็รู้สึกว่าตัวเองพอเก่งในบางด้านของการเขียนโปรแกรม แต่พอได้ยินเรื่องแบบนี้ทีไรก็ทำให้กลับมาถ่อมตัวอีกครั้งว่าโลกที่ผมยังไม่รู้นั้นกว้างใหญ่มาก และต่อให้เรียนไปทั้งชีวิตก็คงยังไม่พอ
      • อยากฟังบริบทเพิ่มเติมมากกว่านี้ เทคนิคการเปลี่ยนโปรแกรมที่เก็บสถานะให้กลายเป็นแบบไร้สถานะฟังดูเหมือนเวทมนตร์ เลยอยากเรียนรู้จริง ๆ
      • ผมเป็นนักคณิตศาสตร์ที่มีพื้นฐานด้านทฤษฎีกราฟและอัลกอริทึม เลยสงสัยว่าทักษะแบบนี้จะนำไปใช้กับงานจริงประเภทนี้ได้ไหม ถ้าพอจะแชร์รายละเอียดเพิ่มได้ก็อยากถามเชิงลึกหน่อย
      • ผมคิดว่าความจริงที่ว่ากราฟเป้าหมายเป็นต้นไม้อาจไม่ได้สำคัญขนาดนั้น ประเด็นสำคัญน่าจะอยู่ที่ส่วนที่เป็น “guided” ต่างหากที่ทำให้เดินเพียงรอบเดียวได้
        • สมมติว่าเริ่มจากโหนดหนึ่งในกราฟต้นฉบับ และถ้ามี isomorphism อยู่จริง รากของต้นไม้เป้าหมายก็ต้องตรงกับโหนดนั้นด้วย
        • มองปัญหาเป็นการเดินกราฟต้นฉบับตามแพตเทิร์นของต้นไม้เป้าหมาย ถ้าไม่ตรงก็ false ถ้าตรงทั้งหมดก็ true แบบนี้ ต่อให้ไม่ใช่ต้นไม้ ถ้ากำหนดจุดเริ่มต้นให้ชัด วิธีนี้ก็น่าจะใช้ได้กับ subgraph แบบอื่นด้วย
      • มุกคือ บางทีคนเขียนโปรแกรมประเภทนี้นี่แหละอาจเป็นต้นตอของโจทย์สัมภาษณ์เขียนโค้ดแนว “จงกลับด้าน binary tree” ที่เราเห็นกันทุกวันนี้
        • ผมสนใจทฤษฎีกราฟนะ แต่ศัพท์มันยากเกิน เลยอยากได้คำอธิบายแบบง่าย ๆ สำหรับนักพัฒนาทั่วไป
  • ตอนเรียนมหาวิทยาลัย ผมเคยทำงานให้บริษัทที่มีนโยบายผู้บริหารว่าเด็กจบใหม่สามารถเขียนโค้ดดี ๆ ได้ สุดท้ายมันก็พิสูจน์ตัวเองว่าเป็นกรณีล้มเหลวที่ไม่ได้ถูกพิสูจน์ไว้ก่อน

    • ผมเจอว่าพอแก้บั๊กในโค้ดแล้ว บั๊กเดิมก็ยังกลับมาอีก เลยวิเคราะห์ดู พบว่าแทนที่จะเพิ่มพารามิเตอร์ให้ฟังก์ชันเดิม พวกเขากลับคัดลอกฟังก์ชันขึ้นมาแล้วแก้นิดหน่อย ผลคือผมได้ลบโค้ดไปมากกว่า 3/4 ของทั้งโค้ดเบส (Turbo Pascal หลายพันบรรทัด)
    • ลูกค้าของโปรเจกต์คือฝ่าย Energy และเป็นโปรแกรมจัดการสินค้าคงคลังวัสดุนิวเคลียร์ เป็นความทรงจำที่ทำให้นอนไม่หลับอยู่หลายคืน
      • มีการพูดประชดว่าข้อดีของการคัดลอกโค้ดเดิมคือ ไม่กระทบเสถียรภาพของโค้ดเก่า แถมยังช่วยดูแล metric เรื่อง “ผลงาน” ของผู้จัดการได้ด้วย และถ้าจะ revert ก็แค่ลบสำเนานั้นทิ้ง
      • ในทีมเราก็มีเพื่อนร่วมงานที่ทำโค้ดซ้ำแบบนี้บ่อย ๆ เหมือนกัน ผมคิดว่ามันเป็นนิสัยที่เกิดจากการต้องรีบทำผลลัพธ์ให้ทันคำขอเร่งด่วนหรือคนเสียงดัง ทั้งที่จริงต้นเหตุคือไม่ยอมลงทุนเวลาไปกับการ refactor ฟังก์ชันร่วมและเขียนเทสต์ให้เพียงพอ
      • นักพัฒนารับจ้างที่ผมเคยดูแลในอดีตก็มีนิสัยคล้ายกัน พอผมชี้ว่ามันอาจทำให้เกิดความสับสน เขากลับตอบว่า “ถึงตอนนั้นก็ใช้ Ctrl+F เอาสิ”
      • นี่เกิดขึ้นแถว Blacksburg หรือเปล่า
      • ประสบการณ์ผมก็คล้ายกัน ผมเคยทำงานที่บริษัทซึ่งดูแลพอร์ทัลที่แทบเหมือนกันในหลายประเทศแถบเอเชียตะวันออกเฉียงใต้ โดยซอร์สของแต่ละพอร์ทัลถูกเก็บไว้ใน Git repository แยกกัน และทุกครั้งที่มีฟีเจอร์หรือบั๊กฟิกซ์ที่ต้องใช้ร่วมกัน เราต้องย้อนพอร์ตด้วยมือไปยังสำเนาซอร์สโค้ดทุกชุด เป็นประสบการณ์ที่ชวนอึ้งมาก
        • ผมถามว่า “เอามาไว้ใน repo เดียว แล้วใช้ feature flag สำหรับการปรับแต่งรายพอร์ทัลไม่ได้เหรอ” แต่ก็ถูกปฏิเสธว่าทำไม่ได้
        • สุดท้ายในสองสามเดือนผมก็รวมโค้ดของ 4-5 พอร์ทัลให้เหลือ repository เดียว ใส่ feature flag และอัปเกรดเฟรมเวิร์ก พร้อม deploy ได้อย่างราบรื่น ตอนนี้แก้บั๊กพร้อมกันทุกพอร์ทัลได้แล้ว ความรู้สึกเหมือนได้หลุดพ้นจากความทรมานของงานมือซ้ำ ๆ
  • ในประเด็นที่เกี่ยวกัน มีคนรวบรวมเธรดยอดนิยมใน Hacker News ที่พูดถึง “-2000 lines of code” ไว้ตามลิงก์

    • มีการชี้ว่าธรรมเนียมการนำโพสต์คลาสสิกเก่า ๆ กลับมา repost เป็นระยะนั้นเป็นประโยชน์ทั้งกับผู้ใช้ใหม่และผู้ใช้เก่า
      • ผมเป็นมนุษย์ง่าย ๆ ที่ถ้าเห็นคำว่า “-2k lines of code” ก็จะกดโหวตให้อัตโนมัติ
        • เวลาคุยกับลูกค้าที่อยากวัด productivity ด้วย metric แกนเดียว ผมมักเล่าเรื่องของ Atkinson ให้ฟัง ตัวชี้วัด productivity ที่แท้จริงควรอิง utility และถ้าใครสามารถวัดสิ่งนี้ได้อย่างแท้จริง ก็น่าจะเข้าชิงรางวัลโนเบลเศรษฐศาสตร์ได้เลย
  • โปรเจกต์เว็บ UI ที่ผมรับช่วงต่อมีโค้ด 250,000 บรรทัด ยังไม่รวมฝั่งแบ็กเอนด์

    • นักพัฒนาคนก่อนฉลาดนะ แต่เพิ่งเขียน JS เป็นครั้งแรก เขาเก็บสถานะทั้งหมดไว้ใน custom attribute ของ DOM และโครงสร้างก็เต็มไปด้วย addEventListener จนผมถึงกับล้อว่า “ถ้าให้พระนักพรตมีหนังสือ JavaScript หนึ่งเล่มกับห้องขังเดี่ยว 10 ปี ก็คงได้โค้ดแบบนี้ออกมา”
    • ผมใช้เวลาหลายเดือนค่อย ๆ แปลงโครงสร้างเป็น web components และลบโค้ดไปได้ 50,000 บรรทัด จากนั้นก็เริ่มเขียนใหม่ทั้งชุด ตอนนี้ทำฟังก์ชันได้เท่าเดิมราว 80% แต่โค้ดทั้งหมดยังเหลือเพียง 17,000 บรรทัดแบบเบา ๆ (ไม่รวมไลบรารีอย่าง Vue/pinia)
    • อีกไม่นานผมคงจะลบได้เกิน 200,000 บรรทัดแล้ว และก็น่าจะไม่มีอะไรในชีวิตการทำงานที่จะเกินประสบการณ์นี้ได้อีก จนอยากเกษียณแล้ว
      • ผมก็เคยเจออะไรคล้ายกัน โดยคนเขียนต้นฉบับแทบจะยังเป็นจูเนียร์ แต่เป็นผู้ก่อตั้งบริษัทและมี productivity สูงมาก โครงสร้างนั้นเต็มไปด้วย code smell ทุกแบบเท่าที่จะจินตนาการได้ เพราะเขาพัฒนาโดยไม่เคยมีประสบการณ์ทำงานเป็นทีมหรือร่วมพัฒนากับโค้ดของคนอื่น
        • ฟังก์ชันเดียวหลายพันบรรทัด, switch/case/if/else/ternary ซ้อนกัน 10 ชั้น, SQL ปะปนกับ JS/HTML/HTML ที่ฝัง JS และเป็นโครงสร้างฟรอนต์เอนด์ยุค PHP/Dojo ที่ไม่มี automated test เลย
      • มีคนชี้ว่าคำอธิบายว่า “โค้ดเบาที่ทำได้แค่ 80% ของฟังก์ชัน” เองก็สะท้อนจุดบอดของการเปรียบเทียบแบบนี้ เพราะถ้ายังทำได้เพียงบางส่วนของฟังก์ชันทั้งหมด ก็ไม่จำเป็นต้องใช้จำนวนบรรทัดเท่าโค้ดเดิมอยู่แล้ว
  • มีการ์ตูน Dilbert ตอนหนึ่งเกี่ยวกับโครงสร้างรางวัลที่ผิดเพี้ยนไม่รู้จบ โดยหัวหน้าของ Dilbert สัญญาว่าจะให้รางวัลเป็นเงินทุกครั้งที่แก้บั๊กหนึ่งตัว แล้ว Wally ก็พูดว่า “วันนี้ฉันต้องเขียนโค้ดให้ได้สักหนึ่งมินิแวนแล้วล่ะ!”

    • สถานการณ์แบบนี้เรียกว่า “Perverse incentive” และมีคำอธิบายในลิงก์อ้างอิง
    • ผู้จัดการของผมก็เคยเอาการ์ตูนนี้ (ภาพ) ไปแปะไว้บนผนังห้องพักเบรกเหมือนกัน
    • มีคนถามแบบจริงจังว่า ‘มินิแวน’ หมายถึงอะไร
  • มีการแชร์กรณีจริงที่ลบโค้ดไป 64,000 บรรทัดใน repository dotnet/runtime

    • เป็นการเปลี่ยนโครงสร้างที่ต้องตัดสินใจเปลี่ยนแบบเด็ดขาดในครั้งเดียว โดยแทนที่การรองรับ C# + WinRT interop แบบ built-in เดิม ด้วยเครื่องมือ source generation ดูPR นี้
  • ทุกครั้งที่เห็นสถิติว่า LLM เพิ่ม productivity ของนักพัฒนาได้มากแค่ไหน ผมจะนึกถึงเรื่องคลาสสิกนี้เสมอ

    • มีคนแย้งว่า AI ก็เก่งเรื่องลบโค้ดเหมือนกัน พร้อมแชร์กรณีขำ ๆ ในคอมมูนิตี้ ของ Cursor ที่มีคนบอกว่า “AI ลบทุกอย่างในคอมผมไปหมดแล้ว”
    • ทุกวันนี้วลีอย่าง “X% ของโค้ดใหม่ของเราเขียนโดย AI!” กลายเป็น catchphrase ยอดนิยมของวงการไปแล้ว
    • ถ้ารวมต้นทุนการสร้างและบำรุงรักษาโรงไฟฟ้านิวเคลียร์แห่งใหม่เข้าไปด้วย ตัวเลข productivity ของนักพัฒนาก็คงดูเกินจริงแบบเสียดสีมากขึ้นไปอีก
  • ผมไม่ได้จบ CS และทำงานด้วยความรู้ภาคปฏิบัติที่เรียนรู้เอาระหว่างทำงาน

    • โปรเจกต์ของเรามีเป้าหมายเพื่อจัดรูป live object ใหม่ให้อยู่ในรูปแบบที่มนุษย์อ่านเข้าใจได้ง่าย
      • รูปแบบสุดท้ายต้องใช้ชนิดข้อมูลหลายแบบที่ซับซ้อนมาก ในขณะที่รูปแบบตั้งต้นค่อนข้างเรียบง่าย
      • ถ้ามี data node ที่คล้ายกัน เราต้องเทียบแล้วรวมมันเข้าด้วยกัน (พูดอีกแบบคือดึงออกเป็นเมธอดและหาพารามิเตอร์) เพื่อให้การอ่านง่ายขึ้น
        • ช่วงแรกเราแปลงไปเป็นชนิดข้อมูลปลายทางก่อนแล้วค่อยเทียบกัน ทำให้การผสมของชนิดข้อมูลระเบิดขึ้นมหาศาลจนแทบจัดการไม่ได้ และสุดท้ายซับซ้อนถึงขั้นที่วิศวกรไม่สามารถทำความเข้าใจโครงสร้างนี้ได้ตลอดหลายปี
      • ต่อมาผมได้รู้จักแนวทางที่ใช้ hashmap จึงเปลี่ยนมาเป็นโครงสร้าง 2 ขั้น โดยแยก node ที่มีกระดูกสันหลังเหมือนกันด้วยค่าแฮช แล้วค่อยเทียบและรวม ก่อนจะแปลงเป็นชนิดข้อมูลสุดท้าย
      • เมื่อเปลี่ยนจาก abstraction ที่ยึดตามสถานะของ type ไปเป็น abstraction ที่ยึดตามข้อมูลเป็นศูนย์กลาง ก็ทำให้แม้แต่ลำดับชั้นคลาสประหลาด ๆ ก็จัดการเป็นแอตทริบิวต์ธรรมดาได้ง่ายขึ้น
      • สรุปคือมันเป็นโครงสร้าง decompiler หลายชั้นที่งี่เง่า แต่ประสบการณ์นี้ทำให้ความเร็วในการประมวลผลและความสามารถในการอ่านดีขึ้นมาก ไม่มี silver bullet ที่ใช้ได้กับทุกสถานการณ์ แต่สำหรับเรา ‘type’ คือปัญหาหลัก และวิธีแก้นี้ช่วยโปรเจกต์เราได้มาก
  • ก่อนการประเมินผลงานปลายปี ผมไปดูสถิติของตัวเองใน monolithic repository ภายในบริษัท แล้วพบว่าถ้าวัดจากยอดสุทธิของโค้ด ผมกลายเป็นคนที่ติดลบ

    • สาเหตุมาจากการลบโค้ด API และโค้ดที่สร้างอัตโนมัติสำหรับ type รวมถึงการปลดระวาง API เวอร์ชันเก่า แต่ความรู้สึกที่ได้ไปทำงานทุกวันแล้วเหมือนมีหน้าที่แค่ลบโค้ด มันกลับสนุกอย่างประหลาด
  • นานมาแล้วผมเคยช็อกกับกรณี KPI ที่ย่ำแย่มากในโปรเจกต์ใหญ่แห่งหนึ่ง ที่ PL จะจดจำนวนบั๊กของนักพัฒนาแต่ละคนด้วยมือแบบออฟไลน์ (ทั้งบั๊กที่แก้และบั๊กที่ก่อ) แล้วเอาไปแปะบนกำแพง

    • ผมรอดมาได้เพราะอยู่โปรเจกต์ที่เกี่ยวข้องกันเฉย ๆ แต่มีเพื่อนร่วมงานคนหนึ่งได้แรงบันดาลใจจากเรื่องเล่าของผู้กำกับ Lars von Trier ที่เคยถูกตัดชื่อออกจาก “รายชื่อนักเขียน” ของระบบราชการ หลังจากตัดส่วนกางเขนออกจากธงเดนมาร์กแล้วเย็บใหม่ให้ดูเหมือนธงคอมมิวนิสต์สีแดง จากนั้นเพื่อนคนนั้นก็ตัดบรรทัดจำนวนบั๊กของตัวเองออกแล้วแปะกลับเข้าไปใหม่เพื่อประท้วงอย่างเปิดเผย วันถัดมารายชื่อนี้ก็หายไปตลอดกาล และยังเป็นความทรงจำอันล้ำค่าสำหรับผม
      • คำตอบสั้น ๆ ตรงไปตรงมาของเพื่อนคนนั้นว่า “เพราะผมไม่อยากอยู่ในลิสต์นี้ไง!” สรุปทุกอย่างได้ดีมาก
      • ยังมีคนแชร์ด้วยว่ามันยากจะจินตนาการว่าธงกับรายชื่อถูกจัดวางเป็นภาพอย่างไร