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

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

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

Привет, Хабр! Меня зовут Иван, я 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

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

Поделиться
Понравилась статья? Расскажите другим
ВКонтакте
Читайте также
Архив рубрики ~Коротко из Telegram~ Quantinuum показала, куда пойдут деньги от IPO Компания Quantinuum выпустила на… Архив рубрики ~Обо всем~ Самая мучительная смерть ради спаривания Архив рубрики ~Полезное~ Становимся гуру Claude Code за неделю — Anthropic обновили свой… Архив рубрики ~Коротко из Telegram~ NVIDIA выпустила ИИ для поиска дипфейков Компания представила Synthetic Video… Архив рубрики ~Коротко из Telegram~ Suno выпустила Studio 2 В Studio 2.0 появился MIDI. Можно… Архив рубрики ~Полезное~ Удаляем все майнеры, вредоносы и прочий мусор со своего компа… Архив рубрики ~Коротко из Telegram~ Проектируем дом бесплатно прямо в браузере Вышел опенсорсный Pascal Editor,… Архив рубрики ~Полезное~ Нашли библиотеку с 1000+ бесплатными аналогами популярных программ Автор собрал… Архив рубрики ~Коротко из Telegram~ Бесплатно превращаем аудио и видео в текст Нашли приложение Vibe,… Архив рубрики ~Коротко из Telegram~ ИИ всё сильнее меняет геймдев Claude Opus 5 уже способен… Архив рубрики ~Коротко из Telegram~ НСПК предупредила о сбоях при оплате картами Visa и Mastercard… Архив рубрики ~Коротко из Telegram~ Российский банк выложил в открытый доступ один из крупнейших в… Архив рубрики ~Коротко из Telegram~ NVIDIA выпустила инструмент, который за миллисекунды отличает настоящее видео от… Новости робототехники Гуманоид дороже 200 годовых прибылей: китайская Unitree вышла на биржу… Архив рубрики ~Коротко из Telegram~ Quantinuum показала, куда пойдут деньги от IPO Компания Quantinuum выпустила на… Архив рубрики ~Обо всем~ Самая мучительная смерть ради спаривания Архив рубрики ~Полезное~ Становимся гуру Claude Code за неделю — Anthropic обновили свой… Архив рубрики ~Коротко из Telegram~ NVIDIA выпустила ИИ для поиска дипфейков Компания представила Synthetic Video… Архив рубрики ~Коротко из Telegram~ Suno выпустила Studio 2 В Studio 2.0 появился MIDI. Можно… Архив рубрики ~Полезное~ Удаляем все майнеры, вредоносы и прочий мусор со своего компа… Архив рубрики ~Коротко из Telegram~ Проектируем дом бесплатно прямо в браузере Вышел опенсорсный Pascal Editor,… Архив рубрики ~Полезное~ Нашли библиотеку с 1000+ бесплатными аналогами популярных программ Автор собрал… Архив рубрики ~Коротко из Telegram~ Бесплатно превращаем аудио и видео в текст Нашли приложение Vibe,… Архив рубрики ~Коротко из Telegram~ ИИ всё сильнее меняет геймдев Claude Opus 5 уже способен… Архив рубрики ~Коротко из Telegram~ НСПК предупредила о сбоях при оплате картами Visa и Mastercard… Архив рубрики ~Коротко из Telegram~ Российский банк выложил в открытый доступ один из крупнейших в… Архив рубрики ~Коротко из Telegram~ NVIDIA выпустила инструмент, который за миллисекунды отличает настоящее видео от… Новости робототехники Гуманоид дороже 200 годовых прибылей: китайская Unitree вышла на биржу…

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