javascript

Разработка мигратора кода с использованием ИИ на примере миграции с Linaria на CSS Modules

  • суббота, 28 марта 2026 г. в 00:00:05
https://habr.com/ru/companies/lemana_tech/articles/1011388/

Всем привет!

Меня зовут Михаил Витик, я занимаюсь разработкой больше двадцати лет, а сейчас работаю в Лемана Тех техлидом в сервисной команде, которая поддерживает команды разработки сайта Лемана ПРО. За это время довелось поработать с разными языками и стеками — от Borland C++ и Delphi до .NET и современного TypeScript. В какой‑то момент у нас возникла задача, которая на первый взгляд казалась довольно рутинной, но при более близком рассмотрении оказалась типичным инженерным болотом: много однотипной работы, высокая цена ошибок. А главное, огромные временные затраты.

Нужно было массово переписать стили во множестве проектов: на сайте применяется подход с микрофронтовой архитектурой, порядка 50 отдельных репозиториев, каждый из которых отвечает за свою часть. Именно эта задача и привела меня к идеям автоматической миграции, codemod‑трансформеров и использованию ИИ.

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

В качестве примера будет рассмотрена миграция с Linaria — CSS‑in‑JS решения — на CSS Modules. Я уже выступил с докладом на эту тему на митапе MoscowJS, а теперь по его мотивам пишу этот текст. По ходу дела мы разберемся: 

  • почему прямое использование ИИ для переписывания файлов оказалось плохой идеей,

  • чем хороши codemod‑трансформеры,

  • как они работают под капотом,

  • каким образом ИИ в сочетании с TDD и практиками экстремального программирования позволяет сильно ускорить их разработку.

Почему понадобилась миграция

Основной сайт Лемана ПРО построен вокруг SSR. Исторически мы использовали собственный движок, но постепенно пришли к решению двигаться в сторону более стандартных и поддерживаемых решений вроде Next.js. В процессе выяснилось, что одна из ключевых технических зависимостей мешает этому переходу — библиотека Linaria.

Linaria — это CSS‑in‑JS инструмент, который хорошо работает в SSR‑окружении и позволяет писать стили прямо в TypeScript или JavaScript. У него есть удобные примитивы: можно описывать CSS через tagged template literal, можно создавать styled‑компоненты. Это комфортно в повседневной разработке, но в нашем случае библиотека оказалась плохо совместима с целевой инфраструктурой и поддерживается не так активно, как хотелось бы.

В результате возникла необходимость перевести весь проект на альтернативное решение. Одним из самых простых и понятных вариантов оказались CSS Modules. Таким образом нам понадобилось сделать максимально дешевый переход с Linaria на Module CSS для достаточно большой кодовой базы.

На уровне одного файла это выглядит безобидно. Мы просто выносим стили в отдельный файл с расширением module.css, импортируем классы и используем их в компоненте. Но когда таких мест сотни или тысячи, а репозиториев несколько десятков, задача перестает быть тривиальной. Особенно если учесть, что помимо простых CSS‑блоков есть styled‑компоненты, динамические значения, пропсы, вычисления и другие нетривиальные случаи.

В целом есть три способа решить эту задачу:

  • переписать все руками,

  • переписать с помощью ИИ,

  • переписать автоматически с помощью скриптов или codemod трансформеров.

А теперь поговорим про плюсы и минусы каждого из них.

Ручной труд в XXI веке?

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

Очевидно, что хотелось автоматизации.

Просто попросить ИИ переписать код?

С появлением современных моделей ИИ естественная мысль звучит так: зачем писать какие‑то инструменты, если можно просто скормить файлы нейросети и сказать «перепиши с Linaria на CSS Modules».

Для одного файла это работает. Модель довольно неплохо понимает задачу и может выдать адекватный результат. Но как только речь заходит о десятках тысяч строк кода, начинаются проблемы.

Во‑первых, это дорого. Большие проекты требуют много токенов. Во‑вторых, это долго, потому что нужно обрабатывать файлы по одному или придумывать сложные пайплайны. В‑третьих, результат стохастический. Сегодня модель сработала хорошо, завтра — нет. Появляются галлюцинации, пропущенные случаи, случайные правки. Никакой гарантии повторяемости. И главное — нет формального способа доказать, что все переписано корректно. Поэтому такой путь для серьезной кодовой базы оказался слишком рискованным.

Codemod как оптимальное решение

Здесь на сцену вышли codemod‑трансформеры. Это специализированные программы, которые автоматически преобразуют исходный код по заданным правилам. По сути, это скрипты для массового рефакторинга.

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

Как устроен codemod

Чтобы понять, почему этот подход надежен, важно разобраться в механике. Codemod не работает с текстом напрямую. Сначала исходный код парсится в абстрактное синтаксическое дерево, или AST. Это структурированное представление программы, где каждая конструкция — функция, условие, вызов, импорт — становится узлом дерева.

Дальше трансформер проходит по этому дереву, находит нужные узлы и заменяет их. После этого дерево сериализуется обратно в текст.

Code mode registry

Для JavaScript и TypeScript есть библиотека jscodeshift, которая предоставляет удобный API для таких операций. Мы описываем, что именно хотим найти и на что заменить, а остальное делает инструмент.

Этот подход давно используется для миграций между версиями библиотек, для внедрения best practices, для удаления feature toggle кода и даже для сложных преобразований вроде массовой интернационализации.

Все перечисленные выше миграции и многие другие собраны в отдельном registry, которое можно найти на сайте. Советую поискать там готовое решение прежде чем писать свое, либо попытаться найти похожие и сделать композицию.

Codemod Studio

Если вы не нашли в реестре подходящего трансформера, в его разработке поможет инструмент Codemod Studio. С момента моего выступления команда сместила фокус с классического jscodeshift на собственный проприетарный движок JSSG. Он предлагает более интуитивный синтаксис для некоторых операций, хотя и требует привыкания после стандартного API jscodeshift. Из ключевых преимуществ Codemod Studio стоит выделить готовый бойлерплейт для разработки непосредственно в браузере и бесшовную интеграцию с GitHub. Продвинутые возможности ИИ, включая ModGPT и поддержку MCP (Model Context Protocol), позволяют генерировать код трансформера по текстовому описанию, значительно снижая порог входа. Кроме того, Studio поддерживает автоматическую генерацию тестов на основе ваших примеров "до" и "после", что гарантирует стабильность codemod перед его массовым запуском в репозитории.

Типичные проблемы при написании трансформеров

Когда начинаешь писать первый codemod, быстро становится понятно, что код гораздо разнообразнее, чем кажется. Один и тот же паттерн может быть записан десятком разных способов. Люди используют разные стили, сокращения, форматирование. Плюс всегда находятся пограничные кейсы, которые сложно автоматизировать.

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

Здесь очень помогает подход TDD. Сначала описывается сценарий «было — стало», затем пишется трансформер, который делает тест «зеленым». Со временем так накапливается целый набор кейсов, и надежность решения растет. А кроме того, это позволяет LLM активно переписывать код без опаски, что что-то сломается.

Почему ИИ лучше использовать для написания трансформера?

В какой‑то момент пришла мысль: если писать трансформер вручную долго, почему бы не попросить ИИ помочь? Тогда мы получаем лучшее из двух миров. ИИ ускоряет разработку инструмента, а сам инструмент работает уже детерминировано  и без галлюцинаций. Код мигрирует не модель, а обычная программа. Это снимает вопросы стоимости, безопасности и воспроизводимости. ИИ видит только тестовые примеры, а не реальную кодовую базу. Сам же трансформер запускается локально.

Я начал с того, что сделал тестовое окружение для разработки. 

Затем собрал все варианты использования Linaria в проектах. С помощью ИИ получилось быстро сформировать список файлов и сгруппировать сценарии. Это дало понимание масштаба и позволило составить набор тестовых кейсов. Затем был создан минимальный boilerplate на основе react‑codemod. Из него убрали все лишнее, добавили тестовую инфраструктуру и возможность проверять не только TypeScript‑файлы, но и генерируемые CSS‑модули.

Разработка велась в IDE с поддержкой ИИ. По сути, это было парное программирование, только вместо второго разработчика — модель. Я добавлял тест,

просил помочь реализовать логику, запускал тесты, обсуждал с моделью рефакторинг, улучшает структуру.

Неожиданно хорошо заработали практики экстремального программирования. TDD помогал бороться с возможными ошибками модели, а быстрые рефакторинги стали почти бесплатными. Можно было смело просить «сделай код чище», «разбей на функции», «уменьшите сложность». В итоге трансформер постепенно эволюционировал. Код становился проще, понятнее и структурированнее. Метрики сложности заметно уменьшились.

Что получилось в итоге

Вместо месяцев ручной работы появился инструмент, который можно запустить на всей кодовой базе. Он работает быстро, предсказуемо и одинаково каждый раз. Сложные случаи покрыты тестами, а нестандартные можно доработать вручную.

Главное ощущение — это контроль. Мы точно знаем, что именно делает трансформер, и можем доказать корректность через тесты. Это гораздо спокойнее, чем надеяться, что ИИ ничего не перепутает при массовом переписывании.

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

И наконец, практики TDD и экстремального программирования неожиданно получили второе дыхание. Когда стоимость написания и рефакторинга кода падает почти до нуля, хочется тестировать чаще, улучшать структуру смелее и экспериментировать быстрее. Если раньше автоматическая миграция казалась чем‑то сложным и дорогим, то сейчас, с правильными инструментами и помощью ИИ, это становится вполне рутинной задачей.