Как Go-разработчику сэкономить несколько недель жизни

от автора

Привет! Меня зовут Александр Сусиков, я тимлид команды, которая занимается платформой PaaS для СберМаркета. В этой статье я расскажу, как повысить скорость разработки с помощью кодогенерации.

Зачем нужна кодогенерация

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

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

Вот основные преимущества кодогенерации:

  • уменьшает ручной труд при разработке. Код пишется быстрее, а ошибок становится меньше;
  • стандартизирует код. Одну и ту же задачу можно решить разными способами, а кодогенерация предлагает конкретный вариант и задаёт таким образом стандарт;
  • улучшает производительность. Например, скорость работы приложения можно повысить, если заменить рефлексию в Go на кодогенерацию;
  • позволяет обходить ограничения языка. Например, до версии 1.18 в Golang отсутствовали дженерики — их компенсировали кодогенерацией.

Какие инструменты кодогенерации подойдут для каждого этапа разработки

Представьте, что вам поручили разработать простой сервис — небольшой прокси, который общается с внешним Rest API. Ответы API при этом просят кэшировать, чтобы повысить стабильность и производительность работы.

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

Создание проекта — генерация директорий и основных файлов. В этом помогут консольные утилиты:

Ещё вариант — создать свои шаблоны или генераторы кода. Это удобно, если в компании микросервисная архитектура — тогда сервисы будут похожи по структуре и используемым инструментам.

Создание веб-сервера и клиента по спецификации. Наш сервис из себя будет представлять веб-сервер, который будет ходить в кэш и если там не будет данных, то обращаться к внешнему API — для общения с ним понадобится клиент. В СберМаркете пропагандируют подход Contract-first: когда спецификация пишется до кода. С готовой спецификацией можно сразу сгенерировать и сервер, и клиент для описанного API — так удобнее.

Сгенерировать код по спецификации помогут:

Генерация метрик. Работу прокси из нашего примера можно оценивать по таким метрикам: сколько было попыток и сколько ответов нашлось в кэше.

С генерацией метрик поможет

Он использует паттерн-декоратор — создает враппер, который будет отправлять метрики в зависимости от наличия ошибки.

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

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

Моки сгенерируют:

Инициализация графа зависимостей. При инициализации приложений в конструкторы нужно передавать конкретную реализацию, а не интерфейсы. Тем самым мы получаем граф зависимостей. С его построением поможет

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

На любом этапе удобно использовать генераторы в связке со встроенной в Go командой go generate — она позволяет запускать все генераторы одной строкой. Команда включает поиск специального комментария, начинающегося с go:generate. Затем происходит выполнение инструкций, которые написаны после этого текста.

//go:generate mockery --name Cache type Cache interface {     Get(key string) string }

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

Подробнее о go generate можно почитать в официальном блоге Go. Перевод на русский — в статье на Хабре.

Как платформа СберМаркета использует кодогенерацию для работы с инфраструктурой

Платформа СберМаркета PaaS помогает разработчикам решать вопросы, связанные с инфраструктурой, это ускоряет доставку фич на прод. Вот как мы используем для этого кодогенерацию.

Алерты

Для добавления алертов разработчики СберМаркета создают yaml-файл с несколькими полями, где прописывают выражения для алерта, его имя, runbook и другие параметры. На основе этого файла генерируются Prometheus Alerting Rules, которые попадают в Alert Manager.

import-alerts-worker-not-run: &import-alerts-worker-not-run     name: Import alerts workers have not run     expr: sum(increase(workers_job_executes{queue="ImportAlerts", DEFAULT_LABELS}[5m])) == 0     for: lm     description: "Import workers have not run during 5 minutes"     runbook: ""     dashboard: https://grafana.sbmt.io/d/ueja7ew/odin      labels:         app: "paas-odin" 

Инфраструктурные зависимости и зависимости от сервисов

При локальной разработке возникает проблема инфраструктурных зависимостей и зависимостей от других сервисов. Эту задачу отлично решает Docker, но для него нужно подготавливать docker-compose-файлы и описывать, какие контейнеры необходимы для работы.

У сервисов платформы СберМаркета есть манифест, в котором разработчики указывают зависимости сервиса. Эту информацию мы используем для генерации docker-compose-файла. В итоге локально запустить сервис можно всего в одну строчку.

sbm-cli service up

Все инструменты одним списком

  • Для создания проекта: buffalo, beego.
  • Для создания веб-сервера и клиента по спецификации: swag, go-swagger, oapi-codegen, openapi-generator.
  • Для генерации метрик: gowrap.
  • Для создания моков: mockery, gomock.
  • Для инициализации графа зависимостей: wire.
  • Для запуска генераторов одной строкой: go generate.


Мы завели соцсети с новостями и анонсами Tech-команды. Если хотите узнать, что под капотом высоконагруженного e-commerce, следите за нами там, где вам удобнее всего: Telegram, VK.


ссылка на оригинал статьи https://habr.com/ru/company/sbermarket/blog/676486/