3 คะแนน โดย GN⁺ 3 일 전 | 2 ความคิดเห็น | แชร์ทาง WhatsApp
  • Bun ซึ่งเริ่มต้นด้วย Zig เติบโตเป็น runtime ที่มีการดาวน์โหลดมากกว่า 22 ล้านครั้งต่อเดือน แต่ปัญหาความเสถียรที่เกิดซ้ำจากการผสานกันระหว่างเอนจิน JavaScript แบบ GC กับการจัดการหน่วยความจำด้วยตนเอง กลายเป็นเหตุผลให้เปลี่ยนไปใช้ Rust
  • แทนที่จะให้คนย้ายโค้ด Zig จำนวน 535,496 บรรทัดตลอด 1 ปี ทีมรัน dynamic workflow ของ Claude Code ประมาณ 50 รายการ และ Claude instance สูงสุด 64 ตัวแบบขนานเป็นเวลา 11 วัน
  • การ port ถูกตรวจสอบด้วย PORTING.md, LIFETIMES.tsv, ผู้ implement 1 คนกับ reviewer เชิงปฏิปักษ์ อย่างน้อย 2 คน และชุดทดสอบ TypeScript เดิม โดยผ่าน CI 6 แพลตฟอร์ม 100%
  • หลังเปลี่ยนเป็น Rust, Bun v1.4.0 แก้ บั๊ก 128 รายการ ที่ทำซ้ำได้ใน v1.3.14 แก้ memory leak ที่ instrument ได้ทั้งหมด และลดขนาด binary บน Linux·Windows ลงประมาณ 20%
  • Bun v1.3.14 เป็นเวอร์ชัน Zig สุดท้าย และ v1.4.0 เป็นเวอร์ชัน Rust แรกที่ให้ใช้ใน canary โดยทีมใช้ borrow checker, Miri, LeakSanitizer และ fuzzing แบบ 24/7 บนฐาน coverage เป็นเครื่องมือปรับปรุงความเสถียร

Bun ที่เริ่มต้นด้วย Zig และปัญหาความเสถียร

  • Bun เริ่มต้นจากโปรเจกต์ที่ port แบบทีละบรรทัด transpiler สำหรับ JavaScript·TypeScript ของ esbuild จาก Go ไปเป็น Zig
  • โค้ด Zig ชุดแรกเขียนขึ้นเมื่อวันที่ 16 เมษายน 2021 และการควบคุมระดับต่ำกับการออกแบบที่เน้นประสิทธิภาพของ Zig ทำให้การ implement Bun ช่วงแรกเป็นไปได้
  • Bun ช่วงแรกถูกเขียนด้วย Zig โดยคนคนเดียวตลอด 1 ปี และมีขอบเขตกว้างมาก
    • transpiler·minifier·bundler สำหรับ JavaScript, TypeScript, CSS
    • package manager ที่เข้ากันได้กับ npm
    • test runner คล้าย Jest
    • การ resolve module ที่เข้ากันได้กับ Node.js·TypeScript
    • client สำหรับ HTTP/1.1·WebSocket
    • การ implement Node.js API เช่น fs, net, tls
  • ปัจจุบัน Bun CLI ถูกดาวน์โหลดมากกว่า 22 ล้านครั้งต่อเดือน ถูกใช้เป็น runtime โดย Claude Code และ OpenCode และมี Vercel, Railway, DigitalOcean เป็นต้นที่ให้การรองรับแบบ 1st-party

บั๊กด้านความปลอดภัยหน่วยความจำที่เกิดซ้ำ

  • ตัวอย่างบั๊กที่แก้ใน Bun v1.3.14 รวมถึง use-after-free, double-free, memory leak, การเข้าถึง out-of-bounds และ race condition
    • heap-use-after-free จากการเรียก .reset() ระหว่าง async .write() ของ node:zlib
    • use-after-free ที่ JS callback แบบ reentrant ของ node:http2 ทำให้เกิด hashmap rehash จน pointer ของ stream ภายในเป็นโมฆะ
    • ปัญหาที่ callback valueOf() หรือ toString() detach ArrayBuffer ใน UDPSocket.send() และ sendMany()
    • crash และ out-of-bounds read จากการ detach หรือ resize ArrayBuffer ระหว่างการ coercion argument ใน Buffer#copy, Buffer#fill
    • memory leak ที่เกี่ยวข้องกับ crypto.scrypt, tlsSocket.setSession(), fs.watch()
    • double-free ระหว่างการจัดการ vendor prefix และ multi-layer background ของ CSS parser
    • crash จาก race condition ของ MessageEvent ระหว่างการเข้าถึงพร้อมกันของ BroadcastChannel หรือ MessagePort
  • ก่อนหน้านี้ก็ใช้กลไกหลายอย่างเพื่อเสริมความเสถียร
    • patch ให้ Zig compiler รองรับ Address Sanitizer และรันชุดทดสอบ ASAN ในทุก commit
    • บน Windows แจกจ่าย build แบบ Zig safety-checked ReleaseSafe
    • fuzz API ของ Bun runtime แบบ 24/7 ด้วย Fuzzilli
    • ดำเนินการทดสอบ memory leak แบบ end-to-end จำนวนมาก
  • ไม่ได้มีจุดยืนว่า Zig เองเป็นปัญหา แต่ข้อกำหนดที่ต้องจัดการค่าของ GC ร่วมกับหน่วยความจำที่จัดการเอง เป็นแหล่งหลักของปัญหาความเสถียร

เหตุผลที่เลือก Rust

  • JavaScript เป็นภาษาแบบ GC และเอนจินอย่าง JavaScriptCore กับ V8 มีกฎที่เข้มงวดเกี่ยวกับ exception handling และ GC
  • Zig ไม่ได้จัดการหน่วยความจำอัตโนมัติเหมือน C ไม่มี constructor·destructor และส่วนใหญ่ต้องระบุ cleanup ด้วย defer ที่แต่ละ call site
  • ใน Bun การจัดการ lifetime ของค่า GC และค่าที่จัดการด้วยตนเองให้ถูกต้อง เป็นแหล่งใหญ่ของปัญหาความเสถียร
    • ต้องตรวจสอบว่า byte ที่ allocate ถูก free ที่ไหน
    • ต้องรับประกันว่า free เพียงครั้งเดียว
    • ต้องตรวจสอบการจัดการ JavaScript exception ให้ถูกต้อง
    • ต้องตรวจสอบว่า GC pointer มองเห็นได้จาก conservative stack scanner หรือไม่
  • วิธี cleanup ของ Zig คือ defer, errdefer แบบชัดเจน ส่วน C++ ใช้ destructor และ move ขณะที่ Rust ใช้ Drop
  • ในโค้ด Zig เดิมของ Bun มีการผสมกันระหว่าง arena lifetime, reference counting และการ review อย่างละเอียด
  • แม้จะบังคับกฎ ownership ด้วย style guide และ code review ได้ แต่ในโค้ดที่ปลอดภัยของ Rust, use-after-free, double-free และ free ที่ตกหล่นใน error path จะกลายเป็น compiler error
  • โค้ดของ Bun ประมาณ 20% เป็น C++ และฝังไลบรารี C/C++ หลายตัว
    • JavaScriptCore
    • uWebSockets และ usockets
    • lshpack และ lsquic
    • BoringSSL
    • SQLite
  • C++ ก็เป็นตัวเลือกได้ แต่ยังคงต้องพึ่ง style guide และ code review และแม้มี ASAN ก็ยังอาจเกิด memory corruption และ leak ได้

กลยุทธ์การเขียนใหม่: ทำทีเดียวแบบเชิงกล

  • โค้ด Zig เดิมของ Bun มี 535,496 บรรทัด ไม่รวมคอมเมนต์ และการเขียนใหม่แบบดั้งเดิมถูกประเมินว่าเป็นงานที่ทีมวิศวกรขนาดเล็กต้องใช้เวลาประมาณ 1 ปี
  • เพราะไม่สามารถหยุดแก้บั๊ก แก้ความปลอดภัย และพัฒนาฟีเจอร์เป็นเวลา 1 ปีได้ จึงเลือก การ port แบบเชิงกล ที่ลดการเปลี่ยนแปลงพฤติกรรมผู้ใช้ให้เหลือน้อยที่สุดเป็นแนวทางที่เสี่ยงต่ำที่สุด
  • ชุดทดสอบของ Bun เขียนด้วย TypeScript จึงไม่ขึ้นกับภาษาที่ใช้ implement runtime
  • การเขียนใหม่แบบ incremental ถูกมองว่าจะเจ็บปวดในระยะสั้นและกลาง เพราะต้องสร้างโค้ดชั่วคราวและหวังว่าจะลบทิ้งได้ภายหลัง จึงย้ายทั้งหมดในครั้งเดียว
  • โค้ด Rust ถูกเขียนให้ดูเหมือน transpile มาจากโค้ด Zig และเลือกแนวทางค่อย ๆ ลด unsafe หลัง Bun v1.4 พร้อม refactor ไปเป็น Rust ที่ idiomatic มากขึ้น

Dynamic workflow ของ Claude Code

  • ในการเขียนใหม่ด้วย Rust มี dynamic workflow ประมาณ 50 รายการใน Claude Code ที่รันต่อเนื่องเป็นเวลา 11 วัน
  • workflow ไล่ตั้งแต่การเขียนคู่มือการ port, แปลงไฟล์, แก้ compiler error, กู้คืน subcommand, ทำให้ชุดทดสอบทั้งหมดผ่าน ไปจนถึง cleanup ขนาดใหญ่
    • สร้างคู่มือการ port ที่ map pattern และ type ของ Zig ไปเป็น pattern และ type ของ Rust
    • port ไฟล์ .zig ทั้งหมดเป็นไฟล์ .rs แบบเชิงกลตาม PORTING.md และ LIFETIMES.tsv
    • แก้ compiler error แยกตาม crate
    • กู้คืนการทำงานของ subcommand เช่น bun test, bun build
    • ทำให้ชุดทดสอบทั้งหมดผ่าน
    • refactor และ cleanup ขนาดใหญ่
  • ตลอดเวลาส่วนใหญ่ คนอ่าน output ของ workflow เพื่อตรวจสอบปัญหาและบั๊ก พร้อมปรับ prompt เพื่อให้ Claude แก้ loop
  • เป็นงานเตรียมการ มีการหารือกับ Claude ประมาณ 3 ชั่วโมงเกี่ยวกับวิธี map pattern ใน codebase Zig ไปเป็น Rust และผลลัพธ์นี้ถูก serialize เป็น PORTING.md
  • เพื่อเพิ่ม lifetime ของ Rust ให้โค้ดจัดการหน่วยความจำด้วยตนเอง ได้รัน workflow ที่วิเคราะห์ lifetime ของทุก struct field
    • ค้นหา field ที่มี lifetime ซับซ้อน
    • เสนอ lifetime
    • agent reviewer เชิงปฏิปักษ์ 2 ตัวตรวจสอบ
    • นำ feedback มาปรับและบันทึกเป็น LIFETIMES.tsv

วิธีรีวิวแบบปฏิปักษ์

  • มี Claude ผู้รีวิวแบบปฏิปักษ์ แยกอยู่คนละ context window กับ Claude ที่ทำ implementation แต่ละตัว โดยผู้รีวิวได้รับคำสั่งให้ดูเฉพาะ diff และสมมติว่าโค้ดผิดเพื่อค้นหา bug
  • โครงสร้างพื้นฐานประกอบด้วยผู้ implement 1 คน, ผู้รีวิวแบบปฏิปักษ์อย่างน้อย 2 คน และ fixer 1 คน
  • bug ที่ผู้รีวิวจับได้จริงทั้งหมดเป็นโค้ดที่ compile ผ่าน แต่มีปัญหาด้านพฤติกรรม
    • uv_close เป็น asynchronous แต่ Box<uv::Pipe> ถูก drop ที่ท้าย match arm ทำให้ libuv ถือ freed memory อยู่ จนเกิด use-after-free และ double-free
    • ข้อผิดพลาดของ timespec ที่ทำให้เกิด nsec ติดลบ เมื่อใช้ trunc() กับ file time ค่าลบที่ไม่ใช่จำนวนเต็ม
    • ข้อผิดพลาดที่ unwrap_or ประเมิน argument แบบ eager ทำให้เกิด panic ในกรณีละเว้น percentage ของ color-mix()
  • เช่นเดียวกับการรีวิวโดยมนุษย์ มีการแยก context ของผู้เขียนกับผู้รีวิว เพื่อลด bias ที่อาจเกิดจากการที่ผู้ implement อยากให้ merge

การทำ port ขนาดใหญ่และ parallelization

  • ก่อนย้ายไฟล์ .zig ทั้งหมด 1,448 ไฟล์ ได้ตรวจสอบขั้นตอนกับไฟล์ 3 ไฟล์ก่อน
    • ผู้ implement 1 คนเขียนไฟล์ .rs
    • ผู้รีวิว 2 คนตรวจสอบว่าพฤติกรรมตรงกับ .zig และทำตาม PORTING.md, LIFETIMES.tsv หรือไม่
    • fixer 1 คนนำข้อเสนอไปปรับใช้
  • ช่วงต้นของการ port ไฟล์ทั้งหมด Claude หลายตัวรัน git stash, git stash pop, git reset HEAD --hard จนชนกันเอง
  • หลังจากนั้นจึงเพิ่มกฎใน workflow เพื่อห้าม git stash, git reset, คำสั่ง git ที่ไม่ใช่การ commit ไฟล์เฉพาะ และคำสั่งช้าอย่าง cargo
  • สุดท้ายใช้ workflow shard 4 ชุดและ worktree 4 ชุด โดยในแต่ละ shard มี Claude 16 ตัว commit และ push ไฟล์
  • ด้วย parallelization และการเตรียมการล่วงหน้า ช่วง peak Claude เขียนโค้ดได้ประมาณ 1,300 บรรทัดต่อนาที
  • commit ใน port branch ที่ไม่รวม merge มี 6,502 commit, ชั่วโมง peak มี 695 commits และ landed diff สุดท้ายคือ +1,009,272 บรรทัด
  • ยังมีปัญหาที่ไม่ได้เพิ่ม IOPS พื้นฐานของ EC2 instance ทำให้เพียง grep ช้า ๆ ครั้งเดียวก็ทำให้การอ่าน/เขียนดิสก์หยุดไปหลายนาที

ข้อผิดพลาด compile และการแยก crate

  • หลังจากเขียนโค้ดทั้งหมดแล้ว Claude workflow จึงแก้ compiler error
  • codebase Zig โดยพื้นฐานแล้วเป็น compilation unit เดียว ขณะที่โค้ด Rust ตั้งใจจะแบ่งเป็นประมาณ 100 crate เพื่อให้ compile เร็วขึ้น
  • ประเภทข้อผิดพลาดที่ยากที่สุดคือ circular dependency
    • แค่ PR แยก crate ก่อนการ rewrite เป็น Rust ยังไม่เพียงพอ
    • workflow แยกต่างหากทำหน้าที่จัดประเภทและบันทึกว่าโค้ดที่มี circular dependency ควรอยู่ที่ไหน
    • workflow อีกชุดทำ refactoring ดังกล่าว
  • หลังแก้ circular dependency แล้ว ก็เผยให้เห็น compiler error ประมาณ 16,000 รายการ
  • ข้อผิดพลาดเหล่านี้ถูกประมวลผลแบบขนานแยกตาม crate
    • รัน cargo check ในแต่ละ crate
    • จัดกลุ่ม output ตามไฟล์แล้วบันทึกไว้
    • แก้ compiler error ของ crate นั้น
    • ผู้รีวิวแบบปฏิปักษ์ 2 คนตรวจสอบการเปลี่ยนแปลง
    • fixer 1 คนนำการแก้ไขไปปรับใช้
  • เคยมี false start ที่ Claude ตีความ “ทำให้ทุก crate compile ได้” เป็นการสร้าง function stub
  • เมื่อเกิด pattern ที่พยายามใช้ comment อธิบายยาว ๆ เพื่อ justify workaround จึงเพิ่มกฎรีวิวว่า “ถ้าต้องใช้ comment ยาวระดับย่อหน้า แปลว่าโค้ดผิดและต้องแก้โค้ด”

กระบวนการจนทดสอบผ่าน

  • หลัง cargo check ผ่านแล้ว จึงแก้ link error, panic ทันทีหลังเริ่มต้น, การรัน bun --version, bun test <file> ตามลำดับ
  • ใช้ workflow ที่บันทึก stacktrace ความล้มเหลวของแต่ละ CLI subcommand เป็นไฟล์ แล้วแก้ผ่าน loop ผู้ implement·ผู้รีวิว·fixer
  • workflow สำหรับไฟล์ทดสอบ shard ไฟล์ทดสอบแบบสุ่มประมาณ 100 ไฟล์ไปยัง worktree 4 ชุด และบันทึก stacktrace กับ error ของแต่ละ failure เพื่อแก้ไข
  • test suite มีการทดสอบ memory leak และ integration test ที่อาจ timeout ใน debug build
    • การทดสอบที่รัน next dev และตรวจว่า hot module reloading ตรวจพบการเปลี่ยนแปลง 100 ครั้ง
    • stress test ที่ใช้จำนวน TCP socket จนถึงขีดจำกัดสูงสุด
    • การทดสอบอ่าน/เขียนดิสก์ระดับกิกะไบต์
    • การทดสอบที่ spawn process ประมาณ 10,000 process
  • เพื่อ isolation จึงใช้ systemd-run และ cgroups จำกัดการใช้ memory/CPU และแยก pid namespace
  • ถึงอย่างนั้นเครื่องก็ crash หลายครั้งเพราะพื้นที่ดิสก์ไม่พอ
  • สองวันหลัง CI ครั้งแรก จำนวนไฟล์ทดสอบที่ล้มเหลวลดจาก 972 เหลือ 23 และอีกหนึ่งวันครึ่งหลังจากนั้น Linux ก็ green ทั้งหมด
  • สุดท้าย CI test ทั้งหมดผ่านครบ 6 แพลตฟอร์ม
    • macOS x64
    • macOS arm64
    • Linux x64
    • Linux arm64
    • Windows x64
    • Windows arm64
  • หลังทดสอบผ่าน 100% มนุษย์ตรวจด้วยตนเองว่าการทดสอบถูกรันจริงและไม่ได้ถูก skip แล้วจึง merge
  • จุดที่ merge เข้า main ยังไม่ใช่ versioned release และยังไม่มั่นใจพอที่จะ release แต่เป็นระดับความมั่นใจที่พอจะทุ่มเทกับ rewrite ต่อได้

ขนาดและต้นทุนการทดสอบ

  • ในช่วง 11 วัน ตั้งแต่ May 3 ถึง merge วันที่ May 14 มีการสร้าง 6,778 commits
  • test ไม่ได้ถูกลบหรือ skip
  • ขนาดการทดสอบแยกตามแพลตฟอร์มมีดังนี้
    • Debian 13 x64: expect() 1,386,826 ครั้ง, test 60,624 รายการ, ไฟล์ 4,174 ไฟล์
    • macOS 14 arm64: expect() 1,259,953 ครั้ง, test 58,850 รายการ, ไฟล์ 4,175 ไฟล์
    • Windows 2019 x64: expect() 1,007,544 ครั้ง, test 57,337 รายการ, ไฟล์ 4,173 ไฟล์
  • งานก่อน merge ใช้ uncached input token 5.9 พันล้าน, output token 690 ล้าน และ cached input token read 72 พันล้าน
  • คิดตามราคา API มีค่าใช้จ่ายประมาณ 165,000 ดอลลาร์
  • ประเมินว่าถ้ามนุษย์ทำเอง วิศวกร 3 คนที่มี context ของ codebase ทั้งหมดน่าจะใช้เวลาประมาณ 1 ปี
  • model ที่ใช้คือ pre-release Claude Fable 5 และมี disclosure ว่า Bun ถูก Anthropic เข้าซื้อในเดือนธันวาคม 2025

รีวิวความปลอดภัย, fuzzing และสถานะของ unsafe

  • หลัง merge port Rust แล้ว ได้ทำ security review 11 รอบ ด้วย Claude Code Security และจัดการ findings แล้ว
  • เพิ่ม fuzzing แบบ coverage-based ตลอด 24/7 ให้กับ parser ทั้งหมดของ Bun
    • JavaScript
    • TypeScript
    • JSX
    • CSS
    • JSON5
    • JSONC
    • TOML
    • YAML
    • Markdown
    • INI
    • Bun Shell scripts
    • semver ranges
    • ไฟล์ .patch
    • CSS colors
  • fuzzer ส่ง bug ที่พบไปให้ Claude เพื่อส่ง PR ที่รวมการ reproduce และการแก้ไข ส่วนมนุษย์รีวิว PR
  • จนถึงตอนนี้ parser ถูก execute ไปแล้ว 100,000 ล้านครั้ง และนำไปสู่ PR ประมาณ 15 รายการ
  • ณ เวลาที่เขียน โค้ด Rust ประมาณ 4% อยู่ใน unsafe block
    • keyword unsafe ประมาณ 13,000 รายการ
    • ประมาณ 27,000 บรรทัด / จากทั้งหมดประมาณ 780,000 บรรทัด
    • 78% ของ unsafe block เป็นแบบบรรทัดเดียว และเป็น pointer ที่มาจาก C++ หรือการเรียก C library
  • ระบุว่าเพราะยังใช้ library C/C++ อย่าง JavaScriptCore ต่อไป unsafe จึงจะมากกว่าโปรเจกต์ Rust ล้วนเสมอ

Regression ที่พบหลังเปลี่ยนมาใช้ Rust

  • Rust rewrite เป็นการเปลี่ยนแปลงครั้งใหญ่ จึงทำให้เกิด regression ที่ทราบแล้ว 19 รายการ และทั้งหมดได้รับการแก้ไขแล้ว
  • ส่วนใหญ่เกิดจากโค้ดที่ไวยากรณ์ของทั้งสองภาษาคล้ายกัน แต่ความหมายต่างกัน
  • side effect ภายใน debug_assert!

    • assert ของ Zig เป็นฟังก์ชัน ดังนั้น argument จะถูกเรียกใช้ในทุก build
    • debug_assert! ของ Rust เป็น macro ดังนั้นใน release build นิพจน์ทั้งหมดจะถูกลบออก
    • การเรียก insert_stale หายไปใน release build ทำให้เคส HMR บางกรณีของโปรเจกต์ HTML route ที่ใช้ React พัง
    • issue ที่เกี่ยวข้อง: #30678
  • slice ที่มีความยาวเป็นเลขคี่

    • Zig helper reinterpretSlice(u16, bytes) ของ Bun ใช้ @divTrunc จึงละเว้น trailing odd byte
    • bytemuck::cast_slice ของ Rust จะ panic เมื่อความยาวเป็นเลขคี่
    • มี regression ที่ Blob.text() ซึ่งมีไบต์เลขคี่ตามหลัง UTF-16 BOM ไม่คืนค่า string แต่ทำให้ process panic
    • การแก้ไขคือกลับไปละเว้น odd byte ด้วย &buf[..buf.len() & !1]
    • issue ที่เกี่ยวข้อง: #31188
  • Bounds checks

    • โค้ด Zig บน macOS และ Linux ถูกคอมไพล์ด้วย ReleaseFast ทำให้ bounds check ถูกลบออก ส่วน Rust release build ยังคง bounds check ไว้
    • ขนาด overflow block ของ Bun module resolver ยังเป็น placeholder 64 อยู่ ทำให้ ceiling ลดจาก 8.4 ล้าน interned filenames เหลือ 270,272
    • ptrs[4095] ที่ port มาเกิด off-by-one และกลายเป็นเคสที่โปรเจกต์จริงเข้าถึงได้ โดย Rust จะ panic แทนการเขียนออกนอกขอบเขต
    • issue ที่เกี่ยวข้อง: #31503
  • format strings แบบ comptime

    • Output.pretty ของ Zig มี fmt เป็น comptime ดังนั้น color marker อย่าง <r>, <d> จะถูกแปลงเป็น ANSI escape ก่อนแทนที่ argument
    • ฟังก์ชัน Rust ไม่มี comptime parameter จึงประมวลผล marker ใน string ที่เสร็จแล้ว และ rewrite ไปถึง argument อย่างผิดพลาด
    • ใน bun update -i การจบ OSC 8 hyperlink ชนกับ trailing <r> marker ทำให้ r ถูกพิมพ์ออกมาเป็นข้อความ
    • ใน Rust จำเป็นต้องใช้ macro bun_core::pretty!("<r>{}<r>", hyperlink)
    • issue ที่เกี่ยวข้อง: #30693

บั๊กและ memory leak ที่แก้ไขแล้ว

  • Bun v1.4.0 แก้ไข 128 บั๊ก ที่ reproduce ได้ใน v1.3.14
  • ครอบคลุมตั้งแต่ memory leak, crash ไปจนถึง help text ที่ลงสีผิด
  • Drop ของ Rust จะเรียกฟังก์ชัน drop โดยอัตโนมัติเมื่อค่าออกนอก scope
  • ใน Zig ต้องเพิ่ม defer ในแต่ละ call site จึงเกิดการลืม cleanup หรือ cleanup ซ้ำได้ง่าย
  • Drop ของ Rust เป็นการเลือกยอมรับ hidden control flow เพื่อแลกกับการลด footgun ที่พบบ่อย
  • Drop แก้ไข memory leak ที่เกี่ยวกับ file path ใน error handling code ได้หลายจุด
  • การผสานรวม LeakSanitizer ของ Bun ได้รับการปรับปรุง ทำให้ติดตาม native code memory allocations ทั้งหมดได้
  • instrumentable memory leak ทั้งหมดได้รับการแก้ไขแล้ว
  • ปรับปรุง leak ใน Bun.build()

    • ใน Bun v1.3.14 เดิม การเรียก Bun.build() แบบ in-process แต่ละครั้งทำให้ parsed source text และ AST symbol table มีอายุอยู่นานกว่าอายุของ build และ leak ทีละหลาย MB
    • ในการทดสอบที่ bundle โปรเจกต์ 60-module เดิม 2,000 ครั้งใน process เดียว v1.3.14 leak ต่อเนื่องประมาณ 3MB ต่อ build
    • ใน Bun v1.4.0 การใช้หน่วยความจำทรงตัว
    • | Builds | Bun v1.3.14 | Bun v1.4.0 |
    • | --- | ---: | ---: |
    • | 500 | 1,914 MB | 526 MB |
    • | 1,000 | 3,506 MB | 586 MB |
    • | 1,500 | 5,097 MB | 608 MB |
    • | 2,000 | 6,745 MB | 609 MB |

ขนาด binary, การใช้ stack และประสิทธิภาพ

  • แค่การเปลี่ยนแปลงช่วงต้นของ Rust rewrite ก็ทำให้ขนาด binary ลดลง
    • Windows: ลดลง 3.8 MB
    • macOS: ลดลง 5.5 MB
    • Linux: ลดลง 6.8 MB
  • สาเหตุหลักคือการใช้ comptime มากเกินไปในโค้ด Zig
  • หลังจากนั้นยังมีการใช้ Identical Code Folding, ลบ unused data ของ ICU และทำให้บางส่วนของ libicu ถูกคลายการบีบอัดแบบ lazy ด้วย zstd dictionary
  • เมื่อนำ Rust rewrite, การเปลี่ยนแปลง ICU และ identical code folding มารวมกัน ขนาด binary ของ Bun บน Linux และ Windows ลดลงประมาณ 20%
Version Platform Size
Bun v1.4.0 canary Windows 76 MB
Bun v1.3.14 Windows 94 MB
Bun v1.4.0 canary Linux 70 MB
Bun v1.3.14 Linux 88 MB
  • TOML parser และ recursive-descent parser ของ Bun ใช้ stack space น้อยลง
  • LLVM IR codegen ของ Rust ปล่อย intrinsic llvm.lifetime.start และ llvm.lifetime.end ให้กับ stack variable ทำให้ LLVM สามารถนำ stack slot กลับมาใช้ซ้ำได้
  • ก่อนหน้านี้ต้อง refactor ฟังก์ชันขนาดใหญ่เป็นฟังก์ชันเล็กหลายตัวด้วยมือ โดยเฉพาะเพื่อเลี่ยง open issue ของ Zig
  • Rust รองรับ cross-language link-time optimization ระหว่าง C/C++ กับ Rust ทำให้สามารถ inline ข้ามภาษาได้
  • benchmark บน Linux x64

    • เปรียบเทียบ Bun v1.3.14 กับ Bun v1.4.0 บน Linux x64 EC2 Xeon Platinum 8488C
    • วัด HTTP throughput ด้วย oha และ app workload ด้วย hyperfine
    • | server | Bun v1.3.14 | Bun v1.4.0 | Δ |
    • | --- | ---: | ---: | ---: |
    • | Bun.serve | 169.6k req/s | 177.7k req/s | +4.8% |
    • | node:http | 103.8k req/s | 108.5k req/s | +4.5% |
    • | Elysia | 158.9k req/s | 163.3k req/s | +2.8% |
    • | express | 64.5k req/s | 66.6k req/s | +3.2% |
    • | fastify | 91.5k req/s | 95.9k req/s | +4.8% |
    • | workload | Bun v1.3.14 | Bun v1.4.0 | Δ |
    • | --- | ---: | ---: | ---: |
    • | next build | 13.62 s | 13.03 s | +4.5% |
    • | vite build | 1.69 s | 1.65 s | +2.2% |
    • | tsc -b --force | 0.94 s | 0.89 s | +4.7% |

กรณีการใช้งานจริงและสถานะการเผยแพร่

  • Prisma เปิดตัว public beta ของ Prisma Compute บน Rust rewrite ของ Bun
  • ฝั่ง Prisma ระบุว่าได้ทดสอบ failure mode อย่าง connection pool ที่ไม่สามารถกู้คืนได้หลัง VM pause/resume และ memory leak บน Rust rewrite แล้ว และสามารถจัดการ failure mode ดังกล่าวได้ดี
  • Claude Code v2.1.181 และเวอร์ชันหลังจากรีลีสวันที่ 17 มิถุนายน ใช้ Bun ที่พอร์ตเป็น Rust
  • Linux startup ของ Claude Code เร็วขึ้น 10% และนอกเหนือจากนั้น ผู้ใช้ส่วนใหญ่แทบไม่สังเกตเห็นความแตกต่าง
  • Bun v1.3.14 เป็น Bun เวอร์ชันสุดท้ายที่เขียนด้วย Zig
  • Bun v1.4.0 เป็น Bun เวอร์ชันแรกที่เขียนด้วย Rust และให้ใช้งานในรูปแบบ canary

เครื่องมือที่ทีมได้รับและงานที่ยังเหลือ

  • codebase Rust ใหม่ยังคงมีรูปแบบใกล้เคียงกับ codebase Zig เดิมมาก
  • เขียนขึ้นเพื่อให้คนที่เข้าใจโค้ด Zig เดิมสามารถเข้าใจโค้ด Rust ที่แปลแบบเชิงกลได้เช่นกัน
  • การรีวิว PR ของ Rust rewrite ดำเนินไปโดยตรวจสอบว่า adversarial review agent สามารถจับความไม่สอดคล้องระหว่าง Zig กับ Rust การปฏิบัติตาม porting guide และ lifetime guide ได้อย่างถูกต้องหรือไม่ และให้คนอ่านโค้ดจำนวนมากแบบ side-by-side
  • Bun v1.4 ทำให้ Bun เร็วขึ้น เล็กลง ใช้หน่วยความจำน้อยลง และมอบเครื่องมือสำหรับการปรับปรุงเสถียรภาพ
    • Rust borrow checker
    • Miri
    • LeakSanitizer
    • coverage-guided fuzzing ตลอด 24/7 สำหรับ parser
  • ยังมีส่วนที่ต้อง refactor เหลืออยู่ และมีการเชื่อมต่อ bun-unsafe-audit
  • วิศวกรหนึ่งคนเฝ้าติดตาม Fable และ Claude Code อย่างใกล้ชิด จนไปถึงสถานะที่ test suite ทั้งหมดผ่านบนทุกแพลตฟอร์มได้ภายในเวลาเพียง 11 วัน

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

 
GN⁺ 2 일 전
ความคิดเห็นจาก Hacker News
  • บทความนี้แสดงให้เห็นค่อนข้างชัดว่าการเขียนใหม่อัตโนมัติต้องอาศัย วินัยและความระมัดระวัง และมีมนุษย์เข้ามาแทรกแซงอยู่ ให้ความรู้สึกว่าทำอย่างตั้งใจที่สุดเท่าที่จะทำได้ด้วย AI
    แยกอีกประเด็นหนึ่งคือก็ยังไม่ค่อยเข้าใจว่าทำไมในปี 2026 ถึงยังไม่เลือกใช้ภาษาที่ ปลอดภัยด้านหน่วยความจำ และถ้าเป็นไปได้ก็ควรปลอดภัยจาก race condition ด้วย
    Rust ให้สิ่งนั้นพร้อมประสิทธิภาพไปด้วย ดังนั้นถ้าไม่ชอบ garbage collection หรือ immutability เพราะเหตุผลด้านประสิทธิภาพ ก็ยังมีตัวเลือกคือ Rust
    เข้าใจได้ถ้าต้องการประสิทธิภาพสูงสุดแบบถึงที่สุดจนต้องลงไปใช้ C++ หรือเป็นเรื่องความชอบส่วนตัว แต่กรณีอื่นนอกจากนั้นก็ดูแทบจะเป็นตัวเลือกที่ชัดเจนอยู่แล้ว

    • คอมไพเลอร์ Rust ช้ามาก วิธีที่ดีที่สุดในการทำให้เร็วขึ้นดูเหมือนจะเป็นการแยกโค้ดเบสออกเป็นหลาย crate ซึ่งสำหรับหลายคนไม่ใช่ประสบการณ์การพัฒนาที่ดี
      นอกจากนี้ ในหลายปัญหา garbage collector ก็ช่วยกำจัดบั๊กจำนวนมากได้แบบแทบไม่เพิ่มแรงเสียดทาน รวมถึงบั๊กที่บทความนี้พูดถึงด้วย แต่ Rust บังคับให้คุณต้องคิดผ่านมุมมองของ ownership
      ตัวอย่างเช่น นักพัฒนาเกมจำนวนมากชอบทำงานแบบวนรอบอย่างรวดเร็วด้วยภาษาที่มีแรงเสียดทานต่ำ โค้ดเกมก็จุกจิกพอๆ กับโค้ด UI ฝั่งฟรอนต์เอนด์ และขั้นตอน build ก็อาจมีความเฉพาะตัว รวมถึงมักวนรอบด้วย hot reloading
      การบอกให้ใช้คอมไพเลอร์ที่ช้า ก็เท่ากับให้ยอมรับ latency ในรอบการทำงานแบบนั้นมากขึ้น แน่นอนว่าไม่ได้หมายความว่าเหตุผลพวกนี้ใช้ได้กับทุกคน
    • บอกว่ามี “การแทรกแซงของมนุษย์” ฟังดูย้อนแย้งดี ถ้าเป็นโปรเจ็กต์ที่ประสบความสำเร็จในการกำจัด การแทรกแซงของมนุษย์ ทั้งในอดีตและอนาคต
    • ผู้คนย่อมผูกพันกับสิ่งที่ใช้กันมาหลายสิบปี อีกทั้งโลกส่วนใหญ่ก็ยังเขียนด้วย C/C++ ดังนั้นถ้าจะให้ถึงจุดวิกฤตที่ยอมรับกันในวงกว้าง ก็มีสิ่งที่ต้องฝ่าอีกมาก
      Rust ไม่ได้สมบูรณ์แบบ แต่แก้กับดักของ C++ ได้หลายอย่าง ไม่ใช่แค่ undefined behavior แต่รวมถึง package management, ไฟล์ CMake สุดโหด, และ linker error ด้วย
    • จาก Rust ไป C++ ดูเป็นตัวเลือกที่แปลก เพราะได้ปัญหาแทบจะชุดเดิมแต่เสีย ความปลอดภัยด้านหน่วยความจำ ไป
      ถ้าเป็น Zig, Odin, C3 หรือแม้แต่ C รุ่นเก่า อย่างน้อยก็ยังมีข้อดีบางอย่างที่ทั้ง Rust และ C++ ไม่ได้ให้ ต่อให้ข้อดีนั้นเป็นแค่ความเร็วในการคอมไพล์ก็ตาม
    • ทุกครั้งที่เห็น พื้นที่ดิสก์ ที่ต้องใช้สำหรับ build Rust ก็ยังตกใจอยู่ ถ้าจำไม่ผิด การคอมไพล์ Zed ใช้เกิน 50GB
  • ประเด็นสำคัญคือวิธีนี้ถูกกว่าการจ้างทีมวิศวกรรมซอฟต์แวร์มาก ต่อให้จ้างผมด้วยเงิน 200,000 ดอลลาร์ ผมก็คงทำสิ่งนี้ไม่สำเร็จภายใน 1 ปี
    เพราะไม่มีบริบทอะไรเลย และก็ไม่รู้ทั้ง Zig หรือ Rust แม้จะเรียนรู้ได้ภายใน 1 เดือน แต่ก็คงช้ามาก
    ต่อให้ไม่นับคำทำนายแนวเอกฐาน ตอนนี้แค่ AI ในปัจจุบันก็กำลังทำให้การจ้าง วิศวกรซอฟต์แวร์ระดับ 200,000 ดอลลาร์ ถูกให้เหตุผลได้ยากขึ้น
    ในพื้นที่บนสุดของบริษัทที่ขับเคลื่อนด้วยซอฟต์แวร์อย่าง Google หรือ Anthropic ก็คงยังจ้างวิศวกรเก่งมากที่สร้างซอฟต์แวร์ใหม่ซึ่ง AI ยังทำได้ไม่ดีต่อไป แต่สำหรับบริษัทอย่าง Walmart หรือ Target ที่ซอฟต์แวร์เป็นแค่ศูนย์ต้นทุน หรือบริษัทที่เอางานพัฒนาไป outsource อยู่แล้วหรือใช้แรงงาน H1B ราคาถูก ตอนนี้เริ่มมีทางเลือก AI ที่ดีกว่าวิศวกรระดับกลางอย่างมาก
    นักพัฒนาซอฟต์แวร์ราว 1.6 ล้านคนในสหรัฐมีแนวโน้มจะลดลงมาก กลุ่มระดับท็อปอย่าง L6 ของ FAANG คงยังอยู่ได้ แต่พวกนักพัฒนาเฉลี่ยๆ ในธนาคารที่ไม่มีใครรู้จัก หรือคนที่ทำเว็บไซต์ McDonalds คงต้องไปเรียนอย่างอื่น ไม่อย่างนั้นก็อาจตกงานในไม่ช้า
    เมื่อ 1 ปีก่อนผมคงไม่ได้ทำนายแบบนี้ แต่ตอนนี้ดูชัดเจนแล้วว่าการเปลี่ยนแปลงลักษณะนี้จะเกิดขึ้น

    • “ในเศรษฐศาสตร์ Jevons paradox คือเมื่อความก้าวหน้าทางเทคโนโลยีที่ทำให้ใช้ทรัพยากรได้อย่างมีประสิทธิภาพมากขึ้น กลับทำให้การบริโภคทรัพยากรนั้นโดยรวมเพิ่มขึ้นแทนที่จะลดลง เมื่อประสิทธิภาพสูงขึ้น ปริมาณทรัพยากรที่ต้องใช้ต่อการใช้งานหนึ่งครั้งจะลดลง ทำให้ต้นทุนที่แท้จริงต่ำลง และหากอุปสงค์มีความยืดหยุ่นต่อราคามากพอ อุปสงค์ที่ถูกกระตุ้นขึ้นมาก็มักทำให้การใช้ทรัพยากรโดยรวมเพิ่มขึ้นสุทธิ”
      https://en.wikipedia.org/wiki/Jevons_paradox
    • ก็ยังถกเถียงกันได้เต็มที่ว่า วิศวกรที่มีต้นทุน 200,000 ดอลลาร์ ที่เหมาะกับงานนี้ จะสร้างมูลค่าที่มากกว่าไม่ได้จริงหรือ
      อีกทั้งยังถกเถียงได้ว่างานนี้สร้างคุณค่าจริงหรือไม่ ใครก็ตามที่เคยใช้ทั้ง unsafe Rust และ Zig จะรู้ว่า unsafe Rust อันตรายกว่ามากเมื่อเทียบกัน
    • ผมไม่ได้มองแง่ร้ายขนาดนั้น ยังมีสิ่งที่ทำได้อีกไม่จำกัด ก่อนหน้านี้คงไม่มีใครคิดจะเสนอให้เขียนโปรเจ็กต์ใหม่ด้วย Rust แบบจริงจังด้วยซ้ำ
      มันไม่ได้แทนที่งานจริงๆ ของใคร และสุดท้ายถ้าจะทำสิ่งนี้ให้สำเร็จก็ยังต้องจ้าง วิศวกรค่าตัวสูง อยู่ดี
      แทนที่จะจ้างคนน้อยลง ผมคิดว่ามันน่าจะทำให้เกิดการแก้โค้ดมากขึ้น
    • ผมกลับมองตรงกันข้าม การเปลี่ยนแปลงที่ กว้างขวาง แบบนี้มอบหมายให้เฉพาะวิศวกรอาวุโสได้เท่านั้น
      ตอนนี้จึงมีโอกาสมากขึ้นที่จะอยากจ้างวิศวกรอาวุโสที่สามารถทำการเปลี่ยนแปลงแบบนี้ได้จริงเพิ่ม
    • ไม่ใช่แค่นั้น ส่วนใหญ่รวมถึงผู้เขียนเองก็คงไม่คิดว่านี่จะเป็นไปได้จริง
      ไม่เพียงแต่เวลาและต้นทุนที่ใช้จะต่ำกว่าที่หลายคนคาด แต่ยังทำให้คาดได้ด้วยว่าในไม่ช้า ปฏิสัมพันธ์ของมนุษย์ ความผิดพลาด เวลา และต้นทุนแบบนี้ อาจลดลงได้อีก 2 เท่า 5 เท่า หรือแม้แต่เกิน 10 เท่า
      และควรคำนึงด้วยว่าบล็อกโพสต์นี้เองก็ทำหน้าที่เป็น สื่อโปรโมตให้ Claude และ LLM โดยรวม ด้วย
  • ต่อให้ไม่ถกกันถึงตัวโปรเจกต์ Bun หรือธรรมชาติของการเขียนใหม่ก็ตาม ถ้าเพียงแค่เขียนใหม่แบบตรงไปตรงมาโดยออกจาก Zig ก็แก้ memory leak ได้ ทำให้เสถียรขึ้น ลดขนาดไบนารีลง 20% และเพิ่มประสิทธิภาพได้ 5% มันก็ดูไม่ค่อยเป็นผลดีกับ Zig

    • ผมคิดว่าการจัดสิ่งนี้เป็น “การเขียนใหม่แบบตรงไปตรงมาที่ออกจาก Zig” นั้นไม่ยุติธรรม Jarred คลุกอยู่กับโปรเจกต์นี้อย่างลึกซึ้งมา 5 ปี ใช้ทุกอย่างที่เรียนรู้มาระหว่างทาง และยังทุ่ม โทเคนมูลค่า 165,000 ดอลลาร์ ไปกับ coding LLM ที่ล้ำหน้าที่สุดซึ่งทุกคนเข้าถึงได้
      ถ้าเอา Fable มารันกับเวอร์ชัน Zig มูลค่า 165,000 ดอลลาร์ ก็น่าจะมีโอกาสได้ประสิทธิภาพเพิ่ม 5% เหมือนกัน
    • หวังว่า Zig จะไม่ตอบบทความบล็อกนี้แบบเป็นปฏิปักษ์ แต่อย่างน้อยในอนาคตของ Zig ก็น่าจะมีเครื่องมือและการตรวจสอบจากคอมไพเลอร์ที่ดีกว่านี้ ซึ่งช่วยแก้หรือย้ายปัญหาพวกนี้ไปได้มากพอสมควร
      มีการพูดกันมาค่อนข้างนานแล้วว่า Rust และ LLM เป็นคู่ที่เข้ากันได้ดี ความฝืดหลายอย่างของภาษาถูกทำให้ลื่นขึ้นได้ด้วยการเขียนโปรแกรมแบบมี LLM ช่วย
    • ผมคิดว่าคนที่ตั้งใจจะใช้ Zig เข้าใจดีว่าสิ่งเหล่านี้เป็น ปัญหาระดับโปรเจกต์ ไม่ใช่ปัญหาระดับภาษา
    • ก็จริง แต่บ่อยครั้งการเขียนใหม่เองก็มอบข้อดีแบบนี้อยู่แล้ว ต่อให้เขียนใหม่ด้วย Zig ก็อาจได้การปรับปรุงบางส่วนแบบเดียวกัน
    • ผมให้ความสนใจกับคนที่ตัดสินใจยาก ๆ จากบทเรียนที่เจ็บจริง ประมาณว่าคนส่วนใหญ่ที่ใช้ ORM แค่เคยได้ยินมาหรือไม่ก็ไม่อยากเรียน SQL แต่ คนที่ถอด ORM ออก มักเป็นคนที่เคยเจอความสยองด้วยตัวเอง
  • ผมไม่ได้ติดใจที่เอา AI มาใช้ในการเขียน Bun ใหม่เป็น Rust เอง ต่อให้ 1.4 จะยังไม่ดีพอ ตอนเวลาผ่านไปมันก็น่าจะดีขึ้นได้
    สิ่งที่ผลักผมกลับไปหา Node คือการจัดการช่วงเปลี่ยนผ่านที่ดูสมัครเล่นเกินไป
    เวอร์ชัน Zig ไม่มีการรองรับ LTS สำหรับ CVE และเรื่องทำนองนั้น แถมยังปล่อยบั๊กใหญ่ ๆ อย่าง memory leak 3MB ที่ยกในบทความบล็อกค้างไว้ในเวอร์ชัน Zig จนทำให้ถ้าอยากแก้แอป production จริง ๆ ก็แทบถูกบังคับให้ไปใช้เวอร์ชัน Rust อีกทั้งยังไม่มีการมีส่วนร่วมกับชุมชน Bun เลยในเรื่องการตัดสินใจสำคัญแบบนี้
    วันหนึ่งยังพูดว่า “อย่าสร้างดราม่า แค่ลองเล่นอยู่” แล้วไม่กี่วันต่อมาก็กลายเป็น “YOLO, merge เข้า main”
    Jarred ยังดำเนินทุกอย่างเหมือนเป็น แฮกเกอร์เดี่ยว ที่ทำโปรเจกต์ส่วนตัวของตัวเองอยู่

    • การไม่มี LTS รองรับ CVE และเรื่องคล้ายกันสำหรับเวอร์ชัน Zig หมายความว่าแต่ละรีลีสน่าจะมี CVE โผล่มาเพียบและต้องใช้แรงมหาศาล
      อย่างเช่นตัวอย่างปัญหาหน่วยความจำในบล็อกนั่นแหละ ในมุมความปลอดภัย ผมว่าควรมองว่าเวอร์ชัน Zig เหมือนไม่มีอยู่ดีกว่า ใช้ก็ต้องรับความเสี่ยงเอง
      ส่วนเรื่องที่ Jarred บริหารเหมือนโปรเจกต์ส่วนตัว อย่างน้อยพวกเขาก็มีสิทธิ์ทำแบบนั้น โดยเฉพาะถ้าเป็นบริษัทเจ้าของอยู่ ก็เป็นเรื่องที่คาดเดาได้
    • ลูกค้าที่จ่ายเงินจะได้ LTS แล้วมีลูกค้าที่จ่ายเงินคนไหนเรียกร้อง LTS สำหรับ branch Zig หรือเปล่า? หรือกำลังคาดหวังแรงงานฟรีจากผู้ดูแลโอเพนซอร์สโดยไม่มีเหตุผลพิเศษ?
    • ถ้า 1.4 ไม่ได้สร้าง breaking change จาก 1.3 แล้วทำไมต้องมี LTS และการรับประกัน สำหรับคนที่จะค้างอยู่ที่ 1.3 ด้วย? เท่าที่ผมเห็น regression ที่รู้กันทั้งหมดก็ถูกแก้เหมือนรีลีสอื่น ๆ แล้ว
    • LTS จะเกี่ยวข้องกว่าตอนที่ความเข้ากันได้พัง ตอนนี้ 1.4 ยังไม่ได้รีลีสเลยด้วยซ้ำ และจากทุกตัวชี้วัดในสนามจริงก็ดูเหมือนดำเนินไปได้ดีมาก มีคนจำนวนมากใช้เขียนงานด้วย Claude Code มาหนึ่งเดือนแล้วโดยไม่มี regression
      ผมไม่เห็นอะไรที่พอจะเรียกว่าประมาทได้
      ตรงกันข้าม เขาถึงกับให้ Claude สองอินสแตนซ์ในบทบาทผู้ตรวจทานเชิงปฏิปักษ์มาประกบทุกการเปลี่ยนโค้ด ทุกบรรทัด มีมนุษย์ทีมไหนที่ทำรีวิวอิสระสองรอบกับทุกบรรทัดบ้าง? นอกจากคนที่เขียนซอฟต์แวร์กระสวยอวกาศ ผมไม่รู้จักเลย
      memory leak ก็ถูกแก้แล้ว แล้วมันสำคัญตรงไหนว่าเขียนด้วยภาษาอะไร? สุดท้ายคนก็ใช้ Bun เพื่อรันโค้ด TypeScript และอย่างอื่น
      ผู้ใช้ Bun สนใจแค่ไหนว่า Bun เขียนด้วย Zig? สำหรับผมคือไม่เลย ผมใช้ Bun มา 2 ปี เพิ่งเคยไปค้นดู Zig แค่ครั้งเดียว มันไม่เกี่ยวอะไรเลย
      มันเสถียรกว่าเดิมไหม? ใช่ มันเล็กลงไหม? ใช่ มันเร็วขึ้นไหม? ใช่ มีหลักฐานไหมว่ามันปลอดภัยน้อยลง? ไม่มี โค้ดเปิดให้ดูมาสองเดือนแล้ว ถึงตอนนี้พวกคัดค้านควรหา smoking gun ได้แล้ว แต่ก็หาไม่ได้
      ยังต้องการหลักฐานอีกเท่าไรว่าเรื่องนี้คือความสำเร็จครั้งใหญ่?
      นี่คือ ความเป็นจริงแบบใหม่ เอเจนต์เก่งพอจนเราเข้ามาอยู่ในขอบเขตที่โปรเจกต์แบบนี้ทำได้แล้ว และนั่นก็น่าสนใจ
  • “การเขียนใหม่เป็น Rust นี้เป็นงานที่ตามปกติคงใช้เวลาทีมวิศวกรที่เข้าใจบริบทของโค้ดเบสทั้งหมด 1 ปี แต่เมื่อใช้ Fable และมีวิศวกร 1 คนคอยเฝ้าดู Claude Code อย่างใกล้ชิด ใช้เวลาเพียง 11 วันตั้งแต่เริ่มจนชุดทดสอบผ่าน 100% บนทุกแพลตฟอร์ม”
    ในเชิงเทคนิคก็น่าประทับใจ แต่ก็แอบมองข้ามข้อเท็จจริงที่ว่าถ้า Bun ไม่ได้เป็นส่วนหนึ่งของ Anthropic มันจะมีค่าโทเค็น 165,000 ดอลลาร์
    การเปรียบเทียบนี้ไม่ได้ยุติธรรมทั้งหมดนัก ถ้าตั้งต้นว่าค่าใช้จ่ายส่วนเพิ่มเป็น 0 ดอลลาร์ ก็แปลว่าทีมเล็กคงต้องใช้เวลา 1 ปีในการพอร์ต
    อยากเห็นการเทียบระหว่างการจ่าย 165,000 ดอลลาร์ให้ Claude ใน 11 วัน กับการเอาเงินก้อนนั้นไปแบ่งให้คน 50 คนช่วยเขียนโค้ด Zig ใหม่ทีละบรรทัด คิดว่า Claude น่าจะเร็วกว่าและจึงถูกกว่า แต่ส่วนต่างอาจไม่ได้มหาศาลขนาดนั้น

    • คำนวณคร่าวๆ ได้ไม่ยากเลย คนหนึ่งทำงานประมาณ 250 วันต่อปี และถ้าสมมติเงินเดือนระดับ Bay Area ต้นทุนรวมแบบอนุรักษ์นิยมก็น่าจะราว 300,000 ดอลลาร์ต่อปี
      ก็ตกวันละ 1,200 ดอลลาร์
      50 คน * 11 วัน เท่ากับ 660,000 ดอลลาร์ ซึ่งเป็น 4 เท่าของค่า Claude
      แถมยังตั้งสมมติฐานว่าคน 50 คนนั้นจะไม่ติดขัด ไม่เหยียบเท้ากันเอง และไม่มีปัญหาเรื่องการประสานงานด้วย ความซับซ้อนในการประสานงานอย่างเดียวก็มหาศาลแล้ว
      ถึงจะไม่ชอบเท่าไร แต่ในกรณีนี้ Claude ชนะขาด ไม่ใช่แบบเฉือนกันนิดเดียว
    • แค่การประสานงานคน 50 คนให้ทำงานร่วมกันอย่างมีความหมายก็น่าจะกินเวลาอย่างน้อย 11 วันแล้ว
    • ดูเหมือนว่าความต่างหลักคือผู้ลงมือทำที่เป็น AI อาจถูกกว่า เร็วกว่า และในทางปฏิบัติอาจ ดีกว่าอย่างสม่ำเสมอ ได้ด้วย แต่จะให้มนุษย์ชุดเดิมทำได้แบบนั้นเป็นเรื่องยากมาก
      ต่อให้ยังไม่ใช่คำตอบของวันนี้ อย่างน้อยมันก็มองได้ว่าเป็นสัญญาณของอนาคตที่เป็นไปได้ไม่ใช่หรือ?
    • ตัวอย่างการใช้คน 50 คนกับงานนี้ทำให้นึกถึงสำนวนคลาสสิกว่า “ผู้หญิงเก้าคนก็ทำให้คลอดลูกในหนึ่งเดือนไม่ได้”
      คำใบ้คือ คน 50 คนนั้นต้องถูกประสานงาน
    • Jarred ใช้โมเดลระดับ Mythos แต่ถ้าโมเดล open-weight บางตัวเก่งได้ระดับนั้น โดยเฉพาะ GLM 5.2 ที่ดูเผินๆ ก็เหมือนจะทำได้ ก็จะถูกกว่าผู้เชี่ยวชาญมากมาก
      ค่าใช้จ่ายคร่าวๆ คือ DeepSeek v4 Pro & Mimo v2.5 Pro 3,426 ดอลลาร์, Tencent HY3 3,892 ดอลลาร์, GLM 5.2 30,016 ดอลลาร์, Qwen 3.7 Max 37,925 ดอลลาร์, Claude Opus 4.8 & GPT 5.5 xhigh 82,750 ดอลลาร์
      คิดจากอินพุตโทเค็นที่ไม่แคช 5.9 พันล้านโทเค็น, เอาต์พุตโทเค็น 690 ล้านโทเค็น, และการอ่านอินพุตโทเค็นที่แคชแล้ว 72 พันล้านโทเค็น
  • นี่คือพลังของชุดทดสอบที่แข็งแรง LLM ทำได้ยอดเยี่ยมเมื่อมีรางวัลที่ตรวจสอบได้
    ต่อจากนี้น่าจะมีโปรเจ็กต์ที่ถูกเขียนใหม่เป็น Rust มากขึ้นอีกเยอะ Rust ให้การตรวจสอบหลายอย่างผ่าน type system และมี overhead ต่ำโดยไม่ต้องพึ่ง garbage collection จึงเป็นเป้าหมายที่เหมาะมากสำหรับการเขียนใหม่ลักษณะนี้
    ในยุคของ agent coding เหตุผลที่จะใช้ภาษาแบบ garbage-collected ก็น้อยลงเรื่อยๆ
    มองว่า Rust คือ local optimum สำหรับการเขียนโค้ดด้วย LLM อนาคตอาจมีภาษาที่ดีกว่านี้ แต่ Rust น่าจะครองอยู่ไปอีกนานพอสมควร

    • อาจเป็นเพราะการพัฒนาแบบวนรอบที่เร็วกว่าได้เหมือนกัน การรับประกันด้านความปลอดภัยของ Rust ไม่ได้มาฟรีๆ และถึงจะยอดเยี่ยมก็ยังส่งผลต่อเวลาในการวนรอบ
      ฉันเคยย้ายโปรเจ็กต์ส่วนตัวขนาดเกิน 300,000 บรรทัดจาก Python ไปเป็น TypeScript และเหตุผลที่ไม่ได้ใช้ Rust ก็คือเวลาในการพัฒนาแบบวนรอบนี่แหละ
  • สงสัยว่า Anthropic ใช้ Bun ในลักษณะไหนบ้าง รู้ว่าใช้เป็น “runtime” ของ Claude Code แต่แทนที่จะย้าย Zig 1 ล้านบรรทัดไปเป็น Rust ทำไมไม่ พอร์ต Claude Code ไปเป็น Rust เลย เพื่อจะได้ไม่ต้อง bundle JS runtime ไปทั้งก้อน?
    หรือว่า Anthropic ใช้ Bun ในส่วนอื่นด้วย? อาจเป็นพวกการเรียกใช้เครื่องมือรัน JS ภายในคำตอบของ Claude ก็ได้

    • ฉันก็สงสัยเหมือนกัน โดยเฉพาะเมื่อ Codex เขียนด้วย Rust อยู่แล้วก็ยิ่งน่าสงสัย
      ทำไมถึงไม่ย้าย Claude Code ไปตรงๆ เลย
      เดาว่าชุดทดสอบอาจจะยังไม่แข็งแรงพอ
      งานนี้อาจทำให้พวกเขากล้าขึ้นก็ได้
  • แนวคิดที่ว่า “ในเชิงประวัติศาสตร์ การเขียนใหม่เป็นความคิดที่แย่มาก” เปลี่ยนไปในช่วง 5 ปีที่ผ่านมา
    ครั้งแรกคือตอนที่ฉันเข้าร่วมบริษัทที่มีซอฟต์แวร์โปรดักต์ซึ่งแทบใช้งานไม่ได้ เราทำทั้งการรีแฟกเตอร์แบบค่อยเป็นค่อยไปและการเขียนใหม่แบบเดิมๆ แต่สุดท้ายก็ได้เรียนรู้ว่าแกนกลางมันผุพังเกินกว่าจะเยียวยา และทางที่ดีที่สุดคือเขียนใหม่จากหลักการแรก
    บทเรียนจากตรงนั้นคือ ภูมิปัญญาเดิมที่สืบต่อกันมาอาจใช้ได้เฉพาะกับกรณีการเขียนใหม่ของ ระบบที่ซับซ้อนแต่ยังทำงานได้ เท่านั้น
    หลังจากนั้นก็เจอสถานการณ์หลายแบบในยุค agent coding ทั้งในงานประจำและงานอดิเรก ฉันทำส่วนใหญ่ๆ ของซอฟต์แวร์ซับซ้อนอย่าง Salesforce, Gmail, และ Pioneer Rekordbox ขึ้นมาใหม่ได้ด้วยทีมเล็กมาก
    เช่นเดียวกับโพสต์บล็อก จุดสำคัญคือการสร้างวงจรตรวจสอบที่ยอดเยี่ยมรอบพฤติกรรมหลักด้วย compiler, linter, test harness และ test suite
    ยิ่งนานยิ่งรู้สึกว่า การออกแบบและติดตั้ง test harness แบบครอบคลุมต่างหากคือเนื้องานจริง พอมีสิ่งนั้นแล้วก็ปล่อยให้ LLM ลงมือทำได้เลย

    • ฉันก็คิดคล้ายกัน งานของเราอาจเปลี่ยนไปเป็น คนเลี้ยงฝูงเอเจนต์เขียนโค้ด
      ในกรณีนั้น สิ่งอย่าง test harness, linter, และ workflow ก็น่าจะกลายเป็นสุนัขต้อนแกะของเรา
  • ประเด็นที่น่าสนใจคือ การถกเถียงส่วนใหญ่รอบหัวข้อนี้ตั้งอยู่บนสมมติฐานว่าการเขียนใหม่เกิดขึ้นโดยใช้ โมเดลอย่าง Opus ไม่ใช่ Fable
    สมมติฐานแบบนั้นอย่างน้อยก็ถูกใช้บางส่วนเป็นเหตุผลว่าทำแบบนั้นไม่ได้หรือไม่ใช่ความคิดที่ดี
    แม้ตัวโมเดลเองจะไม่ได้เปลี่ยนสาระของเรื่องทั้งหมด แต่ส่วนตัวรู้สึกว่าควรระมัดระวังมากขึ้นเวลาประเมินความสามารถของโมเดลที่ Anthropic และองค์กรที่เกี่ยวข้องใช้ภายใน

    • ฉันก็คิดเหมือนกัน พอมาย้อนดูแล้ว ตอนที่ Jarred อธิบายแพตเทิร์น “เขียนไฟล์ .zig ทั้งหมดใหม่เป็น .rs” ในเดือนพฤษภาคม ก็มีโอกาสสูงที่ฉันจะเข้าใจผิด เพราะเขาพูดเหมือนกับว่านั่นเป็นสิ่งที่ฉันก็น่าจะทำตามแพตเทิร์นนั้นได้ในเดือนพฤษภาคม
      สิ่งที่เขาไม่ได้พูดคือเขากำลังใช้ Fable ก่อนเปิดตัว อยู่ [1]
      สัญญาณถัดไปที่อาจใช้ดูได้คือถ้าบริษัทในเครือของ Anthropic ปิด Claude Co-Authored-By trailer [2] ถ้าเป็นปีที่มี IPO ก็ควรคว้าโอกาสทุกครั้งในการโปรโมต Claude ยกเว้นกรณีที่ตอนนั้นในเดือนพฤษภาคมเป็นอะไรอย่าง Fable ที่ยังบอกใครไม่ได้
      [1]: https://xcancel.com/jarredsumner/status/2060050586024743376#...
      [2]: https://github.com/oven-sh/bun/commit/23427dbc12fdcff30c23a9...
  • ทุกครั้งที่เขียนโปรเจ็กต์ใหญ่ใหม่ ก็ทำให้มันเล็กลงและเร็วขึ้น และแก้บั๊กใหญ่ได้ทั้งหมด รวมถึงบั๊กเล็กส่วนใหญ่ด้วย
    ทีมปัจจุบันก็มีประสบการณ์คล้ายกัน เลยสงสัยว่าถ้า เขียนใหม่จาก Zig เป็น Zig ในสเกลเดียวกัน จะส่งผลต่อคุณภาพอย่างไร

 
GN⁺ 3 일 전
ความคิดเห็นบน Lobste.rs
  • แม้จะใช้ C++ ก็น่าจะเป็นตัวเลือกที่สมเหตุสมผลสำหรับ Bun อยู่ดี น่าจะได้ประโยชน์จาก constructor และ destructor และลบโค้ด wrapper แบบ extern "C" ออกไปได้มาก แต่ก็ยังต้องพึ่ง style guide ที่บังคับผ่าน code review อยู่ดี และแม้มี ASAN ก็ยังคงเกิด memory corruption และ memory leak ต่อไป
    น่าสนใจที่ Node.js ทำงานได้ดีแม้ใช้ C++ แต่ผมไม่เคยมอง Bun เป็นโปรเจกต์จริงจัง ตอนนี้มันดูเหมือน test bench ของฝ่ายการตลาด Anthropic เลยคิดว่าจะถอยห่างต่อไป
    • Node เองก็เคยมี CVE ด้าน memory safety จากโค้ดไลบรารีของตัวเองอย่างแน่นอน แค่ค้นว่า "nodejs memory cves" ก็เจอหลายรายการทันที
    • การบอกว่า Node ทำงานได้ดีด้วย C++ ก็อยู่ในระดับเดียวกับการบอกว่า Bun ทำงานได้ดีด้วย Zig นั่นแหละ Node มีความสนใจและผู้ใช้มากกว่า ปัญหาเลยถูกพบเร็วกว่า สุดท้ายทั้งคู่ก็อยู่ในสถานการณ์แบบ “ถ้าระวังสุด ๆ และไม่มีใครทำพลาด ก็จะทำงานได้สมบูรณ์แบบ”
      สปอยล์คือ ในความเป็นจริงไม่ได้ระวังกันขนาดนั้น และก็มีการทำพลาดด้วย
  • ประโยคที่ว่า “ประมาณ 4% ของโค้ด Rust ของ Bun อยู่ในบล็อก unsafe และ 78% ในนั้นเป็นบล็อกบรรทัดเดียว” ดูเหมือนเป็นคำพูดเพื่อให้สบายใจ แต่การที่บล็อก unsafe มีบรรทัดเดียวหรือไม่ไม่ใช่ประเด็น ถ้าข้างในนั้นทำลายการรับประกันความปลอดภัย โค้ดทั้งหมดนอกบล็อกก็อาจมี soundness ที่ถูกทำลายได้ เช่นกัน
    การ merge ช่วงแรกของพอร์ต Rust ของ Bun มี unsoundness ชัดเจนแบบนี้อยู่: https://github.com/oven-sh/bun/issues/30719
    issue นั้นได้รับการรับมือโดยที่ผู้ดูแลเปิดใช้เครื่องมือ Miri ของ Rust ใน CI และในส่วน “What's Next” ของบทความก็มี Miri (which runs for a growing chunk of code in CI) รวมอยู่ด้วย ดังนั้นดูเหมือนว่ากำลังทำงานไปในทิศทางนั้น ซึ่งเป็นเรื่องดี
    ถ้าพูดอย่างเป็นธรรม Rust ที่มีการละเมิดความปลอดภัยก็ยังอาจดูแลง่ายกว่าได้ ขึ้นอยู่กับคุณภาพของโค้ด Zig ที่มันเข้ามาแทนที่ ถึงอย่างนั้น จำนวนบรรทัดโค้ดต่อบล็อก unsafe ก็ไม่ใช่ตัวชี้วัดคุณภาพ โดยเฉพาะอย่างยิ่งถ้าบล็อกเหล่านั้นไม่มีแนวปฏิบัติการเขียนโค้ดอื่น ๆ ความเชี่ยวชาญ หรือการตรวจสอบอัตโนมัติประกอบด้วย
    • ประโยคนั้นดูเหมือนไม่ได้ตั้งใจให้สบายใจ แต่ใกล้เคียงกับการบอกว่า บล็อก unsafe ไม่ได้เกิดจากกระบวนการพอร์ต แต่เกิดจาก ข้อกำหนดของโปรเจกต์ มากกว่า ถ้าเรียกใช้ไลบรารี C ก็จำเป็นต้องมีบล็อก unsafe และไม่มีทางกำจัดได้ด้วยการ refactor อย่างเดียว
      แน่นอนว่าถ้าเขียนไลบรารี C นั้นใหม่ด้วยก็เป็นไปได้ แต่นั่นอาจค่อยพิจารณาภายหลัง
  • หนึ่งในจุดที่น่าสนใจที่สุดของ Bun คือโดยพื้นฐานแล้วมันเป็นเรื่องราวของ วิศวกรคนเดียวที่ทำงานได้มากกว่าที่คาดไว้มาก ตอนแรก Jarred บอกว่าเป็นเพราะ Zig คราวนี้บอกว่าเป็นเพราะ Claude แต่ถ้าจะบอกว่าเป็นเพราะตัว Jarred เองหรือ work ethic ของเขาก็ไม่แปลก อาจเป็นพลังของทีมเล็ก ๆ หรืออาจเป็นเพราะเป็นการเขียนและ implement สิ่งที่มีอยู่แล้วขึ้นมาใหม่ก็ได้
    ในประกาศ “Bun is joining Anthropic” Jarred บอกว่าจะจ้างวิศวกรเพิ่มเพื่อทำงานกับ Bun แต่ถ้าดูแค่ GitHub ทีม Bun กลับดูเหมือนเล็กลงด้วยซ้ำ ไม่แน่ใจว่าจะสรุปอะไรได้จากตรงนี้ แค่ประมาณว่า “Bun เป็นทีมเล็ก” เท่านั้น
  • พูดว่า “การเขียนใหม่เป็นความคิดที่แย่มาก” แล้วก็เดินหน้า เขียนใหม่ ทันทีนั่นเอง
    วิธีการเองน่าสนใจ แต่บทความอ่านแล้วเหมือนบทความการตลาด ขาดการวิเคราะห์ว่าต้นทุนเท่าไร ไม่มีความเสี่ยงของการเขียนใหม่ด้วย Rust และคำอธิบายเชิงรูปธรรมว่าทำไมถึงเกิดการเขียนใหม่ตั้งแต่แรกก็อ่อน เดาว่าอาจเป็นเพราะ no ai policy ของ Zig หรืออาจมีนโยบายภายใน Anthropic ที่ต้องการโฟกัสกับ Rust
    • เรื่องต้นทุน อย่างน้อยย่อหน้านี้ก็ดูเกี่ยวข้อง: “ก่อน merge ใช้ input token ที่ไม่ถูก cache 5.9 พันล้าน token, output token 690 ล้าน token และการอ่าน input token ที่ถูก cache 72 พันล้าน token คิดตามราคา API แล้วประมาณ 165,000 ดอลลาร์
      ส่วนเหตุผลที่เขียนใหม่นั้น ผมว่าบทความเล่าเรื่องได้ค่อนข้างสอดคล้อง Bun ยังคง crash ต่อเนื่องแม้จะมีมาตรการเพื่อจับปัญหาแล้ว และนักพัฒนาก็ต้องการวิธีป้องกันปัญหาเหล่านี้อย่างเป็นระบบมากขึ้น
      แผนแรกคือบังคับใช้สไตล์การเขียนโค้ดบางแบบให้เข้มขึ้น และนำ smart pointer มาใช้ แต่ Jared มองว่า smart pointer ที่ทำเองใช้งานแย่กว่า Rust และไม่มีการรับประกันเท่า Rust จากนั้นจึงกลายเป็นว่า “ลองทดสอบสักสัปดาห์ไหมว่าโมเดลใหม่ของ Anthropic จะเขียน Bun ใหม่เป็น Rust ได้หรือเปล่า?” และเมื่ออัตราการผ่าน test suite สูงขึ้น กระแสก็ดูเหมือนเปลี่ยนจาก “น่าลอง” เป็น “จะ merge”
      กล่าวคือ ดูไม่เหมือนตัดสินใจเขียนใหม่ด้วย Rust ตั้งแต่แรก แต่ใกล้เคียงกับ “Rust ดูเหมือนให้ทางแก้ปัญหา แต่ทำไม่ได้เพราะต้นทุนการเขียนใหม่สูง ทว่าพอลองพอร์ตด้วย LLM แล้วเห็นความเป็นไปได้ งั้นก็ไปทางการเขียนใหม่ด้วย LLM กัน” มากกว่า
    • “ก่อน merge ใช้ input token ที่ไม่ถูก cache 5.9 พันล้าน token, output token 690 ล้าน token และการอ่าน input token ที่ถูก cache 72 พันล้าน token คิดตามราคา API แล้วประมาณ 165,000 ดอลลาร์
    • เหตุผลในการเขียนใหม่ดูมีความชอบธรรมเพียงพอ มีความกังวลเรื่อง ปัญหา memory safety ที่เกิดซ้ำ และความกลัวการแก้บั๊กแบบไล่ตีตัวตุ่นไม่รู้จบ วิศวกรบางคนอาจรับมือด้วยวิธีอื่น แต่การเลือกเขียนใหม่เป็น Rust ด้วย LLM ก็เป็นหนึ่งในวิธีแก้ปัญหานี้
    • แน่นอนว่าอ่านแล้วเหมือนบทความการตลาด ไม่ว่าจะตั้งใจหรือไม่ก็ตาม แต่ในทางปฏิบัติการคำนวณต้นทุนแทบเป็นไปไม่ได้ โดยเฉพาะถ้านักพัฒนาเข้าถึงโมเดล Anthropic ก่อนเปิดตัวได้ อย่างไรก็ตาม ถ้าคนทั่วไปอย่างเราจะเขียนใหม่ในสเกลนั้นด้วยโมเดล Claude ปัจจุบัน ก็พอประเมินต้นทุนได้
  • แทนที่จะคอยแก้บั๊กพวกนี้ทีละตัว เหตุผลที่ว่าควรทำให้ดีกว่านี้เพื่อผู้ใช้ที่พึ่งพาอยู่ และควรป้องกันอย่างเป็นระบบไม่ให้บั๊กแบบนี้เกิดซ้ำ ถือเป็นเหตุผลที่ยอดเยี่ยม ถึงอย่างนั้น แม้เหตุผลจะเป็นแค่ว่า “กระแส Rust กำลังดี” ผมก็คงยอมรับได้เหมือนกัน
    ขอแสดงความยินดีกับ Jarred, ทีม Bun และ Anthropic ที่ทำสิ่งนี้สำเร็จ