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

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

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

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

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

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

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

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

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

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

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

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

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

print(template.render(data=TRANSLATIONS))e75d1209dbd6cc8b537b9a699e7f8317

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

Вы можете хранить шаблоны в отдельных папках или подгружать их из 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))591843cd0fdce088d69853acbdc7e7a4

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)2d68d05167e53f038a39305e3806b94b

То есть 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~ ИИ превращают в дизайнера логотипов — вышел скилл для сборки… Архив рубрики ~Коротко из Telegram~ Я знаю, что ты видишь во сне! ИИ научился понимать,… Архив рубрики ~Коротко из Telegram~ Свой почерк можно превратить в настоящий шрифт — Draw Your… Архив рубрики ~Коротко из Telegram~ ИИ добрался и до ремонта — «ВсеИнструменты.ру» уже использует его,… Архив рубрики ~Коротко из Telegram~ Почти в любом сервисе с персональной лентой рекомендации подбирает цепочка… Архив рубрики ~Коротко из Telegram~ За хостинг VPN на российских серверах будут БАНИТЬ на год… Архив рубрики ~Коротко из Telegram~ 🪟 Исследователи изучили логи эксперимента с моделями OpenAI, которые получили… Архив рубрики ~Коротко из Telegram~ Чем больше котов в стране, тем счастливее люди — учёные… Архив рубрики ~Коротко из Telegram~ Argon выдумывает меньше всех конкурентов. В тесте AA-Omniscience от Artificial… Архив рубрики ~Коротко из Telegram~ Я думал я один это заметил: лимиты Sol-6.1 кажутся бесконечными,… Архив рубрики ~Коротко из Telegram~ GOOOGLEEE!!🌈🌈🌈🌈 https://blog.google/innovation-and-ai/models-and-research/gemini-models/gemini-4-argon/ Google показала Gemini 4 Argon, свою новую флагманскую… Новости робототехники Старых роботов Figure отправили в лаву расплавленную сталь. Компания списывает… Архив рубрики ~Коротко из Telegram~ Anthropic выпустила гайд по Claude Sonnet 5.5 — как выжать… Архив рубрики ~Коротко из Telegram~ Anthropic выпустила Claude Sonnet 5.5 — повседневную модель, которая почти… Архив рубрики ~Коротко из Telegram~ ИИ превращают в дизайнера логотипов — вышел скилл для сборки… Архив рубрики ~Коротко из Telegram~ Я знаю, что ты видишь во сне! ИИ научился понимать,… Архив рубрики ~Коротко из Telegram~ Свой почерк можно превратить в настоящий шрифт — Draw Your… Архив рубрики ~Коротко из Telegram~ ИИ добрался и до ремонта — «ВсеИнструменты.ру» уже использует его,… Архив рубрики ~Коротко из Telegram~ Почти в любом сервисе с персональной лентой рекомендации подбирает цепочка… Архив рубрики ~Коротко из Telegram~ За хостинг VPN на российских серверах будут БАНИТЬ на год… Архив рубрики ~Коротко из Telegram~ 🪟 Исследователи изучили логи эксперимента с моделями OpenAI, которые получили… Архив рубрики ~Коротко из Telegram~ Чем больше котов в стране, тем счастливее люди — учёные… Архив рубрики ~Коротко из Telegram~ Argon выдумывает меньше всех конкурентов. В тесте AA-Omniscience от Artificial… Архив рубрики ~Коротко из Telegram~ Я думал я один это заметил: лимиты Sol-6.1 кажутся бесконечными,… Архив рубрики ~Коротко из Telegram~ GOOOGLEEE!!🌈🌈🌈🌈 https://blog.google/innovation-and-ai/models-and-research/gemini-models/gemini-4-argon/ Google показала Gemini 4 Argon, свою новую флагманскую… Новости робототехники Старых роботов Figure отправили в лаву расплавленную сталь. Компания списывает… Архив рубрики ~Коротко из Telegram~ Anthropic выпустила гайд по Claude Sonnet 5.5 — как выжать… Архив рубрики ~Коротко из Telegram~ Anthropic выпустила Claude Sonnet 5.5 — повседневную модель, которая почти…

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