Архив рубрики ~Лента новостей~

Генерация кода: сокращаем рутину в разработке

Генерация кода: сокращаем рутину в разработке
Генерация кода: сокращаем рутину в разработке

Привет, Хабр! Меня зовут Иван, я DevOps‑инженер в ИТ‑холдинге Т1. В современной разработке автоматизация — это давно не «роскошь», а «базовый минимум». Однако многие команды до сих пор ограничиваются лишь простыми возможностями IDE (Integrated Development Environment), упуская потенциал генерации кода. В прошлом году я выступал с этой темой на конференции Импульс Т1. В статье расскажу подробнее, как перейти к генерации кода в масштабах проекта и зачем разбираться в синтаксических деревьях.

Зачем создавать код автоматически

Главная цель генерации кода — не просто сэкономить время разработчика, а обеспечить соответствие кода заданной схеме (например, OpenAPI). Когда генерация настроена правильно, исчезает риск рассинхронизации схемы и реализации, и вносить изменения можно значительно быстрее.

Этот подход применим во многих задачах:

  • создание однотипного кода, часто встречающегося в проекте;

  • создание API‑клиентов из различных схем: OpenAPI, AsyncAPI, gRPC и др.;

  • создание конфигураций (Helm, Ansible) и инфраструктуры;

  • миграция баз данных;

  • стилизация, линтинг, форматирование кодовой базы;

  • автоматический рефакторинг.

Уровни автоматизации: от сниппетов до среды выполнения

Внедрять генерацию кода можно на разных этапах жизненного цикла приложения:

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

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

  • Генерация кода для общих модулей: API‑клиенты, схемы сообщений в брокере, схемы баз данных.

  • Генерация кода во время сборки: встраивание URL бэкенда во фронтенд, встраивание ключей для проверки лицензии, Whitelabel‑кастомизация.

  • Генерация кода во время развёртывания: встраивание URL бэкенда во фронтенд, патчинг, создание инфраструктуры.

  • Генерация в среде выполнения: продвинутый уровень, позволяющий менять логику программы на интерпретируемом языке во время выполнения. Также это используют в no‑code и low‑code средах для обфускации или расширения возможностей языка (как, например, в PyTest, который динамически трансформирует код для улучшения отладки).

Как сделать генератор

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

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

Представим, что у нас есть приложение, для которого необходимо перенести список текстов из json в константы. Нам нужно сгенерировать так, как показано справа:

f679c315023ff894f558771d926d366f

Воспользуемся конкатенацией. Сначала получим список переводов (получение записано в константу для упрощения примера):

TRANSLATIONS = { «hello»: “Привет, {username}!”, «welcome»: “Добро пожаловать!”, «goodbye»: “Пока, {username}!”, }ab5d62730f5f424f145cfa342564cfbc

Теперь генерируем код: получаем пары ключ‑значения из словаря, записанного выше. Далее к ключу добавляем префикс MESSAGE и переводим в UPPERCASE, обёртываем значение в кавычки и выводим результат в консоль.

for key, value in TRANSLATIONS.items(): # MESSAGE_{key.upper()} = «{value}» key = «MESSAGE_» + key.upper() print(key + ‘ = «‘ + value + ‘»‘)

Если у вас есть API‑схема с рекурсией, то вы можете расширить метод и добавить рекурсивную генерацию.

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

Масштабируемый подход (шаблонизация)

Если генератор должен поддерживать несколько языков программирования (например, Python и JavaScript) или пользовательские шаблоны, то прямая конкатенация строк становится неудобной. В этом случае правильнее использовать шаблонизаторы (например, Jinja2). Логика работы здесь разделена: генератор отвечает за получение данных из API или файла, а шаблон определяет структуру результирующего кода.

Например, у нас есть такой шаблон:

{%- for key, value in data.items() -%} MESSAGE_{{ key | upper }} = «{{ value }}» {% endfor -%}

Загрузим его из константы:

import jinja2 environment = jinja2.Environment() template = environment.from_string(«»» {%- for key, value in data.items() -%} MESSAGE_{{ key | upper }} = «{{ value }}» {% endfor -%} «»»)

Передадим значения в поле data шаблона и выведем в терминал:

print(template.render(data=TRANSLATIONS))

После запуска генератора получим в терминале результат.

Вы можете хранить шаблоны в отдельных папках или подгружать их из API. Это позволяет использовать один и тот же движок генератора, просто подставляя нужный шаблон в зависимости от того, какой язык требуется пользователю. Такой подход минимизирует дублирование логики и упрощает расширение функциональности. При этом всё также необходимо следить за экранированием, отступами и корректным синтаксисом.

Изменяем уже существующий код

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

Допустим, у нас уже есть некая кодовая база, которую мы хотим автоматически рефакторить, например, заменив все print на logger.info. Если просто найти и заменить поиском, то можно случайно испортить комментарии.

32cec6675ba56a2fcbc4bc4cc5d42c6a

Можно воспользоваться абстрактным синтаксическим деревом (Abstract Syntax Tree, AST). Вот пример на Python:

f45c949dec3acc61f90b61dfb775e0ef

Можно пройти по дереву и заменить вызовы функции print на logger.info, а затем вывести дерево обратно в терминал.

import ast from ast import * code = «»» # print result of operation print(«Result:», 1 + 2) «»» tree = ast.parse(code) for node in ast.walk(tree): if not isinstance(node, Call): continue if not isinstance(node.func,Name): continue if node.func.id != «print»: continue node.func = ast.Attribute( value=ast.Name( id=»logger», ctx=ast.Load() ), attr=»info», ctx=ast.Load(), ) print(ast.unparse(ast_obj=tree))

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

Управляем стилем кода

В прошлом примере мы потеряли комментарий из кода. Чтобы этого избежать, можно использовать конкретные синтаксические деревья (Concrete Syntax Tree, CST). Они содержат не только логику, необходимую для запуска кода, но и всю его структуру — от запятых до комментариев. Именно CST позволяют проводить безопасный рефакторинг внутри репозитория без потери читаемости.

Преобразуем код в CST, найдём нужный узел:

e0809a45e05ca607932512b05d9f556a

и преобразуем дерево:

a3ad91f15f49d05931043481e3e93646

import libcst as cst tree = cst.parse_module( «# Log result of operationn» «print(‘Result:’, 1 + 2)n» ) class PrintToLogger(cst.CSTTransformer): def leave_Name(self, _: cst.Name, node: cst.Name): if node.value == «print»: # Заменяем переменную print на logger.info return cst.Attribute( value=cst.Name(value=»logger»), attr=cst.Name(value=»info»), dot=cst.Dot(), ) return node transformed_tree = tree.visit(PrintToLogger()) print(transformed_tree.code)

То есть CST обладает всеми возможностями AST, но при этом сохраняет стиль и комментарии.

Будущее: LLM и Model Context Protocol (MCP)

Использование LLM для написания кода выглядит заманчиво, но имеет свои риски: модели могут ошибаться и галлюцинировать, они не имеют прямого доступа к контексту вашего репозитория.

Здесь на помощь приходит Model Context Protocol (MCP). Это протокол, позволяющий моделям взаимодействовать с инструментами разработки: анализировать код проекта, запускать CLI‑команды, получать диагностику от IDE (LSP) и автоматически запускать тесты.

Для того, чтобы сократить количество галлюцинаций LLM в кодовой базе, мы можем предоставить инструменты для генерации кода напрямую языковой модели. Некоторые агенты (например, oh my pi) уже предоставляют инструменты для того, чтобы модель могла менять кодовую базу с помощью AST. Для своей же кодовой базы можно создать скилл агента, прописав логику использования вашего CLI‑инструмента. Альтернативный вариант — реализовать аналогичный функционал через MCP‑сервер, что поможет модели взаимодействовать с кодом и вносить изменения.

С чего начать

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

  • Если у вас есть несколько сервисов, между которыми есть сетевое взаимодействие, то стоит внедрить контракты для этого взаимодействия. В этом поможет OpenAPI‑generator, который создаёт код на множестве языков, позволяет добавлять свои шаблоны и генерировать клиентский и серверный код.

  • Если у вас есть множество микросервисов с аналогичной базой, то поможет Cookiecutter, который создаёт из шаблонов (произвольных) репозитории и проекты (например, микросервисы).

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

Если вы хотите узнать больше о применении генерации кода в реальных проектах, приглашаем вас на конференцию Импульс Т1. 19 ноября в рамках трека «Архитектура и проектирование» мы обсудим, как меняется роль архитектора в эпоху ИИ, как доносить архитектурные решения до разработки и смежных ролей и какие практики лучше работают при построении ИТ‑систем.

Источник: habr.com

Оцените материал:

Поделиться
Понравилась статья? Расскажите другим
ВКонтакте
Читайте также
Новости робототехники Как Generalist использует демонстрационные данные с использованием людей для обучения роботов Архив рубрики ~Коротко из Telegram~ В работе сервисов Microsoft произошёл масштабный сбой Пользователи жалуются на… Новости робототехники Gravis Robotics вложила 200 миллионов долларов на автономное строительство Новости робототехники Человекоподобные машины не так хороши, как принято мечтать Архив рубрики ~Коротко из Telegram~ ✔️ Робособаки вытесняют охранников в США Американские компании начали активно использовать робособак… Архив рубрики ~Коротко из Telegram~ ✔️ River AI привлек $1.1 млрд Игорь Бабушкин, бывший сооснователь… Новости робототехники Uber добавляет дроны Zipline в свою сеть доставки еды Eats. Архив рубрики ~Коротко из Telegram~ Парень навайбкодил сайт, где продаёт рекламные места на… унитазе. И… Архив рубрики ~Коротко из Telegram~ Мой ИИ врач (и как сделать себе такого же) В… Архив рубрики ~Коротко из Telegram~ Чапалах по Antrophic: удаляйте любые ИИ-метки с вашего текста и… Архив рубрики ~Коротко из Telegram~ Маску не хватает всей мировой индустрии чипов. Tesla и SpaceX… Архив рубрики ~Коротко из Telegram~ Нашли библиотеку референсов для сильного веб-дизайна Для всех, кто делает… Архив рубрики ~Коротко из Telegram~ Xiaomi выпустила очиститель воды, который сразу наливает КИПЯТОК — чайник… Архив рубрики ~Коротко из Telegram~ 13 августа вышла Gemini 3.7 Flash. Забавно, что с релиза… Новости робототехники Как Generalist использует демонстрационные данные с использованием людей для обучения роботов Архив рубрики ~Коротко из Telegram~ В работе сервисов Microsoft произошёл масштабный сбой Пользователи жалуются на… Новости робототехники Gravis Robotics вложила 200 миллионов долларов на автономное строительство Новости робототехники Человекоподобные машины не так хороши, как принято мечтать Архив рубрики ~Коротко из Telegram~ ✔️ Робособаки вытесняют охранников в США Американские компании начали активно использовать робособак… Архив рубрики ~Коротко из Telegram~ ✔️ River AI привлек $1.1 млрд Игорь Бабушкин, бывший сооснователь… Новости робототехники Uber добавляет дроны Zipline в свою сеть доставки еды Eats. Архив рубрики ~Коротко из Telegram~ Парень навайбкодил сайт, где продаёт рекламные места на… унитазе. И… Архив рубрики ~Коротко из Telegram~ Мой ИИ врач (и как сделать себе такого же) В… Архив рубрики ~Коротко из Telegram~ Чапалах по Antrophic: удаляйте любые ИИ-метки с вашего текста и… Архив рубрики ~Коротко из Telegram~ Маску не хватает всей мировой индустрии чипов. Tesla и SpaceX… Архив рубрики ~Коротко из Telegram~ Нашли библиотеку референсов для сильного веб-дизайна Для всех, кто делает… Архив рубрики ~Коротко из Telegram~ Xiaomi выпустила очиститель воды, который сразу наливает КИПЯТОК — чайник… Архив рубрики ~Коротко из Telegram~ 13 августа вышла Gemini 3.7 Flash. Забавно, что с релиза…

Оставить комментарий