2 điểm bởi GN⁺ 3 giờ trước | 1 bình luận | Chia sẻ qua WhatsApp
  • Bun, khởi đầu bằng Zig, đã phát triển thành runtime được tải xuống hơn 22 triệu lần mỗi tháng, nhưng việc kết hợp engine JavaScript dựa trên GC với quản lý bộ nhớ thủ công đã gây ra các vấn đề ổn định lặp lại, trở thành động lực để chuyển sang Rust
  • Thay vì để con người chuyển 535.496 dòng mã Zig trong 1 năm, nhóm đã chạy song song khoảng 50 workflow động của Claude Code và tối đa 64 instance Claude trong 11 ngày
  • Quá trình port được kiểm chứng bằng PORTING.md, LIFETIMES.tsv, 1 người triển khai cùng ít nhất 2 reviewer đối kháng, và bộ test TypeScript hiện có; tất cả đều pass 100% trên CI của 6 nền tảng
  • Sau khi chuyển sang Rust, Bun v1.4.0 đã sửa 128 lỗi tái hiện được ở v1.3.14, khắc phục toàn bộ rò rỉ bộ nhớ có thể instrumentation, và giảm kích thước binary trên Linux·Windows khoảng 20%
  • Bun v1.3.14 là phiên bản Zig cuối cùng, còn v1.4.0 là phiên bản Rust đầu tiên được cung cấp trên canary; nhóm dùng borrow checker, Miri, LeakSanitizer và fuzzing dựa trên coverage 24/7 làm công cụ cải thiện độ ổn định

Bun khởi đầu bằng Zig và vấn đề ổn định

  • Bun bắt đầu là dự án port từng dòng transpiler JavaScript·TypeScript của esbuild từ Go sang Zig
  • Mã Zig đầu tiên được viết vào ngày 16/4/2021, và khả năng kiểm soát cấp thấp cùng thiết kế hướng hiệu năng của Zig đã giúp hiện thực hóa bản triển khai Bun ban đầu
  • Bun giai đoạn đầu được một người viết bằng Zig trong 1 năm, với phạm vi rất rộng
    • Transpiler·minifier·bundler cho JavaScript, TypeScript, CSS
    • Trình quản lý package tương thích npm
    • Test runner tương tự Jest
    • Phân giải module tương thích Node.js·TypeScript
    • Client HTTP/1.1·WebSocket
    • Triển khai các API Node.js như fs, net, tls
  • Hiện Bun CLI được tải xuống hơn 22 triệu lần mỗi tháng, được Claude Code và OpenCode dùng làm runtime, và được Vercel, Railway, DigitalOcean cùng các bên khác hỗ trợ first-party

Các lỗi an toàn bộ nhớ lặp lại

  • Các ví dụ lỗi được sửa trong Bun v1.3.14 bao gồm use-after-free, double-free, rò rỉ bộ nhớ, truy cập out-of-bounds và race condition
    • Heap-use-after-free do gọi .reset() trong lúc async .write() của node:zlib
    • Use-after-free trong node:http2 khi callback JS tái nhập gây rehash hashmap, làm vô hiệu hóa con trỏ stream nội bộ
    • Vấn đề callback valueOf() hoặc toString() detach ArrayBuffer trong UDPSocket.send()sendMany()
    • Crash và out-of-bounds read trong Buffer#copy, Buffer#fill do ArrayBuffer bị detach hoặc resize trong quá trình coercion đối số
    • Rò rỉ bộ nhớ liên quan đến crypto.scrypt, tlsSocket.setSession(), fs.watch()
    • Double-free khi CSS parser xử lý vendor prefix và background nhiều lớp
    • Crash do race condition MessageEvent khi truy cập đồng thời BroadcastChannel hoặc MessagePort
  • Trước đây nhóm cũng đã dùng nhiều cơ chế để tăng cường độ ổn định
    • Patch hỗ trợ Address Sanitizer vào Zig compiler và chạy bộ test ASAN trên mọi commit
    • Phát hành bản build ReleaseSafe có kiểm tra an toàn của Zig cho Windows
    • Fuzz API runtime của Bun 24/7 bằng Fuzzilli
    • Vận hành nhiều test rò rỉ bộ nhớ end-to-end
  • Lập trường không phải Zig tự thân là vấn đề; nguồn chính của vấn đề ổn định là yêu cầu phải xử lý đồng thời giá trị GC và bộ nhớ quản lý thủ công

Lý do chọn Rust

  • JavaScript là ngôn ngữ GC, và các engine như JavaScriptCore và V8 có quy tắc nghiêm ngặt về xử lý exception và GC
  • Zig không tự động quản lý bộ nhớ như C, không có constructor·destructor, và cleanup phần lớn phải được chỉ định rõ bằng defer tại từng call site
  • Trong Bun, việc xử lý đúng lifetime của giá trị GC và giá trị quản lý thủ công là một nguồn lớn gây ra vấn đề ổn định
    • Phải xác nhận byte đã cấp phát được giải phóng ở đâu
    • Phải đảm bảo chỉ được giải phóng một lần
    • Phải kiểm tra đúng cách việc xử lý exception JavaScript
    • Phải xác nhận con trỏ GC có hiển thị với conservative stack scanner hay không
  • Cách cleanup của Zig là defer, errdefer tường minh; C++ dùng destructor và move, còn Rust dùng Drop
  • Trong mã Zig hiện có của Bun, arena lifetime, reference counting và review cẩn thận được kết hợp với nhau
  • Cũng có thể cưỡng chế quy tắc ownership bằng style guide và code review, nhưng trong mã Rust an toàn, use-after-free, double-free và free bị thiếu trên error path sẽ trở thành lỗi trình biên dịch
  • Khoảng 20% mã của Bun là C++ và nhúng nhiều thư viện C/C++
    • JavaScriptCore
    • uWebSockets và usockets
    • lshpack và lsquic
    • BoringSSL
    • SQLite
  • C++ cũng có thể là một lựa chọn, nhưng vẫn phụ thuộc vào style guide và code review; ngay cả khi có ASAN, hỏng bộ nhớ và rò rỉ vẫn có thể xảy ra

Chiến lược viết lại: một lần, theo kiểu cơ học

  • Mã Zig hiện có của Bun có 535.496 dòng không tính chú thích, và một lần viết lại theo cách truyền thống được đánh giá là công việc mất khoảng 1 năm với một nhóm kỹ sư nhỏ
  • Vì không thể dừng sửa lỗi, vá bảo mật và phát triển tính năng trong 1 năm, port cơ học nhằm giảm thiểu thay đổi hành vi với người dùng được chọn làm cách tiếp cận ít rủi ro nhất
  • Bộ test của Bun được viết bằng TypeScript nên không phụ thuộc vào ngôn ngữ triển khai runtime
  • Viết lại tăng dần được đánh giá là đau đớn trong ngắn và trung hạn vì phải tạo mã tạm và kỳ vọng sẽ xóa sau này, nên nhóm chuyển toàn bộ một lần
  • Mã Rust được viết để trông như được transpile từ mã Zig, và hướng đi được chọn là sau Bun v1.4 sẽ giảm dần unsafe rồi refactor theo Rust idiomatic

Workflow động của Claude Code

  • Trong lần viết lại bằng Rust, khoảng 50 workflow động trên Claude Code đã chạy liên tục trong 11 ngày
  • Các workflow trải dài từ viết hướng dẫn port, chuyển đổi file, sửa lỗi biên dịch, khôi phục subcommand, vượt qua toàn bộ test, cho đến cleanup quy mô lớn
    • Tạo hướng dẫn port ánh xạ các pattern và type của Zig sang pattern và type của Rust
    • Port cơ học mọi file .zig thành file .rs theo PORTING.mdLIFETIMES.tsv
    • Sửa lỗi compiler theo từng crate
    • Khôi phục hoạt động của các subcommand như bun test, bun build
    • Pass toàn bộ bộ test
    • Refactor và cleanup quy mô lớn
  • Trong phần lớn thời gian, con người đọc đầu ra của workflow, kiểm tra vấn đề và lỗi, rồi điều chỉnh prompt để Claude sửa vòng lặp
  • Trong phần chuẩn bị, nhóm đã thảo luận khoảng 3 giờ với Claude về cách ánh xạ các pattern trong codebase Zig sang Rust, và kết quả được tuần tự hóa thành PORTING.md
  • Để thêm Rust lifetime vào mã quản lý bộ nhớ thủ công, nhóm chạy workflow phân tích lifetime của mọi struct field
    • Tìm các field có lifetime phức tạp
    • Đề xuất lifetime
    • 2 agent review đối kháng kiểm tra
    • Phản hồi được phản ánh và lưu vào LIFETIMES.tsv

Phương thức review đối kháng

  • Với mỗi Claude triển khai, đặt một Claude reviewer đối kháng trong một context window riêng; reviewer chỉ nhận diff và được chỉ thị giả định rằng code sai để tìm bug
  • Cấu trúc cơ bản gồm 1 người triển khai, 2 reviewer đối kháng trở lên và 1 fixer
  • Tất cả bug mà reviewer thực sự bắt được đều vượt qua biên dịch nhưng có vấn đề về hành vi
    • uv_close là bất đồng bộ nhưng Box<uv::Pipe> bị drop ở cuối match arm, khiến libuv giữ freed memory, dẫn đến use-after-free và double-free
    • Lỗi timespec khi dùng trunc() với file time âm không nguyên, tạo ra nsec âm
    • Lỗi unwrap_or đánh giá eager đối số, gây panic trong trường hợp lược bỏ percentage của color-mix()
  • Giống như review của con người, tách context của tác giả và reviewer để giảm thiên lệch có thể phát sinh do người triển khai muốn merge

Thực thi port quy mô lớn và song song hóa

  • Trước khi chuyển toàn bộ 1.448 file .zig, họ xác minh quy trình trước bằng 3 file
    • 1 người triển khai viết file .rs
    • 2 reviewer kiểm tra xem hành vi có khớp với .zig và có tuân theo PORTING.md, LIFETIMES.tsv hay không
    • 1 fixer áp dụng các đề xuất
  • Ở giai đoạn đầu port toàn bộ file, nhiều Claude chạy git stash, git stash pop, git reset HEAD --hard và xung đột lẫn nhau
  • Sau đó họ thêm vào workflow các quy tắc cấm git stash, git reset, các lệnh git không phải commit file cụ thể, và các lệnh chậm như cargo
  • Cuối cùng, họ dùng 4 workflow shard và 4 worktree; trong mỗi shard, 16 Claude commit và push file
  • Nhờ song song hóa và chuẩn bị trước, ở mức peak Claude viết khoảng 1.300 dòng code mỗi phút
  • Nhánh port có 6.502 commit không tính các commit merge, giờ peak đạt 695 commit, và landed diff cuối cùng là +1.009.272 dòng
  • Do không tăng IOPS mặc định của instance EC2, chỉ một lệnh grep chậm cũng khiến đọc/ghi đĩa bị dừng trong vài phút

Lỗi biên dịch và tách crate

  • Sau khi viết xong toàn bộ code, workflow Claude sửa lỗi compiler
  • Codebase Zig thực chất là một compilation unit duy nhất, còn code Rust dự kiến được chia thành khoảng 100 crate để biên dịch nhanh hơn
  • Nhóm lỗi khó nhất là phụ thuộc vòng
    • Chỉ PR tách crate ngay trước khi viết lại bằng Rust là chưa đủ
    • Một workflow riêng phân loại và ghi lại nên đặt code có phụ thuộc vòng ở đâu
    • Một workflow khác thực hiện phần refactor đó
  • Sau khi xử lý phụ thuộc vòng, khoảng 16.000 lỗi compiler lộ ra
  • Các lỗi này được xử lý song song theo từng crate
    • Chạy cargo check trong từng crate
    • Gom output theo file và lưu lại
    • Sửa lỗi biên dịch của crate đó
    • 2 reviewer đối kháng review thay đổi
    • 1 fixer áp dụng sửa đổi
  • Cũng có một false start khi Claude diễn giải “hãy làm cho tất cả crate biên dịch được” thành việc tạo function stub
  • Khi xuất hiện pattern biện minh workaround bằng các chú thích giải thích dài, họ thêm quy tắc review: “nếu cần comment dài cỡ một đoạn văn thì code đã sai và cần sửa code”

Quá trình đến khi pass test

  • Sau khi cargo check pass, họ lần lượt xử lý lỗi link, panic ngay sau khi khởi động, chạy bun --version, rồi bun test <file>
  • Họ dùng workflow lưu stacktrace thất bại theo từng CLI subcommand vào file, rồi sửa qua vòng lặp triển khai–reviewer–fixer
  • Workflow cho file test shard khoảng 100 file test ngẫu nhiên vào 4 worktree, lưu stacktrace và lỗi theo từng thất bại rồi sửa
  • Bộ test có các bài kiểm tra rò rỉ bộ nhớ và test tích hợp có thể timeout trong debug build
    • Test chạy next dev và hot module reloading phát hiện 100 thay đổi
    • Stress test làm cạn số lượng TCP socket tối đa
    • Test đọc/ghi đĩa ở quy mô gigabyte
    • Test spawn khoảng 10.000 process
  • Để cô lập, họ dùng systemd-run và cgroups để giới hạn mức dùng bộ nhớ/CPU và tách pid namespace
  • Dù vậy, máy vẫn crash nhiều lần do hết dung lượng đĩa
  • Hai ngày sau lần chạy CI đầu tiên, số file test thất bại giảm từ 972 xuống 23; một ngày rưỡi sau đó Linux hoàn toàn green
  • Cuối cùng, toàn bộ test CI trên 6 nền tảng đều pass
    • macOS x64
    • macOS arm64
    • Linux x64
    • Linux arm64
    • Windows x64
    • Windows arm64
  • Sau khi test pass 100%, con người kiểm tra thủ công rằng test thực sự được chạy và không bị skip, rồi merge
  • Thời điểm merge vào main không phải là một versioned release; họ chưa đủ tự tin để release, nhưng đã đủ tự tin để dồn sức cho rewrite

Quy mô test và chi phí

  • Trong 11 ngày, từ ngày 3/5 đến khi merge ngày 14/5, 6.778 commit được tạo ra
  • Test không bị xóa hoặc skip
  • Quy mô test theo nền tảng như sau
    • Debian 13 x64: expect() 1.386.826 lần, 60.624 test, 4.174 file
    • macOS 14 arm64: expect() 1.259.953 lần, 58.850 test, 4.175 file
    • Windows 2019 x64: expect() 1.007.544 lần, 57.337 test, 4.173 file
  • Công việc pre-merge dùng 5,9 tỷ uncached input token, 690 triệu output token và 72 tỷ cached input token read
  • Chi phí theo giá API vào khoảng 165.000 USD
  • Họ đánh giá rằng nếu con người tự làm thì 3 kỹ sư có context toàn bộ codebase sẽ mất khoảng 1 năm
  • Model được dùng là pre-release Claude Fable 5, và có disclosure rằng Bun đã được Anthropic mua lại vào tháng 12/2025

Review bảo mật, fuzzing và tình trạng unsafe

  • Sau khi merge bản port Rust, họ hoàn tất 11 vòng review bảo mật bằng Claude Code Security và xử lý các finding
  • Fuzzing dựa trên coverage chạy 24/7 được thêm cho tất cả parser của Bun
    • JavaScript
    • TypeScript
    • JSX
    • CSS
    • JSON5
    • JSONC
    • TOML
    • YAML
    • Markdown
    • INI
    • Bun Shell scripts
    • semver ranges
    • file .patch
    • CSS colors
  • Fuzzer gửi bug tìm được cho Claude để Claude nộp PR bao gồm tái hiện và bản sửa; con người review PR
  • Đến nay, parser đã được chạy 100 tỷ lần và dẫn tới khoảng 15 PR
  • Tại thời điểm viết, khoảng 4% code Rust nằm trong block unsafe
    • Khoảng 13.000 keyword unsafe
    • Khoảng 27.000 dòng / tổng khoảng 780.000 dòng
    • 78% block unsafe là một dòng, là con trỏ đến từ C++ hoặc lời gọi thư viện C
  • Họ cho biết vì vẫn tiếp tục dùng các thư viện C/C++ như JavaScriptCore, lượng unsafe sẽ luôn nhiều hơn so với dự án Rust thuần

Regression được phát hiện sau khi chuyển sang Rust

  • Rust rewrite là một thay đổi quy mô lớn nên đã tạo ra 19 regression đã biết, và tất cả đều đã được sửa
  • Phần lớn đến từ những đoạn code có cú pháp tương tự giữa hai ngôn ngữ nhưng ngữ nghĩa khác nhau
  • Side effect bên trong debug_assert!

    • assert của Zig là hàm nên các đối số được thực thi trong mọi build
    • debug_assert! của Rust là macro nên trong release build, toàn bộ biểu thức bị loại bỏ
    • Lời gọi insert_stale biến mất trong release build, làm hỏng một số trường hợp HMR cụ thể của dự án HTML route dùng React
    • Issue liên quan: #30678
  • Slice có độ dài lẻ

    • Zig helper reinterpretSlice(u16, bytes) của Bun dùng @divTrunc nên đã bỏ qua trailing odd byte
    • bytemuck::cast_slice của Rust sẽ panic khi độ dài là lẻ
    • Đã có regression khiến Blob.text() với các byte lẻ sau UTF-16 BOM không trả về chuỗi mà làm process panic
    • Cách sửa là bỏ qua odd byte trở lại bằng &buf[..buf.len() & !1]
    • Issue liên quan: #31188
  • Bounds checks

    • Code Zig trên macOS và Linux được compile bằng ReleaseFast nên bounds check bị loại bỏ, còn Rust release build vẫn giữ bounds check
    • Kích thước overflow block của Bun module resolver vẫn để placeholder 64, làm ceiling giảm từ 8,4 triệu interned filenames xuống 270.272
    • Lỗi off-by-one ptrs[4095] được port sang trở nên có thể chạm tới trong dự án thực tế, và Rust panic thay vì ghi out-of-bounds
    • Issue liên quan: #31503
  • Format string comptime

    • Trong Output.pretty của Zig, fmtcomptime nên các color marker <r>, <d> được chuyển thành ANSI escape trước khi thay thế đối số
    • Hàm Rust không có comptime parameter nên xử lý marker trên chuỗi đã hoàn chỉnh, và rewrite nhầm cả đối số
    • Trong bun update -i, OSC 8 hyperlink termination xung đột với trailing marker <r>, khiến r được in ra như văn bản
    • Với Rust cần dùng macro bun_core::pretty!("<r>{}<r>", hyperlink)
    • Issue liên quan: #30693

Các bug đã sửa và rò rỉ bộ nhớ

  • Bun v1.4.0 sửa 128 bug có thể tái hiện trong v1.3.14
  • Phạm vi bao gồm rò rỉ bộ nhớ, crash, cho đến help text bị tô màu sai
  • Drop của Rust tự động gọi hàm drop khi giá trị ra khỏi scope
  • Trong Zig, phải thêm defer ở từng call site, nên dễ bị thiếu cleanup hoặc cleanup trùng lặp
  • Drop của Rust là lựa chọn chấp nhận hidden control flow để đổi lại việc giảm các footgun phổ biến
  • Drop đã sửa nhiều rò rỉ bộ nhớ liên quan đến file path trong error handling code
  • Tích hợp LeakSanitizer của Bun được cải thiện, theo dõi tất cả native code memory allocations
  • Tất cả instrumentable memory leak đều đã được sửa
  • Cải thiện rò rỉ trong Bun.build()

    • Trong Bun v1.3.14 trước đây, mỗi lần gọi in-process Bun.build(), parsed source text và AST symbol table tồn tại lâu hơn vòng đời build, gây rò rỉ vài MB mỗi lần
    • Trong bài test bundle cùng một dự án 60 module 2.000 lần trong một process, v1.3.14 tiếp tục rò rỉ khoảng 3MB mỗi build
    • Trong Bun v1.4.0, mức sử dụng bộ nhớ đi ngang
    • | 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 |

Kích thước binary, mức dùng stack, hiệu năng

  • Chỉ với thay đổi ban đầu của Rust rewrite, kích thước binary đã giảm
    • Windows: giảm 3,8 MB
    • macOS: giảm 5,5 MB
    • Linux: giảm 6,8 MB
  • Nguyên nhân chính là code Zig đã dùng comptime quá nhiều
  • Sau đó cũng áp dụng identical code folding, loại bỏ unused data của ICU, và cách lazy decompress một phần libicu bằng zstd dictionary
  • Kết hợp Rust rewrite, thay đổi ICU và identical code folding, kích thước binary Bun trên Linux và Windows giảm khoảng 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 và các recursive-descent parser của Bun dùng ít stack space hơn
  • LLVM IR codegen của Rust phát ra các intrinsic llvm.lifetime.startllvm.lifetime.end cho stack variable, giúp LLVM tái sử dụng stack slot
  • Trước đây, để обход qua open issue của Zig, họ phải tự refactor các hàm đặc biệt lớn thành nhiều hàm nhỏ hơn
  • Rust hỗ trợ cross-language link-time optimization giữa C/C++ và Rust, cho phép inlining giữa các ngôn ngữ
  • Benchmark Linux x64

    • So sánh Bun v1.3.14 và Bun v1.4.0 trên Linux x64 EC2 Xeon Platinum 8488C
    • HTTP throughput được đo bằng oha, app workload được đo bằng 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% |

Các trường hợp sử dụng thực tế và trạng thái phát hành

  • Prisma đã ra mắt public beta của Prisma Compute trên nền bản rewrite Rust của Bun
  • Phía Prisma cho biết họ đã kiểm thử trên bản rewrite Rust các failure mode gồm connection pool không khôi phục sau khi VM pause/resume và memory leak, và bản rewrite đã xử lý tốt các failure mode này
  • Claude Code v2.1.181 và các phiên bản sau bản phát hành ngày 17 tháng 6 sử dụng Bun được port sang Rust
  • Startup trên Linux của Claude Code nhanh hơn 10%, còn ngoài ra hầu hết người dùng gần như không nhận ra khác biệt
  • Bun v1.3.14 là phiên bản Bun cuối cùng được viết bằng Zig
  • Bun v1.4.0 là phiên bản Bun đầu tiên được viết bằng Rust và được cung cấp dưới dạng canary

Công cụ đội ngũ thu được và những việc còn lại

  • Codebase Rust mới vẫn giữ hình thái rất giống codebase Zig hiện có
  • Được viết để những người hiểu mã Zig ban đầu cũng có thể hiểu được mã Rust được dịch một cách cơ học
  • Việc review PR rewrite Rust được tiến hành bằng cách kiểm tra xem agent review đối nghịch có phát hiện đúng các điểm không nhất quán giữa Zig và Rust, hướng dẫn porting, và việc tuân thủ lifetime guide hay không, đồng thời con người đọc nhiều đoạn mã theo kiểu side-by-side
  • Bun v1.4 giúp Bun nhanh hơn, nhỏ hơn, giảm mức sử dụng bộ nhớ và cung cấp công cụ để cải thiện độ ổn định
    • Rust borrow checker
    • Miri
    • LeakSanitizer
    • coverage-guided fuzzing 24/7 cho parser
  • Vẫn còn những phần cần refactor, và bun-unsafe-audit đã được kết nối
  • Một kỹ sư đã theo dõi sát sao Fable và Claude Code, đạt tới trạng thái toàn bộ test suite pass trên mọi nền tảng chỉ trong 11 ngày

1 bình luận

 
Các ý kiến trên Lobste.rs
  • Ngay cả nếu dùng C++ thì có lẽ đó cũng là một lựa chọn hợp lý cho Bun. Họ có thể có constructor và destructor, đồng thời xóa được rất nhiều mã wrapper extern "C", nhưng vẫn sẽ phải dựa vào style guide được ép buộc qua code review, và dù có ASAN thì hỏng bộ nhớ và rò rỉ bộ nhớ vẫn sẽ tiếp diễn
    Thú vị là Node.js vẫn chạy tốt với C++, nhưng tôi chưa bao giờ xem Bun là một dự án nghiêm túc. Giờ nó trông như một test bench của bộ phận marketing Anthropic, nên tôi vẫn sẽ tránh xa
    • Node chắc chắn cũng từng có các CVE về an toàn bộ nhớ xuất phát từ mã thư viện của chính nó. Chỉ cần tìm "nodejs memory cves" là thấy ngay vài trường hợp
    • Nói Node chạy tốt với C++ cũng cùng mức với nói Bun đã chạy tốt với Zig. Node được chú ý và có nhiều người dùng hơn nên vấn đề lộ ra nhanh hơn, còn rốt cuộc cả hai đều ở trong tình huống “nếu cực kỳ cẩn thận và không ai mắc lỗi thì sẽ hoạt động hoàn hảo”
      Spoiler: thực tế thì người ta không cẩn thận đến thế, và vẫn mắc lỗi
  • Câu “khoảng 4% mã Rust của Bun nằm trong các khối unsafe, và 78% trong số đó chỉ là một dòng” nghe như muốn trấn an, nhưng việc một khối unsafe có một dòng hay không không quan trọng. Nếu trong đó phá vỡ các bảo đảm an toàn, thì toàn bộ mã bên ngoài khối cũng có khả năng bị phá vỡ soundness
    Bản merge ban đầu của port Rust cho Bun có chứa dạng unsoundness rõ ràng như thế này: https://github.com/oven-sh/bun/issues/30719
    Vấn đề đó đã được các maintainer phản hồi bằng cách bật công cụ Miri của Rust trong CI, và phần “What's Next” của bài viết cũng có Miri (which runs for a growing chunk of code in CI), nên có vẻ họ đang làm theo hướng đó, điều này là tốt
    Công bằng mà nói, ngay cả Rust có vi phạm an toàn cũng có thể dễ bảo trì hơn tùy vào chất lượng của mã Zig mà nó thay thế. Dù vậy, số dòng mã trên mỗi khối unsafe không phải là thước đo chất lượng, đặc biệt nếu các khối đó cũng không đi kèm thực hành lập trình, chuyên môn hay kiểm tra tự động khác
    • Câu đó có vẻ không nhằm trấn an, mà gần với ý rằng các khối unsafe không phát sinh từ quá trình port, mà xuất phát từ yêu cầu của dự án. Nếu gọi thư viện C thì cần khối unsafe, và không có cách nào loại bỏ chỉ bằng refactoring
      Tất nhiên nếu viết lại cả thư viện C đó thì có thể, nhưng chuyện đó có thể xem xét sau
  • Một trong những điểm thú vị nhất ở Bun là về cơ bản đây là câu chuyện một kỹ sư làm được nhiều việc hơn dự kiến rất nhiều. Ban đầu Jarred nói là nhờ Zig, lần này nói là nhờ Claude, nhưng cũng không lạ nếu đó là nhờ chính Jarred hoặc đạo đức làm việc của anh ấy. Cũng có thể là sức mạnh của một nhóm nhỏ, hoặc vì họ đang viết lại và triển khai những thứ vốn đã tồn tại
    Trong thông báo “Bun is joining Anthropic”, Jarred nói họ sẽ tuyển thêm kỹ sư để làm Bun, nhưng nhìn trên GitHub thì đội Bun có vẻ lại còn nhỏ đi. Tôi không rõ rút ra kết luận gì từ đây, chỉ là “Bun là một nhóm nhỏ” mà thôi
  • Nói “viết lại là một ý tưởng tồi tệ” rồi ngay sau đó lại tiến hành viết lại
    Bản thân phương pháp thì thú vị, nhưng bài viết đọc như một bài marketing. Nó cũng thiếu phân tích về chi phí, không nói đến rủi ro đi kèm việc viết lại bằng Rust, và ngay từ đầu cũng giải thích khá mơ hồ vì sao việc viết lại xảy ra. Nếu đoán thì có thể là do chính sách không AI của Zig, hoặc do nội bộ Anthropic có định hướng tập trung vào Rust
    • Về chi phí, đoạn này ít nhất có vẻ liên quan: “trước khi merge, đã dùng 5,9 tỷ token đầu vào không cache, 690 triệu token đầu ra, và 72 tỷ lượt đọc token đầu vào đã cache; theo giá API thì khoảng 165.000 USD
      Còn về lý do viết lại, tôi thấy bài viết kể một câu chuyện khá nhất quán. Bun vẫn tiếp tục crash dù đã có các biện pháp để bắt lỗi, và các developer muốn một cách có hệ thống hơn để ngăn các vấn đề như vậy
      Kế hoạch ban đầu là ép một số phong cách lập trình chặt chẽ hơn và đưa smart pointer vào, nhưng Jared cho rằng smart pointer tự làm có usability kém hơn Rust và cũng không có bảo đảm. Vì vậy nó trở thành “hay thử trong một tuần xem model mới của Anthropic có thể viết lại Bun bằng Rust không?”, và khi tỷ lệ vượt qua test suite tăng lên, luồng diễn biến có vẻ đã chuyển từ “đáng thử” sang “sẽ merge”
      Nói cách khác, có vẻ không phải là quyết định viết lại bằng Rust ngay từ đầu, mà gần hơn với “Rust có vẻ đưa ra lời giải cho vấn đề, nhưng không làm được vì chi phí viết lại. Nhưng thử port bằng LLM thì thấy có khả năng. Vậy hãy viết lại bằng LLM”
    • “trước khi merge, đã dùng 5,9 tỷ token đầu vào không cache, 690 triệu token đầu ra, và 72 tỷ lượt đọc token đầu vào đã cache; theo giá API thì khoảng 165.000 USD
    • Lý do viết lại có vẻ đủ chính đáng. Có nỗi lo về các vấn đề an toàn bộ nhớ liên tục và việc sửa lỗi kiểu đập chuột chũi không có hồi kết; một số kỹ sư có thể đã xử lý theo cách khác, nhưng chọn viết lại bằng Rust với LLM cũng là một lời giải cho vấn đề
    • Đúng là đọc như bài marketing. Dù có chủ ý hay không thì là vậy, nhưng thực tế chi phí gần như không thể tính được. Đặc biệt nếu các developer có quyền truy cập vào các model Anthropic trước khi phát hành. Tuy nhiên, nếu những người bình thường như chúng ta viết lại một hệ thống quy mô như vậy bằng các model Claude hiện nay thì vẫn có thể ước tính chi phí
  • Thay vì tiếp tục sửa từng lỗi như thế này, việc cần làm tốt hơn cho những người dùng đang phụ thuộc vào nó và ngăn các lỗi này tái diễn một cách có hệ thống là một lý do rất tốt. Dù vậy, nếu lý do chỉ là “Rust đang có vibe tốt” thì tôi cũng vẫn chấp nhận
    Xin chúc mừng Jarred, đội Bun và Anthropic vì đã làm được việc này