
Здесь в Берлине я проездом. Не получилось сходить на Гемини Хакатон в Кракове из-за ремонта в доме и кучи сопутствующих хлопот. Буду вайб-кодить на выходных в поездах значит.
Поделюсь, пока интернета хватает только на текстовые сообщения, соображениями о том, что такое код и зачем его нужно скорее похоронить.
Вы, наверное, знакомы с парадоксом Корабля Тесея: если в корабле за время его многолетних путешествий заменяли сломанные доски и через много лет в нём не осталось ни одной молекулы исходного материала — это тот же корабль? Философы, конечно, спорят, но в основном, в практичном реальном мире функционализм побеждает
Проведём мысленный эксперимент, который не выходит из головы.
Возьмём обычное JS-приложение — конвертер единиц. Функция celsiusToFahrenheit занимает три строки: принять число, умножить на 9/5, прибавить 32. Плотный, однозначный код. Машина поймёт, человек — если знает синтаксис.
function celsiusToFahrenheit(value) {
const n = Number(value);
return n * 9 / 5 + 32;
}
Напишем тулзу (я назвал её Tril в честь персонажа известной книги и её рыбки-переводчицы). Рыбка берёт каждую функцию в репозитории и заменяет сухой код на понятный и простой английский текст. Обратите внимание — не комментарий к коду, не документацию, а сам код заменяется. Будто один человек другому по телефону пересказывает, что должно происходить.
Что происходит дальше, думаю, не сложно догадаться. Функция за функцией, как доски в корабле Тесея — весь репозитория заменяется на, возможно, не очень интересную, но связанную и подробную историю изменения состояний переменных, функций. После каждой микро-замены — автоматические тесты. Приложение должно работать после каждой итерации. Плавучесть корабля после ремонта меняться не должна.
На выходе Trillian выдаёт .md файл. Обычный маркдаун. GitHub его рендерит, телефон его показывает, а главно — любой человек его читает.
Для примера выше, в тексте написано буквально следующее:
«Цель: конвертировать температуру из Цельсия в Фаренгейт. Шаг 1: умножить на 9/5. Шаг 2: прибавить 32. Граничные случаи: если вход не число — вернуть NaN. Если null — трактовать как ноль.»
А потом этот маркдаун запускается. tril run поднимает HTTP-сервер. Когда приходит запрос, он не вызывает JavaScript. Он отправляет текстовое описание функции в Claude через инлайн-формат claude -p "PROMPT" и ждёт результат. LLM читает инструкцию на человеческом языке и выполняет её. Просто.
С простецкой функцией перевода градусов в непонятную американскую фигню ИИ справился отлично. Тесты подтвердили.
Понятно, что это было медленно и дорого, и вообще не практично. Каждый запрос — это вызов LLM, задержка в секунды вместо микросекунд. Но дело не в производительности. Дело в том, зачем вообще существуют языки программирования?
Они существуют от большой нужды. Их придумали занудные люди, чтобы машина давала точный результат через свою лямбда-математику и Тюринговые примитивные операции. Машина сперва понимала 0 и 1, а теперь говорит на всех языках человечества одновременно лучше чем любой из отдельно взятых индивидуумов.
Мы должны были выдумывать интерфейсы, ведь машина не понимала наших намерений. Ну, оукеей, поскрипели мозгами и изобрели формальные языки, чтобы перевести мысль в инструкции, в процедуры, чтобы кремний мог их исполнить с точностью до бита. Высоко-уровневые языки — это кайф для тех, кто писал на перфокартах, но по сути они ушли не очень далеко: JavaScript, Python, Rust — они все — костыли. Мосты через пропасть между «я хочу» и «спасибо, за результат».
Код — это сжатый человеческий язык, из которого убрали всю неоднозначность. Мой прототип «Trillian» делает обратное: разжимает челюсти детерминизма, вытаскивает концентрат и на понятном объясняет, что там происходит. Не нужно знать про заебавший в студенчестве оператор ‘;’, без которого компилятор вываливает стотыщ экранов ошибок. Оказывается, LLM способна исполнить этот текст достаточно точно, как интерпретатор исполняет код. (Это теория, я, конечно, не писал на эту тему докторскую и не прогонял миллионы примеров, тут, как говорится, добро пожаловать! Расскажите, что получилось потом)
Pull request в Trillian-репозитории — это не зашифрованный для обычного человека diff в синтаксисе, описанном в загадочных книгах с чёрно-белыми животными. Это редакторская правка обычного текста, каким мы, все нормальные люди, думаем. «Code review» становится просто «review»: «Тут написано «умножить на 9/5» — может, лучше «умножить на 1.8»?» Барьер между теми, кто пишет софт, и теми, кто им пользуется, начинает размываться.
Для тех, кто каждый день только и делает, что болтает с роботами и голосами в своей голове (ну, я например) — этот качественный скачок уже случился. Именитые программисты, включая легендарного создателя Alpha Fold, один за другим делятся в своих блогах, что уж несколько месяцев не писали ни строчки в IDE.
Сайт проекта: tril.cc
Примеры доступны в этом репозитории: https://github.com/sliday/tril
Unit Converter (JavaScript → English)
Максимально простой веб-конвертер на Express.js: шесть функций для градусов, километров, килограммов. Trillian разобрал и описал каждую функцию на английском, включая граничные случаи (null, строка, отрицательное число), и сгенерировал converter.md — GitHub-релевантную документацию. Затем tril run поднял HTTP-сервер, отправляющий текстовое описание функции в Claude и ожидающий ответ. Пять тестов (100°C→°F, 32°F→°C, 1 км→мили, 1 кг→фунты, −40°C→°F) показали совпадение результатов: JS и LLM дали одинаковые числа до шестого знака. Исходник → результат.
Stupid AI Coder (Python → English)
stupid-ai-coder — мой проект на Python двухлетней давности, 625 строк: CLI-утилита, которая итеративно генерирует код через LLM, тестирует его, ловит ошибки, управляет процессами с таймаутами и SIGKILL, парсит AST для извлечения импортов, показывает цветные диффы в терминале. Двадцать зависимостей, асинхронность, треды, работа с файловой системой — совсем не игрушечный пример. Trillian нашёл 25 функций и классов, превратил каждый в структурированный блок на английском, и на выходе получилось 705 строк маркдауна, который местами информативнее оригинального кода: например, явно описано, что run_with_timeout сначала шлёт SIGTERM всей группе процессов, ждёт 0.1 секунды и только потом SIGKILL — в Python это приходилось вычитывать из вложенных if-ов. Результат конвертации.
Корабль плывёт.