Уроки з перенесення проекту Bun на мову Rust за допомогою штучного інтелекту: перевірка — це справжня робота
Що дає нам крок Бунна, допомогтий його агентом, від Zig до Rust, щодо тестових наборів як контрактів, посібників з портування, небезпечного коду та чому перевірка зараз обмежує роботу штучного інтелекту з програмуванням.
Джерела: Bun Rewrote Its Runtime in Rust With AI. The Real Story Is Bigger Than the Code
Більшість інженерних команд намагаються уникати переписування мов програмування великих продакшн-систем якомога довше. Bun – середовище виконання та набір інструментів для JavaScript та TypeScript – за повідомленнями переніс свою реалізацію з Zig на Rust, причому більшу частину роботи з перекладу виконали штучні інтелект-агенти, і цифри справді вражаючі. Проте ще цікавіше те, як процес прийняття рішень визначив, яку частину цього коду можна вважати надійною, а не кількість коду, створеного агентами. У цій статті детально розглядається цей процес та пропонуються практики, які ви можете застосувати до власних процесів оптимізації та міграцій з використанням штучного інтелекту.
Чому зазвичай уникають переписування
Переписування мови супроводжується знайомим списком ризиків. Воно може спричинити тонкі регресії, які ніхто не помічає протягом місяців, змінити продуктивність у непередбачуваних напрямках, зламати платформу, якою користуються лише кілька користувачів, та поглинути значну частину ресурсів команди. У найгіршому випадку команда змушена підтримувати стару та нову реалізації одночасно, платячи подвійну ціну за кожне виправлення багів.
Саме тому міграція на Bun привертає увагу. На момент написання цього тексту репозиторій проекту описує Bun як JavaScript-рунтайм на основі Rust, створений на базі JavaScriptCore, а компанія Anthropic оголосила про придбання Bun у грудні 2025 року. У публічних звітах зазначається, що порт складається приблизно з 535 000 рядків коду на мові Zig, перекладених протягом близько 11 днів, причому агенти виконують більшу частину роботи з реалізації в рамках суворо визначеного процесу.
Хочеться сприйняти це як ще один заголовок на кшталт „Штучний інтелект написав величезну кількість коду“. Краще поставити інше запитання: чи може система штучного інтелекту здійснити дуже масштабні зміни, коли люди створюють надійний механізм для перевірки правильності результату? Це запитання має набагато більше значення для того, як буде розроблятися програмне забезпечення протягом наступних кількох років.
Модифікація, а не повна переробка
Bun спочатку був написаний переважно на Zig — мові системного програмування, яка цінується за можливості низькорівневого керування та прогнозовану продуктивність. Міграція не розглядалась як початок з нуля. Її мета була свідомо обмеженою: зберегти існуючу архітектуру та спостережувану поведінку, змінивши лише мову, на якій написана реалізація.
Саме цей підхід є ключовим дизайнерським рішенням. Традиційний підхід до переписування коду спонукає інженерів постійно переробляти його, змінюючи структури даних, переставляючи модулі, додаючи абстракції та коригуючи API. Кожен з цих варіантів є новим джерелом ризиків та об’єктом перевірки. Виключивши більшість з них, команда Bun перетворила відкриту творчу задачу на механічну, яка має чіткий орієнтир — поточну реалізацію та тести, що її описують.
Кількість рядків здається складною частиною, але це не так. Створення синтаксично коректного коду на Rust є відносно простим. Справжня складність полягає у забезпеченні того, щоб Rust поводився точно так само, як Zig, який він замінює.
Набір тестів як контракт поведінки
Уявіть собі агента, який отримує лише вказівку «переписати цю базу коду на Rust». Ця інструкція залишає відкритими всі важливі рішення: які частини можна змінити, а які мають залишатися незмінними? Які скорочення є прийнятними? Яка поведінка пам’яті є критично важливою? І, насамперед, звідки хтось може дізнатися, що результат правильний?
Bun вже мав відповідь на останнє запитання: велику та досконалу набір тестів. Як тільки тести починають розглядатися як контракт, агент більше не вигадує реалізацію — він відтворює поведінку, яка вже записана у виконуваному форматі, і кожен файл, який він створює, або відповідає цьому контракту, або ні.
Що можуть та чого не можуть обіцяти тести
Набір тестів — це не доказ коректності. Він перевіряє лише ту поведінку, яку хтось планував зафіксувати, і перекладений файл може пройти всі тести, залишаючись при цьому відмінним у шляху, яким ніхто не користувався. Те, що забезпечують тести, — це механізм зворотного зв’язку, який набагато сильніший за прохання до моделі оцінити власний результат. Без них генерований перепис може здаватися цілком правдоподібним, тихо змінюючи семантику. З їх допомогою кожна генерована зміна мусить заслужити своє місце.
Описаний робочий процес Bun містив кілька етапів, які послідовно виконувалися: компіляція, набір тестів, перевірка на підтримуваних платформах, рев’ю коду та подальша верифікація. Модель генерувала кандидатські варіанти; інженерний процес вирішував, які з них залишаться. Саме цей розподіл обов’язків є ключовою ідеєю.
Чому посібник з портування був настільки ж важливим, як і сама модель
Перш ніж агенти почали працювати з тисячами файлів, за повідомленнями, проект створив детальний посібник з портування, у якому описувалося, як конструкції Zig слід виражати в Rust. У ньому розглядалися мапування типів, правила найменування, поширені шаблони перекладу, способи обробки залежностей та чіткі обмеження щодо того, що дозволено робити агентам.
Це дозволяє замінити нечітке запитання (“написати цей файл на Rust”) на більш конкретне: перетворити файл за узгодженими правилами мапування, зберегти його спостережувану поведінку незмінною та не втручатися в архітектуру. У такому середовищі агенти працюють набагато краще, оскільки коло прийнятних варіантів відповідей є малим та чітко визначеним.
Посібник також полегшує процес перевірки. Замість нечіткого запитання “чи все гаразд?” рецензент може поставити два конкретні запитання:
- Чи поводиться цей код на мові Rust так само, як Zig, який він замінює?
- Чи дотримувався агент правил перекладу, узгоджених у проекті?
До обох запитань існують відповіді, які можна перевірити, що саме потрібно під час процесу перевірки, коли обсяг змін величезний.
Що містить корисний посібник з портування
Якщо ви плануєте подібну міграцію, навіть у значно меншому масштабі, такий посібник зазвичай описує:
- як кожен тип даних, контейнер та механізм обробки помилок вихідної мови відповідають аналогам у цільовій мові
- правила найменування, щоб генерований код був послідовним у всіх файлах та агентах
- які залежності можна ввести, а які заборонені
- шаблони, яких агент не повинен використовувати, навіть якщо вони дозволяють скомпілювати файл
- що вважається „завершеним“ для окремого файла чи модуля
Цей загальний урок стосується не лише Bun: система інструкцій для агента може впливати на якість результату майже так само, як і вибір моделі. Команди, які вже мають файли інструкцій для агентів, впізнають цю закономірність; наш посібник з створення ефективного файлу CLAUDE.md охоплює той самий принцип для повсякденної роботи.
Вірна реалізація на Rust не завжди є ідіоматичною реалізацією на Rust
Усі, хто очікує, що портований код буде схожий на проект, написаний з нуля на Rust, будуть розчаровані, і це є навмисним. Вірний порт має виглядати так само, як те, з чого його було портовано.
Це створює помітний компроміс. Zig може лаконічно описувати певні операції низького рівня, тоді як Rust схильний бути більш чітким щодо типів, термінів життя, власності та меж небезпечного коду. Тому компактна функція на Zig може перетворитися на значно довшу функцію на Rust. Додаткова довжина є наслідком оптимізації під поведінкову еквівалентність, а не під елегантність, і не є доказом того, що результат некоректний.
Корисно розділяти два твердження:
- "Це не той Rust, який я б написав з нуля."
- "Цей Rust є некоректним."
Перше — це судження про стиль; друге — це дефект. Розглядати їх як одне й те саме призводить до хибної критики механічних адаптацій.
Спочатку адаптація, потім оптимізація
У описаному підході механічний переклад та подальше вдосконалення розглядалися як окремі етапи. Спочатку змусити Rust поводитися як Bun, а потім вдосконалити сам Rust. Такий розподіл роботи означає, що команда ніколи не змушена одночасно розбиратися у двох великих, взаємопов’язаних змінах. Якщо під час очищення з’являється регресія, її можна приписати саме процесу очищення, адже базова версія вже була перевірена за допомогою тих самих тестів.
Правильне читання блоків unsafe
Спостерігачі, які переглядали порт, помітили велику кількість блоків unsafe та вважали це ознакою низької якості коду на Rust. Ця реакція зрозуміла, але ігнорує те, як код опинився у такому стані.
Rust вимагає, щоб потенційно небезпечні операції, такі як робота з необработаними вказівниками чи виклик сторонніх функцій, були явно позначені ключовим словом unsafe. У Zig немає еквівалентного позначення. Оригінальний код Bun сповнений маніпуляціями пам’яттю низького рівня, роботою з вказівниками та викликами компонентів на C та C++, тому у вірному перекладі більша частина цих елементів природно буде позначена як unsafe у Rust. Крім того, Bun вбудовує JavaScriptCore та взаємодіє з іншими нативними бібліотеками, а межа між кодом Rust та C чи C++ за своєю природою вимагає використання небезпечних операцій.
Іншими словами, порт не додав нової небезпеки; він зробив існуючу небезпеку видимою. Проста кількість блоків unsafe мало що говорить про якість коду. Більш інформативними є такі запитання:
- Чому саме ця операція мусить бути небезпечною?
- Чи достатньо мала небезпечна область, щоб її можна було аналізувати?
Ці запитання також надають чіткий план для фази очищення: зменшити обсяг небезпечних ділянок, загорнути їх у безпечні абстракції та задокументувати інваріанти, від яких кожна з них залежить.
Коли процес перекладу виявляє можливості для покращень
Буквальний перенесення коду все ще може виявити можливості, які були приховані у первинному дизайні. Один зі згаданих прикладів стосувався шляху виконання коду, де реалізація на Zig зверталась до C++ для отримання певної інформації. У Rust відповідні дані, локалізовані за потоком, можна було отримати безпосередньо, уникнувши цього проміжного виклику.
Висновок не полягає у тому, що Rust перевершує Zig за швидкістю; таке узагальнення не витримає ретельної перевірки. Суть проблеми є вузькішою та кориснішою: переміщення коду через межі мов змушує когось або щось уважно розглядати кожен шлях виклику, і ця перевірка іноді виявляє роботу, яка ніколи не була необхідною. Такі висновки заслуговують на оцінку окремо, а не на включення до дискусій про мови програмування.
Куди змістилася інженерна робота
Міграція не припинила інженерну роботу; вона лише змінила її місце. У традиційному розробленні значна частина людського часу йде на набір коду реалізації. У розробленні з допомогою агентів більша частина цього часу спрямовується на:
- визначення обмежень та правил перекладу
- проектування робочих процесів, у яких працюють агенти
- написання та покращення тестів
- перегляд створених змін
- діагностика несправностей
Інженер несе відповідальність за систему, яка створює та перевіряє код, а не за кожну окрему рядок коду. У великому проекті цей цикл виглядає приблизно так: специфікація, потім генерація, потім компіляція, потім тестування, потім перегляд, потім корекція, і знову по колу. Модель бере участь у кількох з цих етапів, але саме конструкція циклу визначає, чи має результат якусь цінність. Саме такий робочий процес, а не кількість рядків, є справжньою інновацією.
Чому Bun був гарним кандидатом
Не кожна база коду підходить для цього підходу, і у Bun було кілька переваг:
- функціональна реалізація, яка може слугувати орієнтиром
- відома, стабільна архітектура
- поведінка, яку можна було спостерігати за допомогою існуючої набору тестів
- чітко обрана мова цілі
- база коду, яку можна розділити на досить незалежні файли та компоненти
- єдиная, вимірювана мета: зберегти програму, змінивши мову
Порівняйте це з проханням до агента розробити новий продукт, де немає прикладної реалізації, а поняття „правильного“ є суб’єктивним. Загальне правило полягає у тому, що чим точніше можна описати бажану поведінку, тим більша частина реалізації може бути автоматизована. Це не означає, що агенти можуть безпечно братися за будь-який великий проєкт. Це означає, що автоматизація працює найкраще, коли кінцевий результат можна виміряти.
Що міграція не доводить
Легко переоцінити такий результат, тому варто чітко вказати його обмеження. Проєкт Bun не доводить, що ШІ може замінити інженерів програмного забезпечення. Він не доводить, що кожну базу коду можна перекласти таким чином, що генерований код автоматично підлягає підтримці чи що Rust завжди швидший за Zig. І він точно не виправдовує об’єднання величезних запитів на зміни, створених за допомогою ШІ, з звичайним кодом продукту.
Навпаки, це показує саме протилежне. Робота залежала від ретельних тестів, чітких правил, перевірок, рецензування, виправлення помилок та постійного людського нагляду. Аналіз опублікованої схеми роботи також вказує на те, що агенти не залишалися без нагляду; люди контролювали процес та коригували його у міру виникнення проблем. Роль інженерного судження не стала менш важливою — навпаки, саме на ньому ґрунтувалося все інше.
Перевірка стає вузьким місцем
Протягом десятиліть написання коду вважалося повільним етапом. Уявімо, що агент може створити 10 000 рядків за той час, який раніше програміст витрачав на 500. Очевидною реакцією є святкування прискорення, поки не виникає наступне запитання: хто буде перевіряти ці 10 000 рядків?
Створення коду зараз є дешевим. Однак переконання у його коректності залишається дорогим, причому витрати різко зростають у випадку часу виконання, компіляторів, баз даних, операційних систем та коду з високими вимогами до безпеки, де невелика помилка може призвести до серйозної проблеми. Це вказує на зростаючу цінність усього, що перевіряє код, а не створює його: наборів тестів, засобів для спостереження, статичного аналізу, методів fuzzing, формальних підходів, сендбоксінгу та аналізу з точки зору потенційних загроз. Команди, які отримають найбільшу користь від агентів для написання коду, можуть бути тими, у яких є найсильніші системи перевірки, а не обов’язково тими, хто має доступ до найкращих моделей.
Практики, які можна скористатися для власних змін за допомогою ШІ
Для застосування цих порад не потрібен проєкт розміром з час його виконання. Вони так само ефективні під час міграції сервісу між фреймворками чи перетворення кодової бази на JavaScript у TypeScript.
Створіть тести перед великими змінами
Ретельний набір тестів є виконуваною специфікацією. Чим більше функцій можна перевірити автоматично, тим більше роботи з реалізації можна безпечно передати іншим. Якщо рівень покриття низький, його підвищення є першою ціллю міграції, а не щось другорядне.
Запишіть правила
Уникайте запитів на кшталт «перепиши це». Вкажіть архітектуру, правила найменування, дозволені та заборонені залежності, швидкі способи виконання, які заборонені, очікування щодо обробки помилок та критерії прийняття для кожної одиниці роботи.
Тримайте процес генерації та перевірки окремо
Агент ніколи не повинен бути єдиним суддею свого власного результату. Незалежний етап перевірки, чи то людина, чи інший агент з іншим завданням, або обидва разом, дає нову перспективу та допомагає виявити проблеми, яких не помічає етап генерації.
Пілотування на невеликій, репрезентативній групі
Спочатку протестуйте процес на кількох типових файлах. Неправильні припущення легко виправити, якщо вони впливають на десять файлів, але стають дуже складними для виправлення, коли їх повторюється десятки тисяч разів.
Вважайте створений код ненадійним, доки це не буде доведено
Код, який компілюється, — це не обов’язково код, який працює. Компіляція — це лише одна з кількох перевірок, а не доказ правильності.
Змушуйте людей нести відповідальність за важливі рішення
Агенти можуть дуже швидко досліджувати величезний простір можливих реалізацій. Вирішення про те, що має робити система та які ризики є прийнятними, залишається обов’язком людини.
Поза дебатами Zig проти Rust
Є спокуса представити ситуацію як боротьбу Zig проти Rust, вручну написаний код проти ШІ чи люди проти агентів. Жоден з цих підходів не пояснює суті проблеми. Порт Bun краще розуміти як експеримент з того, як створюється програмне забезпечення, коли створення коду коштує майже нічого. Як тільки система може перекладати сотні тисяч рядків коду, центральне питання змінюється з «Чи можемо ми це реалізувати?» на «Чи можемо ми створити надійний процес, який покаже нам, чи є реалізація правильною?» Це зовсім різні інженерні проблеми.
Як слід оцінювати результат
Початковий переклад — це лише перша фаза. Кодову базу, створену шляхом механічного перенесення, з часом можна зробити більш ідіоматичною: перевіряти та скорочувати небезпечні ділянки, покращувати абстракції, налаштовувати продуктивність та відмовлятися від шарів сумісності. Як і будь-яка система для продакшну, її остаточно оцінюватимуть за тим, чи працює вона для реальних користувачів. У джерельному матеріалі зазначено, що Bun продовжував випускати нові версії після міграції; перевірте репозиторій та журнал змін проекту, щоб дізнатися про його поточний стан.
Значуща оцінка буде ґрунтуватися на довгострокових показниках, а не на обсязі переписування коду:
- чи залишається час виконання програм стабільним у різних версіях
- чи стає код легшим для підтримки
- чи залишається продуктивність конкурентоспроможною
- чи стають менш поширеними баги, пов’язані з пам’яттю
- чи можуть учасники проекту розуміти та вдосконалювати новий код
Основні висновки
- Цінність міграції Bun полягає у циклі правил, тестів, перевірки та корекції, а не у обсязі створеного коду.
- Формулювання переписування як портування зі збереженням поведінки надає агентам вимірюваний ціль та рецензентам конкретний перелік завдань.
- Посібник з портування звужує діапазон прийнятних результатів та уможливлює масштабну перевірку.
- Об’ємний або схильний до небезпек Rust у вірному порту часто є ціною еквівалентності; оцінюйте небезпечний код за його межами, а не за кількістю.
- У міру того, як генерація стає дешевшою, інвестиції у перевірку стануть тим, що відрізнятиме команди, а проектування цього зворотного зв’язку все більше стає основою інженерної роботи.