3 คะแนน โดย GN⁺ 2024-02-11 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • ในความเป็นจริงที่แม้แต่ฟังก์ชันเรียบง่ายก็ยังต้องใช้ dependency หลายพันรายการและโค้ดหลายสิบล้านบรรทัด ความ บวมพอง ของซอฟต์แวร์เองจึงกลายเป็นสาเหตุใหญ่ของช่องโหว่ด้านความปลอดภัย
  • ความปลอดภัยไม่ได้ขึ้นอยู่กับความหนาแน่นของบั๊กเท่านั้น แต่ยังขึ้นอยู่กับ ปริมาณโค้ดทั้งหมด ที่ผู้โจมตีเข้าถึงได้ด้วย และ attack surface ที่กว้างเกินจำเป็นอาจนำไปสู่การเจาะระบบจริงได้
  • ระบบนิเวศของ dependency อย่าง Electron JS, Node.js, Docker image, npm และ PyPI ทำให้ปริมาณและแหล่งที่มาของโค้ดที่นำไป deploy ไม่ชัดเจน และแม้แต่แอปเปิดประตูโรงรถก็อาจมีโค้ดที่ทำงานอยู่ มากกว่า 50 ล้านบรรทัด เข้ามาเกี่ยวข้อง
  • Rust, sanitizer และ fuzzer ช่วยยกระดับคุณภาพโค้ดได้ แต่ ความล้มเหลวด้านการออกแบบเชิงตรรกะ เช่น การรันโค้ดในเอกสารโดยอัตโนมัติ เป็นสิ่งที่ยากจะป้องกันได้ด้วยการกำจัดบั๊กเพียงอย่างเดียว
  • Trifecta ให้ฟังก์ชันแชร์รูปภาพด้วยโค้ดใหม่ 1,600 บรรทัด, dependency หลักราว 5 รายการ และขนาดรวม 3MB แสดงให้เห็นว่าสามารถสร้างซอฟต์แวร์สมัยใหม่ได้แม้มีโค้ดและ dependency จำกัด

สภาพที่ความปลอดภัยของซอฟต์แวร์ตกอยู่ในอันตราย

  • สถานะความปลอดภัยของซอฟต์แวร์ในช่วงหลัง แย่มาก
    • ในช่วงหนึ่งปีที่ผ่านมา เกิดเหตุละเมิดร้ายแรงกับซอฟต์แวร์มาตรฐานอุตสาหกรรม เช่น Ivanti, MOVEit, Outlook, Confluence, Barracuda Email Security Gateway, Citrix NetScaler ADC และ NetScaler Gateway
    • แม้แต่บริษัทที่มีทรัพยากรมากอย่าง Apple และ Google ก็ยังทำพลาดด้านความปลอดภัยจนทำให้ลูกค้าตกอยู่ในความเสี่ยง
  • เพราะเกิดการรับรู้ว่าซอฟต์แวร์อันตรายเกินไป คำแนะนำให้ไม่ต้องรันเอง แต่ฝากไว้กับ X as a service หรือคลาวด์จึงกลายเป็นเรื่องปกติ
  • สมมติฐานที่ว่าคลาวด์จะทำให้ซอฟต์แวร์ที่มีช่องโหว่น่าเชื่อถือได้ก็เริ่มสั่นคลอน
    • แพลตฟอร์มอีเมลของ Microsoft ถูกแฮ็ก รวมถึงอีเมลรัฐบาลที่เป็นความลับ
    • ยังมีความกังวลเกี่ยวกับความปลอดภัยของ Azure cloud
    • Okta ประสบเหตุละเมิดเป็นครั้งที่สองภายใน 2 ปี และหลังจากนั้นก็มีกรณีผู้ใช้ Okta ถูกแฮ็กตามมาอย่างน่าสงสัย
  • EU กำลังผลักดันกฎหมาย 3 ฉบับเพื่อจัดการความปลอดภัยของซอฟต์แวร์
    • NIS2: สำหรับบริการสำคัญ
    • Cyber Resilience Act: สำหรับซอฟต์แวร์เชิงพาณิชย์และอุปกรณ์อิเล็กทรอนิกส์แทบทั้งหมด
    • Product Liability Directive: ขยายขอบเขตความรับผิดให้ครอบคลุมซอฟต์แวร์

ช่องโหว่มาจากทั้งคุณภาพโค้ดและปริมาณโค้ด

  • ความปลอดภัยของซอฟต์แวร์ขึ้นอยู่กับ 2 แกน
    • ความหนาแน่นของปัญหาความปลอดภัย ในซอร์สโค้ด
    • ปริมาณโค้ด ที่แฮ็กเกอร์เข้าถึงได้
  • ยิ่งมีโค้ดมาก ความเสี่ยงก็ยิ่งสูงขึ้น
    • แม้ความหนาแน่นของบั๊กจะต่ำ แต่ในโค้ดหลายล้านบรรทัดก็ยังสามารถพบช่องโหว่ที่นำไปใช้โจมตีได้
  • กรณี iMessage แสดงให้เห็นว่าการขยาย attack surface สร้างปัญหาอย่างไร
    • แม้แต่ iMessage ที่ไม่ต้องการก็ถูกประมวลผลทันทีบน iPhone เพื่อสร้าง preview
    • Apple รองรับรูปแบบภาพหลากหลาย และแม้แต่ PDF ที่มีฟอนต์บีบอัดแปลก ๆ ก็ถูกนำมาประมวลผลด้วย
    • รูปแบบเก่าเหล่านั้นแทบจะมีภาษาโปรแกรมอยู่ในตัว และผู้โจมตีสามารถใช้มันสำรวจจุดอ่อนอื่น ๆ ของโทรศัพท์ได้
  • Apple สามารถลด attack surface ได้โดยจำกัด preview ให้เหลือรูปแบบภาพที่น้อยลงมาก หรือเป็นรูปแบบเดียวที่ “รู้ว่าดี”
  • EU Cyber Resilience Act ก็ระบุว่าผู้จำหน่ายต้อง ลด attack surface ให้เหลือน้อยที่สุด

โค้ดที่ดีกว่าอย่างเดียวไม่พอ

  • มีความเคลื่อนไหวเพื่อยกระดับคุณภาพโค้ดอยู่แล้ว
    • ภาษาที่ปลอดภัยต่อหน่วยความจำ อย่าง Rust
    • เครื่องมือเสริมความปลอดภัยอย่าง AddressSanitizer
    • fuzzer ที่แปลง input อัตโนมัติเพื่อค้นหาช่องโหว่และบั๊ก
  • แต่ปัญหาความปลอดภัยจำนวนมากเกิดจาก ตรรกะ ที่อยู่เบื้องล่าง มากกว่าบั๊กในตัวโค้ดเอง
  • ช่องโหว่อีเมลของ Barracuda เกิดจากไลบรารีภายนอกที่สแกนสเปรดชีต Excel เพื่อตรวจไวรัส แต่กลับรันโค้ดจริง ๆ
  • การตัดสินใจใส่ฟีเจอร์ที่รันโค้ดในเอกสารโดยอัตโนมัติ ไม่สามารถแก้ได้แม้จะกำจัดบั๊กทั้งหมดในโค้ดแล้วก็ตาม

อยู่ในสภาพที่ไม่รู้ว่ากำลัง deploy อะไร

  • ซอฟต์แวร์สมัยใหม่ใหญ่โตจนยากจะรู้ว่าจริง ๆ แล้วกำลัง deploy อะไรอยู่
  • Niklaus Wirth วิจารณ์ใน “A Plea for Lean Software” ปี 1995 ว่าซอฟต์แวร์ขยายใหญ่ถึงระดับเมกะไบต์
    • ระบบปฏิบัติการ Oberon ของเขามีขนาด 200KB รวม editor และ compiler แล้ว
    • ปัจจุบันบางโปรเจกต์มีแค่ไฟล์ตั้งค่าก็เกิน 200KB แล้ว
  • แอปทั่วไปในปัจจุบันอาจสร้างบน Electron JS
    • Electron JS รวม Chromium และ Node.js ไว้ด้วย
    • Node.js ทำให้เข้าถึงแพ็กเกจ JavaScript ได้หลายหมื่นรายการ
    • คาดว่าการใช้ Electron JS เพียงอย่างเดียวก็อาจนำโค้ดเข้ามาอย่างน้อย 50 ล้านบรรทัด เมื่อรวม dependency แล้ว
  • แอปดึงแพ็กเกจเสริมเข้ามาหลักร้อยถึงหลักพัน และ dependency เหล่านั้นก็ดึง dependency อื่น ๆ ต่ออีก
    • สิ่งที่ถูกรวมอยู่ใน build อย่างแน่ชัดอาจเปลี่ยนได้ทุกวัน
    • บางแพ็กเกจอาจเปิดเผยผู้ใช้ต่อผู้ลงโฆษณาหรือ data broker โดยค่าเริ่มต้น
  • แอปที่ควบคุมอุปกรณ์ในบ้านอาจเชื่อมต่อกับซอฟต์แวร์สแต็กฝั่ง Amazon ด้วย และสแต็กนั้นก็อาจใช้ Node.js กับ dependency หลายรายการเช่นกัน
  • ผลลัพธ์คือแม้แต่การเปิดประตูโรงรถ ก็อาจมี โค้ดที่ทำงานอยู่มากกว่า 50 ล้านบรรทัด บน image ของระบบปฏิบัติการหลายตัวและเซิร์ฟเวอร์หลายเครื่อง

ภาระจากคอนเทนเนอร์และ supply chain ของ dependency

  • ในอดีต เรา deploy ผลลัพธ์จาก compiler หรือชุดไฟล์ที่จะถูก interpret และต้องคิดระหว่างการติดตั้งกับตั้งค่าว่าในแพ็กเกจมีอะไรอยู่บ้าง
  • ทุกวันนี้มัก deploy ผ่านคอนเทนเนอร์ โดยรวมไม่เพียงซอฟต์แวร์ แต่ยังรวมไฟล์ระบบปฏิบัติการเพื่อให้สภาพแวดล้อมรันตรงกันด้วย
    • มักกลายเป็นสถานการณ์ที่เหมือน deploy image ของดิสก์คอมพิวเตอร์เต็ม ๆ
    • บน Docker Hub มี image จำนวนมากที่เกิน 350MB
  • คอนเทนเนอร์ใช้เพื่อวัตถุประสงค์ที่ดีได้ แต่รูปแบบการใช้งานจริงอาจเพิ่มปริมาณโค้ดที่ถูก deploy อย่างมาก
  • ยังไม่แน่ชัดว่า security update ของ dependency ถูกส่งต่อไปถึงแอปปลายทางหรือไม่
    • ยากจะรู้ว่าบั๊กประมวลผลภาพที่ Google และ Apple รีบปล่อยอัปเดตนั้นยังคงอยู่ในแอป Electron หรือไม่
  • ระบบนิเวศ npm มีประวัติเรื่อง repository ของแพ็กเกจถูกยึด, การไฮแจ็ก และการฟื้นคืนชีพแพ็กเกจชื่อเดิม
  • PyPI ก็ประสบปัญหาคล้ายกัน
  • dependency จำเป็นต้องได้รับการตรวจทาน แต่ยากจะคาดหวังให้ตรวจหลายพันรายการอยู่บ่อย ๆ
  • การเขียนทุกอย่างใหม่เองก็ไม่ใช่คำตอบ และยังมีโมดูลดี ๆ อย่าง SQLite ที่มีแนวโน้มปลอดภัยกว่าสิ่งที่เขียนเอง

Trifecta: เครื่องมือแชร์รูปภาพที่สร้างด้วยโค้ดขนาดเล็ก

  • Trifecta เป็น ซอฟต์แวร์แชร์รูปภาพแบบ standalone ที่เรียบง่ายแต่ใช้งานได้จริง
  • สามารถลากและวางรูปภาพในเบราว์เซอร์เพื่อแชร์ได้ง่าย ๆ
  • หากใช้ imgur จะมีคุกกี้และ tracker จำนวนมากถูกติดตั้งในเบราว์เซอร์ และผู้ที่ดูรูปที่แชร์ก็อาจถูกบังคับให้เจอกับ tracker ด้วย
  • เครื่องมือแชร์รูปภาพแบบ self-hosted จำนวนมากก็สร้างบน framework ขนาดใหญ่ จึงถูกมองว่าไม่น่าไว้วางใจ
  • Trifecta ถูกทำให้เล็กเพื่อให้ตรวจทานโค้ดทั้งหมดได้ภายในไม่กี่ชั่วโมง
    • ซอร์สโค้ดใหม่ 1,600 บรรทัด
    • dependency สำคัญราว 5 รายการ
    • ขนาดโค้ดทั้งหมด 3MB
  • โซลูชันแชร์รูปภาพอื่นที่ยกมาเปรียบเทียบถูก deploy เป็น Docker image ขนาด 288MB
  • โซลูชันแชร์รูปภาพที่ใช้ Node อีกตัวหนึ่งพบว่ามี dependency 1,600 รายการ และ JavaScript มากกว่า 4 ล้านบรรทัด
  • Trifecta ไม่ใช่ไซต์สาธารณะที่ให้ใครก็ได้อัปโหลดรูปภาพ แต่เหมาะกับการใช้งานในบริษัทหรือส่วนบุคคล

ปัญหาการเข้าใจผิดว่าความซับซ้อนคือพลัง

  • หนึ่งในปฏิกิริยาที่พบบ่อยต่อ Trifecta คือให้ deploy โดยใช้ชุด Amazon Web Services
    • ซึ่งไม่สอดคล้องกับเป้าหมายของซอฟต์แวร์แบบ standalone ที่ไม่พึ่งพาบริการภายนอก
  • มีปฏิกิริยาว่าพูดถึง Docker อย่างไม่เป็นธรรมด้วย แต่ก็ยอมรับว่าคอนเทนเนอร์ใช้เพื่อจุดประสงค์ที่ดีได้
  • Niklaus Wirth ชี้ในบทความปี 1995 ว่าผู้คนมีแนวโน้ม เข้าใจผิดว่าความซับซ้อนคือความประณีต
  • ดังคำกล่าวของ Tony Hoare การออกแบบซอฟต์แวร์มี 2 แนวทาง
    • ทำโปรแกรมให้เรียบง่ายจนเห็นได้ชัดว่าไม่มีข้อผิดพลาด
    • ทำให้ซับซ้อนจนดูเหมือนไม่มีข้อผิดพลาดที่เห็นได้ชัด
  • Wirth มองว่าแรงกดดันด้านเวลาเป็นสาเหตุหลักของซอฟต์แวร์ที่บวมพอง
    • แรงกดดันด้านเวลาขัดขวางการวางแผนอย่างรอบคอบ
    • ทำให้รีบเพิ่มและแก้ไข แทนที่จะปรับปรุงวิธีแก้ที่พอยอมรับได้
    • ค่อย ๆ บ่อนทำลายมาตรฐานคุณภาพและความสมบูรณ์ของวิศวกร
  • การระเบิดของปริมาณซอฟต์แวร์ไม่ใช่กฎธรรมชาติ แต่เป็นสิ่งที่วิศวกรซอฟต์แวร์ควรลดลง

การลดปริมาณโค้ดกลายเป็นมาตรการความปลอดภัย

  • โลกปัจจุบันกำลัง deploy โค้ดมากเกินไป
    • ส่วนใหญ่เป็นโค้ดจากภายนอก
    • บางส่วนถูกรวมเข้ามาโดยไม่ตั้งใจ
    • ส่วนใหญ่ไม่ได้รับการตรวจสอบอย่างเพียงพอ
  • ผลคือเกิด attack surface มหาศาล และมีโค้ดระดับธรรมดาจำนวนมากถูกเปิดเผยอยู่ภายในนั้น
  • ความพยายามยกระดับคุณภาพโค้ดยังคงดำเนินต่อไป แต่การโจมตีจำนวนมากมาจากความล้มเหลวด้านตรรกะ และความคืบหน้าในการตรวจจับเรื่องนี้ยังค่อนข้างน้อย
  • แค่ลดปริมาณโค้ดที่เปิดเผยต่อโลกก็สามารถสร้างการปรับปรุงได้มากแล้ว
  • เวลาในการออกผลิตภัณฑ์อาจยาวขึ้น แต่กฎหมายที่กำลังจะมาถึงอาจทำให้ผู้จำหน่ายจริงจังกับความปลอดภัยมากขึ้น
  • Trifecta และ Oberon แสดงให้เห็นว่าแม้มีโค้ดและ dependency จำกัด ก็ยังมอบฟังก์ชันได้มาก

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

 
GN⁺ 2024-02-11
ความคิดเห็นจาก Hacker News
  • ใน A Deepness in the Sky ของ Vernor Vinge มนุษยชาติแพร่กระจายไปตามดวงดาวได้ด้วยเพียง เทคโนโลยีความเร็วต่ำกว่าแสง และยานอวกาศระหว่างดาวก็ปรากฏในสภาพที่เทคโนโลยีเก่าแก่จากหลายระบบดาวและหลายอารยธรรมปะปนกันอยู่
    ระบบคอมพิวเตอร์เองก็วิวัฒนาการมายาวนานมากจนแทบไม่มีใครเข้าใจโค้ดส่วนใหญ่แล้ว แค่ใช้งานมันและสร้างสิ่งใหม่ทับขึ้นไปอีกชั้น
    โดยเฉพาะมีตัวละครคนหนึ่งที่เป็นวิศวกรระบบยุคเก่า ซึ่งผ่านการสลับระหว่างภาวะหยุดนิ่งกับการเดินทางมาเป็นเวลานาน จนจัดว่าเป็นหนึ่งในมนุษย์ที่ยังมีชีวิตอยู่ที่เก่าแก่ที่สุด และในอนาคตที่ทุกคนสร้างหลายชั้นทับบนระบบเหล่านั้น ความรู้ของเขาเกี่ยวกับวิธีทำงานและช่องโหว่ในยุคของตัวเองกลับกลายเป็นข้อได้เปรียบอย่างมาก
    ผมคิดว่า Vinge ชี้ประเด็นได้แม่นมาก

    • “ไม่มีใครรู้” มีอยู่สองแบบ: “ไม่มีใครรู้ว่าจะสร้าง เซมิคอนดักเตอร์อุณหภูมิห้อง ได้อย่างไร” กับ “ไม่มีใครรู้ว่าเครื่องซักผ้าของผมเสียเพราะอะไร”
      แบบแรกเป็นปริศนาจริง ๆ ที่วิทยาศาสตร์สมัยใหม่และคนฉลาดมาก ๆ ต้องแก้ แต่แบบหลังใกล้เคียงกับการขาดความสนใจมากกว่า
      ถ้าจ่ายเงินมากพอ วิศวกรที่เก่งก็จะแยกชิ้นส่วนเครื่องซักผ้าแล้วหาข้อบกพร่องที่แน่ชัดได้ แต่ไม่มีใครยอมจ่ายค่าใช้จ่ายนั้น และจะทิ้งแล้วซื้อใหม่แทน
      ความรู้เกี่ยวกับซอฟต์แวร์ในอดีตจัดอยู่ในแบบหลังอย่างชัดเจน ไม่ว่าส่วนไหน หากขุดลงไปก็จะเข้าใจได้อย่างสมบูรณ์ในที่สุด แต่ส่วนใหญ่แล้วการเพิกเฉยหรือวางอีกชั้นทับลงไปนั้นถูกกว่าและใช้งานได้จริงกว่ามาก
    • นึกถึงเรื่องสั้นที่ไม่ค่อยดีของ Asimov อย่าง The Feeling of Power
      เป็นเรื่องที่มนุษย์ในอนาคตลืมเลขคณิตพื้นฐานไปแล้ว และเมื่อมีคนค้นพบมันใหม่ ผู้มีอำนาจก็พยายามนำไปใช้ในสงคราม ผมเข้าใจสารที่ต้องการสื่อ แต่คิดว่าฉากหลังมันไม่สมจริงจนน่าขำเกินไปจนทำให้พลังของเรื่องหายไป
    • Vinge มองได้ถูกจริง ๆ ชอบชื่อ Programmer Archaeologist และมันอธิบายสิ่งที่เราทำกันทุกวันได้ดีมาก
      หากต้องการอภิปรายเพิ่มเติม ดูที่ http://lambda-the-ultimate.org/node/4424
    • นึกถึงตัวละคร นักโบราณคดีซอฟต์แวร์ ในนิยายของ Alastair Reynolds น่าจะเป็นแถว Tau Ceti เป็นผู้เชี่ยวชาญในการขุดค้นโค้ดอายุหลายร้อยปี
      เรากำลังเจอปัญหาแบบนี้อยู่แล้ว ลุงของผมที่อายุ 60 กว่า ๆ กำลังบำรุงรักษาซอฟต์แวร์ขนส่งด้วยรถบรรทุกเก่าที่เขียนด้วย COBOL และยังมีงานเทคโนโลยีโบราณแบบนี้อยู่ ถ้าสนใจก็แนะนำให้ได้
      ปัญหาพื้นฐานเหมือนกับเหตุการณ์ left-pad เราหัวเราะเยาะวิศวกรจูเนียร์ที่ไม่มีคนกำกับดูแลซึ่งติดตั้ง dependency แบบลวก ๆ แต่เมื่อผ่านไปหลายสิบปีและนักพัฒนาหลายรุ่น สุดท้ายซอฟต์แวร์ส่วนใหญ่ก็ต้องพึ่งพา dependency ที่ไม่อาจรู้ที่มาได้ในระดับหนึ่ง
      ลองสมมติว่าต้องปล่อยอัปเดตในปี 2100 ก็คงต้องดันมันผ่านระบบจัดการ dependency ของ npm ในยุคนั้น ในขณะเดียวกันอาจมีอุปกรณ์ที่ต้องพึ่งพากันและต้องอัปเดตความปลอดภัยกระจายอยู่ทั่วระดับระบบสุริยะ มีอุปกรณ์เป็นล้านล้านชิ้น และแคชตัวกลางที่ไม่รู้ว่าอัปเดตล่าสุดหรือไม่ ผมนึกภาพไม่ออกเลยว่า dependency tree แบบนั้นจะหน้าตาเป็นอย่างไร
    • ถ้าคิดถึงการจ้างงานแบบ เฝ้าประตู ในสังคมมนุษย์ คนแบบนั้นอาจแทบไม่มีทางถูกจ้างเลยก็ได้ คงจะออกมาแนว “ไม่มีประสบการณ์กับเฟรมเวิร์ก XYZ งั้นเหรอ? เชิญออกไป”
      การทำงานในสภาพแวดล้อมที่ต้องขุดโค้ดของเฟรมเวิร์กลงไปเพื่อไปให้ถึงแก่นก็ชวนหงุดหงิดเหมือนกัน รู้สึกเหมือนเสียเวลาเปล่า
  • ความบวมโตพบได้ในไลบรารีส่วนใหญ่ของ npm ผู้เขียนไม่รู้จักการออกแบบที่ดี และพยายามทำให้ทุกไลบรารีทำได้ทุกอย่าง
    อย่างเช่นบอกว่าเป็นไลบรารีแปลงการเข้ารหัสสตริง แต่กลับใส่ทั้งการโหลดไฟล์ บันทึกไฟล์ ดาวน์โหลดจากอินเทอร์เน็ต และเครื่องมือบรรทัดคำสั่งไว้ในรีโพซิทอรีเดียวกัน ไลบรารีควรทำงานของตัวเองเพียงอย่างเดียว แล้วปล่อยส่วนที่เหลือให้ผู้ใช้จัดการ
    ฝั่ง Rust ก็ดูไม่ได้ดีกว่าเท่าไร ถ้าลองแก้เอกสารของ Rust จะเห็นว่ามี crate ถูกติดตั้งเข้ามาราว 1,000 ตัว
    ปัญหาไม่ได้อยู่ที่ภาษา แต่อยู่ที่ใครก็อัปโหลดไลบรารีได้ และในความเป็นจริงก็มีใครก็ไม่รู้มาอัปโหลด คนที่ “แค่อยากให้งานเสร็จ” จะเลือกไลบรารีที่มีฟีเจอร์มากที่สุด และเรียกร้องฟีเจอร์เพิ่ม เพราะไม่อยากเขียนโค้ด 3 บรรทัดที่ควรอยู่นอกไลบรารี เช่น “ช่วยเพิ่มการเรนเดอร์ PDF ให้ด้วยได้ไหม?”
    ยังไม่แน่ใจว่าทางแก้คืออะไร แต่เคยคิดถึงการตั้งกลุ่มสนับสนุน Low Dependency พร้อมแบดจ์ เพื่อให้ผู้เขียนไลบรารีอยากได้แบดจ์นั้น และให้ผู้ใช้มองหาเวลาจะเลือกไลบรารี

    • ฟังดูเหมือนกำลังพูดปนกันระหว่างการพึ่งพาต่ำกับความไม่บวมโต ถ้าต้องการ ไลบรารีที่ไม่บวมโต ก็มีแนวโน้มว่าจะต้องดึงของชิ้นเล็ก ๆ จำนวนมากที่ทำอะไรเองได้ไม่มากเข้ามา
      ในทางกลับกัน ถ้าต้องการไลบรารีที่มี dependency น้อย ก็จะได้ของไม่กี่ตัวที่ทำงานได้หลายอย่าง
      ในมุมมองของผม ไลบรารีที่หนากว่านิดหน่อยแต่ dependency น้อย และมาจากผู้เขียนที่ไว้ใจได้ ดีกว่า Lodash ใหญ่ก็จริง แต่เวอร์ชัน ES6 module รองรับ tree shaking และโดยเนื้อแท้แล้วทำหน้าที่เหมือน standard library ที่ JavaScript เคยขาดไป ส่วน date-fns ก็คล้ายกันสำหรับ Date ผมใส่สองตัวนี้เป็นค่าเริ่มต้นในแทบทุกโปรเจกต์เพื่ออุดช่องว่างของไลบรารีแกนหลักของ JavaScript
    • เห็นด้วยกับประเด็นนี้มาก
      เมื่อก่อนเคยรับงานสัญญา Ruby on Rails อยู่ช่วงหนึ่ง ปัญหาประสิทธิภาพหนักมากจนต้องพัฒนาในโหมด release เซิร์ฟเวอร์ถึงขั้นตรวจจับการเปลี่ยนไฟล์แล้ว reload อัตโนมัติไม่ได้
      วันหนึ่งทนไม่ไหวเลยเริ่มขุดดู มี gem ถูกดึงเข้ามามากจนจำไม่ได้ว่ากี่ตัว หนึ่งในนั้นเป็น gem ที่มีไว้เพื่อประหยัด โค้ด 3 บรรทัด จริง ๆ
      หลังจากนั้นก็อยู่ห่างจากชุมชน RoR มาตลอด เพิ่งกลับมารับงานสัญญา RoR อีกครั้งในรอบหลายปี ถึงจะไม่แย่เท่าเดิม แต่ก็ยังไม่ดีอยู่ดี
      บางชุมชนไม่ให้ความเคารพต่อความเสี่ยงที่ dependency นำมาเลย
    • นี่แหละเหตุผลที่ชอบ Go กับ standard library ของมัน ถ้าไม่ใช่ไลบรารีขนาดใหญ่สำหรับการใช้งานเฉพาะทางมาก ๆ โดยทั่วไปแนวทางคือ “ทำเองเถอะ” และถ้าเป็นไลบรารีเล็ก ๆ ที่ทำเรื่องง่าย ๆ การสร้างเองด้วย standard library มักจะดีกว่า แทบทุก องค์ประกอบ มีอยู่แล้ว
      ในทางกลับกัน การที่ Git repository ไหน ๆ ก็โฮสต์ไลบรารี Go ได้ และใครก็ใช้จาก URL นั้นได้ ถือว่าสะดวกมากจริง ๆ
    • ปัญหามาจากทั้งสองฝั่ง
      อย่างแรก ผู้ทำแพ็กเกจอยากสร้างสิ่งนี้ให้เป็นเส้นทางอาชีพ และวิธีเรียกความสนใจก็มีแต่การทำแพ็กเกจจำนวนมาก พวกเขาจึงทำแพ็กเกจที่พึ่งพาแพ็กเกจอื่น ๆ ของตัวเองต่อไปเรื่อย ๆ และพยายามยัดแพ็กเกจที่มีประโยชน์สักหนึ่งสองตัวของตัวเองเข้าไปในโค้ดของคนอื่น
      อย่างที่สอง คือคนที่เชื่อว่าการแก้ปัญหาต้องมีแพ็กเกจใหม่เสมอ พวกเขาไม่สนใจว่ามี dependency มากแค่ไหน หรือปัญหาจริง ๆ ยากหรือไม่ สุดท้ายแทนที่จะเรียนรู้วิธีแก้ปัญหา ก็ไปเรียน API ของ wrapper ที่มีดาว GitHub 4 ดวง
    • คำตอบแบบ “เพิ่ม AI กล่องดำที่กินทรัพยากรมหาศาลเข้ามาเพื่อจัดระเบียบ dependency tree” นั้นน่าเศร้า แต่ดูเหมือนจะเป็นคำตอบที่เราจะได้จริง ๆ ถึงอย่างนั้นมันก็อาจดีกว่าความโกลาหลในปัจจุบัน
      ตามอุดมคติ เครื่องมือแบบนี้ควรใช้เวลาน่าเบื่อไปกับการตัดแพ็กเกจที่ไม่จำเป็นออก ลดความรับผิดชอบของแต่ละแพ็กเกจให้เหลือน้อยที่สุด จัดสภาพแวดล้อมให้สมเหตุสมผล แล้วแคชอย่างเป็นอิสระจนไม่ต้องพึ่ง LLM ควรเรียกตัวตรวจอัปเดตหรือ curator เฉพาะเวลามีปัญหาเท่านั้น
      พูดตรง ๆ นี่เป็นหนึ่งในปัญหาแย่ที่สุดของซอฟต์แวร์สมัยใหม่ และผมคิดว่ามันทำให้โปรเจกต์เกิน 50% ใช้งานไม่ได้ เป็นปัญหาที่น่าเบื่อแต่แก้ได้ จึงเหมาะมากกับ LLM agent ที่ทำได้จริง และถ้ามีก็คงช่วยได้มาก
  • “คุณเคยเห็นเครื่องบินสมัยใหม่ไหม? เคยติดตามไหมว่าเส้นสายของมันวิวัฒนาการไปอย่างไรในแต่ละปี? เคยคิดไหมว่า ไม่ใช่แค่เครื่องบิน แต่ทุกสิ่งที่มนุษย์สร้างขึ้น ความพยายามทางอุตสาหกรรม การคำนวณ และค่ำคืนที่ใช้ไปกับแบบร่างของมนุษย์ สุดท้ายล้วนมุ่งไปสู่หลักการเดียวที่ครอบงำทุกอย่าง นั่นคือ ความเรียบง่ายขั้นสูงสุด?
    ราวกับมีกฎธรรมชาติที่สั่งว่า หากจะขัดเกลาเส้นโค้งของเฟอร์นิเจอร์ กระดูกงูเรือ หรือลำตัวเครื่องบิน ให้เข้าใกล้ความบริสุทธิ์ดั้งเดิมอย่างเส้นโค้งของอกหรือไหล่มนุษย์ ก็ต้องอาศัยการทดลองของช่างฝีมือหลายชั่วคน ความสมบูรณ์แบบดูเหมือนจะมาถึง ไม่ใช่เมื่อไม่มีอะไรให้เพิ่มอีกต่อไป แต่เมื่อไม่มีอะไรให้ตัดออกได้อีกแล้ว”
    — Antoine de Saint Exupéry, Terre des Hommes

    • เพิ่งเคยเห็นบริบทของคำคมนี้ พอรู้ว่าผู้เขียนเป็น นักบิน แล้วก็เข้าใจขึ้นมาก
  • พอเขียนออกมาว่า “การเปิดประตูโรงรถอาจต้องใช้โค้ดที่ทำงานอยู่มากกว่า 50 ล้านบรรทัด และอิมเมจระบบปฏิบัติการบนเซิร์ฟเวอร์หลายเครื่อง” ก็รู้สึกว่ามันบ้าจริง ๆ
    แค่คิดว่ามีโค้ดมากแค่ไหนที่กำลังทำงานอยู่บนเครื่องที่ผมใช้พิมพ์ข้อความนี้ ก็เวียนหัวแล้ว เป็นโค้ดที่ผมไม่เคยตรวจ และคงแทบไม่เคยผ่านการตรวจสอบอย่างเข้มงวดด้วย
    เอาละ กลับไปติดตั้ง dependency ของ npm ต่อก่อน

    • แต่มันก็ทำงานได้อยู่ดี เลเยอร์ที่นำกลับมาใช้ซ้ำได้ และ abstraction ทำให้การแพร่หลายของกรณีการใช้งานคอมพิวติ้งที่เรามีทุกวันนี้เป็นไปได้
  • อุปมาที่ว่า “ซอฟต์แวร์ตอนนี้ถูกมองว่าอันตรายจนถึงขั้นมีคนบอกว่าอย่ารันเอง ให้ฝากไว้กับผู้ให้บริการ ‘X as a service’ หรือไม่ก็ ‘คลาวด์’ แทน ลองเทียบกับสถานการณ์สมมติที่รถยนต์ไฟไหม้บ่อยเกินไปจนมีคำแนะนำว่าอย่าขับเอง แต่ให้ผู้เชี่ยวชาญที่มีนักดับเพลิงมืออาชีพคอยตามประกบตลอดเป็นคนขับให้” นี่น่าเอาไปใช้ต่อจริง ๆ

    • ถ้ารถยนต์เพิ่งถูกประดิษฐ์ขึ้นในปี 2024 ก็คงไม่มีทางอนุญาตให้ประชาชนทั่วไปขับแน่ ๆ แค่มีคนตายไม่กี่คนจากผลิตภัณฑ์ใหม่ก็เป็นเรื่องใหญ่แล้ว ไม่ต้องพูดถึงการเสียชีวิตปีละ 40,000 คน
    • นั่นคือสิ่งที่ ผู้ให้บริการคลาวด์ พูดกัน และพนักงานของพวกเขาที่มีโครงสร้างค่าตอบแทนซึ่งไม่ควรถูกตีความเป็นอย่างอื่นก็เช่นกัน
    • ผู้ใช้ส่วนใหญ่ที่ผมรู้จักยืนอยู่ริมหน้าผา ใกล้จะสูญเสียทุกอย่างที่เคยทำมาทั้งหมดอยู่แล้ว ไม่ได้หมายความว่าควรขายวิญญาณให้บริษัท SaaS นะ อนึ่ง ผมทำงานอยู่ในบริษัทแบบนั้น และบางแห่งอาจเผาข้อมูลทิ้งเสียยังดีกว่าเอาไปฝากไว้ด้วย
      แฟนเก่าของผมไม่ไว้ใจ “คลาวด์” ด้วยเหตุผลที่สมเหตุสมผลจากการเติบโตในอดีตกลุ่มตะวันออก แต่ทางเลือกคือได้แต่หวังว่าจะไม่ทำโน้ตบุ๊ก HP ที่ซื้อมาในราคาต่ำสุดหาย หลังจากให้ความรู้เล็กน้อย อย่างน้อยในเรื่องนั้นเธอก็สบายใจขึ้น
      ปัญหาคือการขาดความรู้โดยรวมและการไม่คำนึงถึงผลลัพธ์ที่ตามมา สุดท้ายก็ต้องยอมรับความเสี่ยง เรียนรู้เอง หรือพึ่งบริษัท SaaS กับคลาวด์ ผมเห็นน้ำตามามาก และไม่ค่อยเห็นกรณีที่เรียนรู้ด้วยตัวเองนัก
      มันเป็นเรื่องความรับผิดชอบส่วนบุคคล แต่เมื่อไม่มีใครอยากรับผิดชอบ การมอบให้ผู้เชี่ยวชาญอาจเป็นทางออกที่แย่น้อยกว่าการเชื่อตัวเอง คำตอบที่ถูกคือการศึกษา แต่มันยากอย่างสิ้นหวัง
    • เคยใช้อุปมาเรื่อง รถยนต์ แทบจะเหมือนกันนี้ตอนที่มีคนแถวนี้คัดค้านอย่างหนักว่า การใช้สารหลอนประสาทไม่ควรทำเด็ดขาด เว้นแต่เพื่อวัตถุประสงค์ทางการแพทย์และมีผู้เชี่ยวชาญช่วยดูแล
  • ซอฟต์แวร์ผอมเพรียวลงกว่านี้ไม่ได้หรอก หากจะทำได้ต้องใช้เวลา ฝีมือ และคนค่าตัวแพง ไม่ใช่แค่คนที่เอาตัวอย่างจากเทคสแต็ก 12 แบบมาต่อกันเป็น ชุดแฟรงเกนสไตน์
    ผมเป็นนักพัฒนาอิสระ และคนที่เพิ่งเรียน node.js เมื่อปีที่แล้วแล้วเอา node.js, คอนเทนเนอร์, บริการฐานข้อมูลโฮสต์บน AWS อะไรก็ได้, Lambda, object storage, Cloudflare, YAML, React, Vite และ dependency อื่น ๆ มาประกอบกันในวันเดียวจนได้เว็บแอปที่สำเร็จรูปแต่ยังเปราะบาง มักเสนอราคาต่ำกว่าผมเสมอ
    ซอฟต์แวร์ที่ผอมเพรียว เร็ว ต้นทุนรันต่ำ และค่าบำรุงรักษาถูกกว่า แม้ระยะยาวจะถูกกว่า แต่เขียนให้มีกำไรได้ยาก

    • ใช่ นี่ไม่ใช่ปัญหาเรื่องการรับรู้ แต่เป็นปัญหาของ โครงสร้างเศรษฐกิจ ถ้าจ่ายเงินให้ซอฟต์แวร์ที่ไม่ยั่งยืน ผู้คนก็จะสร้างมันขึ้นมา
  • สมัยก่อนเคยมีความฝันว่าทุกคนจะใช้ hook และ routine มาตรฐานที่ระบบจัดไว้ให้สำหรับอินเทอร์เฟซและอื่น ๆ ให้นึกถึงอย่าง Macintosh Toolbox หรือ QuickDraw
    ตอนนั้นว่ากันว่างานหลักของนักพัฒนาคือเขียนลอจิกของโปรแกรม และการเปลี่ยนแปลงหรือการเพิ่มควรโปร่งใส system call ควรทำงานเดิมได้อย่างราบรื่นแม้โค้ดภายในจะเปลี่ยนไป และฟีเจอร์ใหม่ควรเป็น superset ของฟีเจอร์เดิม ทำให้โค้ดเก่ายังคอมไพล์หรือรันได้ไม่มีปัญหา ขณะที่ซอฟต์แวร์ใหม่ได้ความสามารถมากขึ้น
    เชื่อกันว่าวิธีนี้จะทำให้บำรุงรักษาง่าย อินเทอร์เฟซเป็นมาตรฐาน และโค้ดผอมเพรียวลงเพราะพึ่งพา system call มาก บรรยากาศตอนนั้นคือควรหลีกเลี่ยงไลบรารีภายนอก
    ความฝันนี้พังลงอย่างรวดเร็ว ให้นึกถึง DLL ปัจจุบัน package management และ packaging จำนวนมากดูเหมือนจะเป็นงานที่ทำให้แน่ใจว่ามีไลบรารีที่ถูกต้องอยู่
    ตอนนั้นการพัฒนาซอฟต์แวร์ขนาดใหญ่ยังแทบอยู่ในวัยทารก จึงเข้าใจได้ว่ามันไม่เป็นไปตามคาด ตอนนี้เรามีประสบการณ์ร่วมกับปัญหาเหล่านี้สะสมมามากแล้ว เลยสงสัยว่าบทสรุปคือความฝันนี้เป็นไปไม่ได้อย่างมีสติ หรือว่าการผ่านสภาพยุ่งเหยิงในปัจจุบันมามากพอจะพาเราไปสู่ความพยายามแบบสมัยใหม่อีกครั้ง
    ถ้าต้องการซอฟต์แวร์ที่เร็ว ผอมเพรียว เสถียร และปลอดภัย ต่อให้จะได้ครบทั้งสี่อย่างพร้อมกันได้ยาก ผมก็ไม่แน่ใจว่าสถานการณ์ปัจจุบันกำลังมุ่งไปทางนั้นหรือไม่

    • มี แรงกดดันซ้ำ ๆ ให้ดันฟังก์ชันลงไปยังเลเยอร์ที่ต่ำกว่า Unix ยุคแรกทำงานน้อยมาก แต่ BSD สมัยใหม่ถูกแจกจ่ายมาในสภาพที่ค่อนข้าง “ครบถ้วน”
      Lisp ยุคแรกใส่สิ่งต่าง ๆ ไว้ในภาษาน้อยมาก แต่ Raku ดันแม้แต่เรื่องเล็ก ๆ ที่น่าจะไปอยู่เป็นไลบรารี npm เข้าไปในสเปกของภาษา
      C ปล่อยให้คุณตัดสินใจเองว่าจะ build โค้ดอย่างไร แต่ภาษาแบบคอมไพล์ใหม่ ๆ ส่วนใหญ่ให้ build tool มาพร้อมกันในรูปแบบใดรูปแบบหนึ่ง
      ในภูมิทัศน์นี้มีบางอย่างที่ได้ผลค่อนข้างดี แต่เกิดขึ้นนอกบริบท “นาย เครื่องจักร โปรเจกต์ใหม่” ที่ขับเคลื่อนงานของ Wirth ปัญหาคือมันมักมาพร้อมกับธรณีประตูของ dependency ขนาดมหึมา อย่างฐานข้อมูลหรือเอนจินเบราว์เซอร์ และถ้าไม่ชอบวิธีที่ dependency นั้นถูกสร้างขึ้นมา สุดท้ายก็จะไม่มีความสุข
  • สิ่งที่พูดเรื่อง Rust อยู่เรื่อย ๆ ก็คือนี่แหละ
    ถ้า 70% ของช่องโหว่ C++ เก่า ๆ เกี่ยวกับหน่วยความจำจริง ๆ ช่องโหว่ต่อบรรทัดโค้ดก็อาจน้อยกว่า C++ ได้ 70%
    แต่ถ้าใน Rust ดึงแพ็กเกจเข้ามาหลายร้อยตัวและจำนวนบรรทัดโค้ดเพิ่มเป็น 10 เท่า เรื่องก็เปลี่ยนไป
    30% ของ 100,000 บรรทัด มีปริมาณรวมมากกว่า 100% ของ 10,000 บรรทัด

    • การนับจำนวน crate แล้วเอาไปเทียบกับจำนวนไลบรารี C++ เป็น ความผิดพลาดเชิงภววิทยา ใน Rust ทีมหนึ่งมักจะแบ่งโปรเจกต์ออกเป็นหลาย crate
      แม้แต่อย่าง QT ถ้าเขียนด้วย Rust ก็คงกลายเป็น crate หลายร้อยตัวในตัวเอง แต่ปริมาณโค้ดและระดับความเสี่ยงที่ยอมรับจะเหมือนเดิมทุกประการ
    • ไม่มีใครบังคับให้ใช้ไลบรารีนี่ แค่เขียน software stack เองก็ได้
      แต่ปัญหาใหญ่คือช่องโหว่ แก้บั๊กใน shared library ตัวเดียวเพื่อแก้ไลบรารีหลายร้อยตัวดีกว่าไหม หรือแก้ไลบรารีหลายร้อยตัวทีละตัวดีกว่า?
    • สงสัยว่ามีหลักฐานไหมว่าโปรแกรม Rust รันโค้ดมากกว่าโปรแกรม C++ ถึง 10 เท่าจริง ๆ ฟังดูไม่น่าเป็นไปได้มาก งานแปล C++↔Rust ส่วนใหญ่ที่ผมเคยเห็นต่างกันราว ๆ 30%
      ข้อเท็จจริงที่ว่า Rust ทำให้ดึง dependency เล็ก ๆ จำนวนมากเข้ามาได้ง่าย แทนที่จะเป็น dependency ขนาดยักษ์ไม่กี่ตัวนั้นไม่เกี่ยวกัน ไม่ได้แปลว่าใช้โค้ดมากกว่า
      ตัวอย่างเช่น นับ crate regex ของ Rust เป็น dependency ไหม? ใน C++ สิ่งนั้นอยู่ใน standard library
      นับ Boost เป็น dependency เดียวใน C++ ไหม? ถ้าเป็น Rust มันคงเทียบได้กับ crate แยกกันสัก 30 ตัว
    • ช่องโหว่ที่เกี่ยวกับหน่วยความจำมักเป็นประเภทเลวร้ายที่สุดอย่าง remote code execution remote code execution ร้ายแรงกว่าช่องโหว่อื่นอย่าง denial of service มาก
      ในโปรแกรม Rust มี remote code execution มากแค่ไหนเมื่อเทียบกับ C++? ความถี่ของ remote code execution ใน C++ น่าจะมากกว่า Rust เกิน 70% ไปไกล
  • ช่วงนี้แอปมักถูกบอกว่าสร้างด้วย Electron JS แต่ดูเหมือนหลายคนยังไม่ค่อยรู้ว่าอาจใช้ native web control ของแต่ละแพลตฟอร์มโดยไม่ต้องพ่วง Electron ก็ได้
    ถ้าทำแบบนั้น แอปที่แจกจ่ายอาจมีขนาดแค่ระดับกิโลไบต์ แนวทางนี้ให้เสรีภาพว่าจะใช้ภาษาแบ็กเอนด์หรือ tech stack ใดก็ได้ ตราบใดที่สื่อสารกับเว็บวิวได้

    • แบบนั้นแอปก็จะใช้เวลาหลายวินาทีในการเริ่ม ทำงานช้า และเพราะผู้ใช้ไม่ได้ใช้ native webview เป็นเบราว์เซอร์หลัก สุดท้ายอาจใช้ RAM มากกว่า Electron เสียอีก
    • “ซอฟต์แวร์ที่เพรียวบาง” ไม่ได้หมายถึงแค่ขนาดดาวน์โหลด
    • สงสัยว่าช่องว่างของ PWA ในตอนนี้คืออะไร
      ทุกวันนี้แอปพลิเคชันสัดส่วนค่อนข้างมากน่าจะทำเป็น PWA ได้ไม่ใช่หรือ?
      ไม่แน่ใจนัก แต่ Discord ก็น่าจะเป็น PWA แทนแอป Electron ได้หรือเปล่า?
      ช่องว่างที่ใหญ่ที่สุดน่าจะเป็นความต่างระหว่างบางสิ่งที่ทรงพลังเทียบเท่า SQLite กับ IndexedDB แต่ถึงอย่างนั้น แอปส่วนใหญ่ก็ดูไม่น่าจำเป็นต้องมีภาษา query ระดับสูงกว่าโมเดล B-tree ของ IndexedDB เสมอไป
  • ขอส่งเสียงเชียร์ปรัชญา suckless อีกครั้ง ไชโย
    [0 ]https://suckless.org/