«Простите, но думать всё-таки придётся»: чему учат ИИ-переписывания Campfire

· Искусственный интеллект
DHH поручил ИИ-агенту переписать Campfire с Rails на Rust, Elixir и Go, не читая код. Пётр Сарнацкий разбирает результаты и приходит к выводу, что программирование ещё не «решено».

cover.svg

Создатель Ruby on Rails Дэвид Хайнемайер Ханссон (DHH) решил переписать мессенджер Campfire Once с Rails на Rust — точнее, поручил это ИИ-агенту, поскольку сам читать и писать на Rust не в силах. Позже добавились версии на Elixir и Go. Пётр Сарнацкий увидел в этом ценный эксперимент: что получается, когда опытный программист пользуется ИИ-агентами, не заглядывая в код.

Расплывчатый запрос — подброшенная монетка

Вывод неутешителен для тех, кто надеется перестать читать код. Главная проблема даже не в ошибках, а в том, что множество решений не имеют единственно правильного ответа. Сохранять ли обратную совместимость? Что важнее — задержка или пропускная способность? Допустима ли потеря уведомлений после сбоя? Если запрос недостаточно конкретен, за вас эти вопросы молча решает языковая модель.

Отсюда и расхождения. Версия на Rust не сохраняет полную обратную совместимость: она, например, отбросила CSRF-токен ради удобства кэширования и заменила Redis внутрипроцессными очередями. Версия на Elixir куда ближе к оригиналу. Это различие не зависит от языка — и уже делает сравнение бессмысленным.

Код всё-таки стоит читать

В Elixir-версии все SQL-запросы обрабатывает один последовательный процесс, даже параллельные чтения. Но и Rust-версия не образец: часть операций с базой выполняется синхронно. В асинхронном рантайме Rust планирование кооперативное — если задача не уступает управление, остальные на том же потоке ждут. Блокирующий запрос или синхронный замок, удерживаемый 10 мс, тормозит всё. Автор резюмирует: нет, программирование не «решено».

Бенчмарки — тоже слоп

Зак Дэниэлс замерил доставку уведомлений под нагрузкой: у Rust — 1% успешной доставки. Но оба теста были «замкнутыми» (клиент шлёт сообщение, дождавшись ответа). Сарнацкий перезапустил замер с постоянной частотой запросов: при 100 POST/с Rust доставлял ~14% событий, Elixir — ~60%. Однако Rust не выдавал HTTP-ошибок, а Elixir терял по тайм-ауту ~23% запросов, с задержкой доставки до 180 секунд.

Причина потерь в Rust — канал tokio::sync::broadcast с ёмкостью 256; переполненный получатель получает ошибку Lagged. У Elixir очереди GenServer по умолчанию безграничны. Поднять ёмкость до 16384 — и доставка вырастает до ~90%, но задержка взлетает с 11 до 130+ секунд. По мнению автора, это хуже: иногда правильнее «упасть быстро» и отключить отстающего клиента, чем обслуживать его мучительно медленно. Elixir же при 100 запросах/с съедал 1,8 ГБ памяти — что лучше, потерять сообщения или получить OOM-kill?

Вывод

Программирование — это компромиссы. Elixir хорош в конкуренции, но не серебряная пуля. Думать критически по-прежнему необходимо: не делать поспешных выводов по одной метрике, знать, когда системе стоит отказать, и помнить, что хорошие бенчмарки писать трудно.


Источник: Hacker News

Комментарии

Войдите, чтобы комментировать.

  • Пока нет комментариев.