К содержимому
Claude Code с 0:полный курс
Новости ClaudeАвтор: Михаил Кузьмицкий

Как в Anthropic мигрируют миллионы строк кода с помощью Claude

Русская адаптация материала Anthropic — подготовлена с участием AI, проверена автором.

Коротко

История о том, как Anthropic перевела Bun с Zig на Rust за две недели и Python-проект на 165 тысяч строк TypeScript за выходные — и какой процесс из шести шагов за этим стоит.

Ещё пару лет назад миграция крупного проекта с одного языка программирования на другой — это история на годы. Команда замораживает роадмап, держит две параллельные кодовые базы, а в итоге получает 90% паритета и вдвое больше головной боли, чем было в начале. Именно поэтому такие проекты обычно откладывали до последнего — пока не становилось совсем невыносимо.

Символ миграции кода: река, разделяющаяся на два параллельных потока

За последний месяц разработчики в Anthropic мигрировали десять кодовых пакетов размером от десятков до сотен тысяч строк, используя Claude Fable 5, Claude Opus 4.8 и гибкие рабочие процессы с агентами. В этом посте — два самых показательных примера и шесть шагов процесса, который за ними стоит.

Два примера, которые меняют представление о возможном

Джарред Самнер, сооснователь Bun и сотрудник Anthropic, перевёл Bun с языка Zig на Rust с помощью Claude Code. Миллион строк кода был написан за меньше чем две недели, при этом 100% существующего набора тестов Bun проходили в CI ещё до слияния. После мерджа обнаружилось 19 регрессий — все они уже исправлены. Rust-версия Bun встроена в Claude Code с июня.

Майк Крегер, соруководитель Anthropic Labs, перевёл внутренний Python-проект на 165 000 строк TypeScript за одни выходные. В процессе участвовали сотни агентов, восемь фазовых «шлюзов» (gate), три раунда адверсариального ревью и финальная проверка паритета — построчное сравнение вывода каждой команды между Python-оригиналом и новым TypeScript-кодом.

Иллюстрация к статье про миграцию кода

Оба случая объединяет один принцип: команды не пытались «поправить» существующий код руками. Они выстроили процесс — цикл перевода, проверки и исправления, — который сам довёл проект до готового результата. Это и есть ключевая мысль всей статьи: ты не чинишь код, ты чинишь процесс (цикл), который этот код производит.

Когда миграция действительно оправдана

Команды берутся за миграцию, когда меняется ландшафт: известный компромисс, на который пошли когда-то, стал слишком дорогим, появился лучший подход, или экосистема исходного языка усыхает. Джарред изначально выбрал Zig для Bun, потому что он давал производительность уровня C при радикальной простоте — идеально для соло-основателя, писавшего Bun «за год в тесной квартире в Окленде, ещё до эры LLM». У этой простоты были известные издержки, и ещё квартал назад их одних не хватило бы, чтобы оправдать заморозку роадмапа на несколько кварталов.

Сегодня CLI Bun скачивают больше 10 миллионов раз в месяц, и он активно используется внутри самого Claude Code. Но бизнес-кейс всё равно нужен: миллионнострочные миграции больше не стоят 3–4 миллиона долларов инженерных ресурсов и четыре года времени, но они всё ещё обходятся в десятки-сотни тысяч долларов. Миграция Bun потребовала 5,9 миллиарда входных токенов (без кеша) и 690 миллионов выходных — это около 165 000 долларов по ценам API. Основная часть проекта Майка обошлась в 27 миллионов токенов.

Для Майка триггером стал этап компиляции. Внутренний инструмент его команды собирался в единый бинарник для пользователей, и сборка на Python-тулчейне занимала около восьми минут на платформу — суммарно до 30 минут ожидания на весь набор платформ при каждом релизе. После переноса на TypeScript та же сборка занимает около двух секунд, бинарник запускается в 6 раз быстрее, а отдельный пайплайн деплоя команда просто отключила.

Совет

Хороший повод для миграции больше не обязан быть «экзистенциальным». Год патчей одной и той же проблемы с памятью в чейнджлоге или один хронический узкий узел — уже достаточное основание попробовать.

Почему ИИ меняет саму математику миграций

Claude Fable 5 — самая мощная общедоступная модель Anthropic, и вместе с Opus 4.8 они особенно хороши в делегировании и проверке параллельной работы через сабагентов. Крупные миграции кода оказались почти идеальным сценарием для таких моделей — вот почему:

Свойство миграцийПочему это подходит агентам
Работа параллельнаТысячи независимых файлов и модулей — агенты работают одновременно, а не по очереди
Контекст полный и понятныйСтарый код сам служит спецификацией и опорой для правил перевода
Есть встроенный «судья»Тестовый набор объективно проверяет результат — модель может биться за истину сутками без арбитра-человека
Очередь задач формируется самаПровал компилятора или теста автоматически становится следующей задачей для агента
Нужна строгая консистентностьРевьюеры ссылаются на конкретное правило при каждой находке — нарушение становится задачей в очереди, а не тихим расхождением

И Майк, и Джарред использовали Fable на ключевых этапах миграции — в частности, в «консультативном» режиме, когда более мощная модель формирует правила, а более лёгкие модели массово применяют их, экономя токены. Кстати, если тебе интересно, как в принципе делегировать сложную работу моделям через агентные сценарии, посмотри бесплатный курс zero2claude — там разбирается именно эта логика, только на простых примерах для новичков.

Обязательное условие: сильный «судья»

Прежде чем начинать миграцию, нужен надёжный судья — измеримое условие успеха и выхода из процесса. Судья должен уметь оценивать оригинальный и целевой код на равных условиях, а это непросто: тесты, написанные для исходного языка, часто зависят от внутренних функций, которых в целевом коде просто не существует.

Чтобы построить такого судью, нужно сделать три вещи: классифицировать существующие тесты (какие можно выразить через внешние вызовы, а какие завязаны на внутренние детали, которые не переживут перенос), переписать переносимые тесты в вид ассертов, работающих против обоих вариантов кода (и проверить адверсариальными агентами, что переписанные тесты не стали слабее оригинальных), и наконец — валидировать самого судью: прогнать его на исходном коде (должен пройти) и на заведомо сломанном (должен упасть). Судья, который не ловит поломку, — не судья.

У Джарреда был большой тестовый набор, написанный на третьем языке (TypeScript), но так бывает не у всех. Для своего Python-в-TypeScript проекта Майк создал контрольный набор из семи реальных сценариев и считал любое изменение поведения багом, который нужно исправить.

Схема шести шагов процесса миграции с ревью и шлюзами на каждом этапе

Шаг 1 — Свод правил, карта зависимостей и инвентарь пробелов

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

Форма свода правил зависит от главного архитектурного решения: сохранит ли новый код ту же структуру, или его перепишут заново. В первом случае (путь Джарреда) правила — это, по сути, таблицы соответствия типов и идиом между языками со ссылками на инвентарь пробелов для сложных мест. Во втором случае (путь Майка) — это скорее проектный документ. Джарред формировал свои правила в диалоге с Claude, вырабатывая политику для каждой зоны неопределённости, а также использовал восемь специализированных сабагентов — каждый ревьюил свою категорию типичных ошибок на основе его собственной инженерной интуиции.

Карту зависимостей файлов нужно построить, чтобы правильно разбить работу на параллельные потоки: какие файлы переводить первыми, а какие объединять в одну партию. Для многих легаси-кодовых баз и языков вроде C/C++ и Python таких явных манифестов зависимостей нет — их приходится вычислять отдельно, и Claude Code умеет разворачивать агентов для написания и прогона детерминированного скрипта, строящего эту карту через цикл проверки и исправления.

Инвентарь пробелов фиксирует то, что новый язык требует иначе, чем старый. При переходе с Zig на Rust ключевым различием стало ручное управление памятью: в Zig компилятор пропустит функцию, которая возвращает буфер и «забывает» упомянуть в комментарии, что вызывающий код обязан его освободить — утечка проявится только во время выполнения. В Rust владение буфером явно переходит вызывающей стороне, память освобождается автоматически, а попытка использовать её после перемещения или освободить дважды просто не скомпилируется.

При переходе с Python на TypeScript пробелом стали интерфейсы и контракты. В Python функция может принять любой объект с нужными методами — какие объекты реально передаются, можно узнать только вычитав всю кодовую базу. В TypeScript контракт (интерфейс с сигнатурами методов) должен быть явно описан, прежде чем код скомпилируется. И Джарред, и Майк создавали отдельные файлы-инвентари для фиксации этого неявного знания — только Джарред делал это заранее, а Майк сначала перевёл код и уже потом собрал инвентарь через аудит постфактум.

Шаг 2 — Стресс-тест правил на малой выборке

Второй шаг — это своего рода «пробный рейс» перед полномасштабной миграцией. Джарред запустил три параллельных агента: один переводил три файла строго по своду правил, второй переводил те же файлы «как опытный Rust-инженер» без жёсткой привязки к правилам, а третий сравнивал два результата и на основе разницы формулировал новые правила перевода.

На этом этапе Джарред поймал два критических изъяна в правилах, которые иначе размножились бы по всем 1 448 файлам проекта Bun и создали массу проблем при полном развороте миграции. Такой стресс-тест построчного сравнения работает только для миграций, сохраняющих структуру кода, — когда два перевода одного файла можно честно сопоставить строку к строке. Если свод правил предполагает архитектурное переосмысление (как у Майка), приходится проверять правила иначе — например, через сквозные прогоны на небольшом реальном сценарии с последующим ревью расхождений.

Иллюстрация процесса ревью и исправления при миграции кода

Дальше — циклы, шлюзы и финальная сверка

После стресс-теста процесс масштабируется по тому же принципу: агенты параллельно переводят батчи файлов по проверенным правилам, а любой провал компилятора или теста автоматически становится следующей задачей в очереди — без человека-арбитра. У Майка это выглядело как восемь фазовых шлюзов и три раунда адверсариального ревью, где отдельные агенты специально искали расхождения в поведении между версиями. Финальным условием прохождения служила построчная сверка вывода каждой команды между Python-оригиналом и TypeScript-портом — любое отличие считалось багом, который нужно закрыть, а не «допустимой погрешностью».

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

Важно

Стресс-тест на малой выборке — не формальность. Именно на этом шаге Джарред поймал баги, которые при масштабировании на 1 448 файлов превратились бы в системную проблему всего проекта.

Что это значит для тебя

Миграции кода перестали быть многолетним проектом, который откладывают до последнего. Худший сценарий теперь — удалить ветку и попробовать заново, а не тащить две кодовые базы годами. Но это не значит, что процесс тривиален: нужен надёжный судья для проверки результата, чёткий свод правил, карта зависимостей, инвентарь неявных требований нового языка — и готовность прогнать весь цикл несколько раз, если первая версия правил окажется неидеальной.

Если тебе интересно, как агенты вообще делегируют друг другу сложную работу и проверяют результат друг за другом, стоит почитать про Claude Fable 5 в Claude Cowork — там показан похожий принцип на менее масштабных задачах.

Частые вопросы

Сколько стоит такая миграция на практике?

Судя по примеру Bun, перевод около миллиона строк кода потребовал 5,9 миллиарда входных токенов (без кеша) и 690 миллионов выходных — примерно 165 000 долларов по ценам API. Проект Майка Крегера обошёлся в 27 миллионов токенов на основную часть работы. Это заметно дешевле классической многолетней миграции силами инженерной команды, но всё ещё требует реального бюджета.

Подходит ли этот подход для любого языка и любой кодовой базы?

Стресс-тест построчного сравнения из шага 2 работает только для миграций, сохраняющих структуру кода (как Zig в Rust у Джарреда). Если новый код переосмысливается архитектурно (как Python в TypeScript у Майка), правила проверяют по-другому — через сквозные прогоны и последующий аудит расхождений, а не построчное сравнение.

Что самое важное нужно подготовить до старта миграции?

Надёжного «судью» — способ объективно проверить, что новый код ведёт себя так же, как старый. Без него нет измеримого условия успеха. Это может быть переписанный тестовый набор или контрольный набор реальных сценариев, как у Майка Крегера, — и его обязательно нужно проверить на заведомо сломанном коде, чтобы убедиться, что он реально ловит поломки.

Если хочешь попробовать всё это руками — начни с бесплатного курса «Claude Code и терминал: с 0».

Источник

По мотивам статьи Anthropic «How Anthropic runs large-scale code migrations with Claude Code». Пересказали по-русски для новичков.

Читайте также

Попробуй на практике

Бесплатные интерактивные курсы по теме — прямо в браузере, с нуля.