Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!
В #CloudMTS мы активно используем Go. Например, Go основной язык в балансировщике нагрузки (GSLB), в сервисах создания и управления кластерами PostgreSQL и Redis.
Благодаря производительности, скорости, встроенной поддержке параллелизма, упрощенному синтаксису, Go становится естественным выбором при написании облачных сервисов.
Сегодня поговорим об инструментарии и подходах, которые помогают получить читаемый и поддерживаемый код, а вместо с ним — производительные и надежные сервисы. Backend-разработчик в подразделении DBaaS Герман Лепин (german_lepin) выступил экспертом для нашей статьи.
Писать надежный код
Качество кода зависит не только от знаний программиста, но и методологий со стандартами, применяемыми в той или иной компании. По данным компании Coralogix, разработчики тратят порядка 75% рабочего времени на отладку (1500 часов в год), а стандартизация упрощает эту задачу, помогает сократить число багов.
Если говорить об этом аспекте в контексте языка Golang, то лучшие практики по написанию кода можно найти в рекомендациях Effective Go и CodeReviewComments. Но некоторые компании дополняют их собственными, более строгими, требованиями — так поступили инженеры из Thanos.io, развивающие открытую систему мониторинга на базе Prometheus. В своем репозитории команда описала несколько «нездоровых паттернов», которые часто приводят к появлению багов в коде Golang.
В частности, инженеры не используют panics. Если с этим исключением работают зависимости, то они в обязательном порядке применяют recover (или по возможности обходят эти зависимости стороной). Разработчики также избегают пакеты reflect и unsafe. Они находят применение только в исключительных случаях или тестовых средах.
Список гайдлайнов помогает генерировать читаемый код, снижающий когнитивную нагрузку на специалистов, участвующих в разработке. Программы становится проще тестировать, даже если необходимо внести изменения в продакшн-среде вроде timeNow func() time.Time mock.
Если говорить о том, каких практик стоит избегать, то участники тематического обсуждения на Reddit говорят, лучше обходить стороной библиотеки для проверки утверждений (assertion libraries). В сообществе сложилось мнение, что работа с ними приводит к плохому коду.
Мы в #CloudMTS почти не используем библиотеку assert. При написании тестов вместо a := assert.New(t) можно использовать r := require.New(t). Кроме того, мы создаем внутри команды свои собственные стандарты. Они не связаны именно с Go и созданы независимо от языка.
Стандарты и решения полностью соответствуют ADR (architecture decision record). Каждый новый член команды может ознакомится с ними и понять, как мы работаем. В случае какого-либо спорного решения всегда можно обратится к ADR.
В #CloudMTS мы используем кодогенерацию в Go, что позволяет сэкономить много времени: генерим внутреннюю очередь, https запросы (используем oto), proto файлы, очередь для общения между микросервисами и, конечно же, моки.
Также есть общая структура каждого пакета `service`, каждый сервис содержит в начале интерфейсы, потом саму логику, что вообще делает сервис, далее метод Инициализации (New).
Выглядит это так:
```shell
package aaa_service
import (
...
)
type (
AaaRepository interface {
SetState(...) error
FetchById(..) (*aaaEntity, error)
}
AaaEventProducer interface {
Produce(ctx context.Context, event workqueue.AaaEvent) error
}
...
)
func (s *service) Process(
ctx context.Context,
event workqueue.AaaRequestEvent,
) error {
...
}
var (
errAaaState = errors.New(...")
)
func New(
aaaRepository AaaRepository,
aaaEventProducer AaaEventProducer,
) *service {
return &service{
aaaRepository: aaaRepository,
aaaEventProducer: aaaEventProducer,
}
}
type service struct {
aaaRepository AaaRepository,
aaaEventProducer AaaEventProducer,
}
```
Использовать инструменты
Профессиональный повар способен приготовить вкусный ужин практически в любых условиях. Но весь его потенциал в полной мере раскрывается на оборудованной кухне со свежими продуктами. В программировании похожая история — инструментарий является одним из ключевых ингредиентов успеха.
Так, разработчики предлагают vim в качестве редактора для работы с Go. Да, он не поддерживает Golang по умолчанию, но ситуацию можно исправить с помощью open source библиотеки vim-go. Среда разработки предлагает несколько интересных функций — например, горячая клавиша gd переместит на строку кода с определением переменной или строки, а ctrl + t вернет на исходную позицию.
Повысить удобство работы с кодом и, соответственно, его качество помогут металинтеры. Это — программы, которые позволяют настроить и запустить сразу большое количество линтеров. В сообществе часто рекомендуют обратить внимание на golangci-lint. Он поддерживает десятки линтеров и имеет интеграции с большинством популярных IDE.
Полезные фишки может предложить не только стороннее программное обеспечение или фреймворк, но и классические утилиты Linux. Например, стандартная функция systemd помогает работать с API при разработке облачных приложений на Go. Во время перезагрузки сервера API может быть недоступен. Нужно время, чтобы остановить старый инстанс приложения и запустить новый. Классический подход к решению этой проблемы — внедрение прокси-приложения, которое слушает сеть и транслирует данные основному приложению после запуска. Достаточно передать сокет слушателя в качестве дискриптора файла дочернему процессу и воссоздать сокет на его стороне (с помощью socket activation в systemd). В итоге при перезагрузках данные не теряются, но хранятся в буфере ОС.
Также всегда необходимо писать тесты, которые проверяют новый функционал, и e2e, проверяющие все возможные сценарии работы (в нашем случае это создание, удаление, блокировка, разблокировка и ресайз). В #CloudMTS для e2e тестов мы используем tavern.
Что можно дополнительно изучить
Golang находится на подъёме и входит в топ-10 языков программирования. И как любой другой пользующийся популярностью ЯП, он регулярно обновляется. Получает новый инструментарий, избавляется от неактуального. Изменения часто затрагивают функции, ускоряющие написание кода и повышающие его безопасность. Следить за модификациями можно в официальном блоге на сайте разработчиков — помимо обновлений там можно найти тематические материалы по информационной безопасности, лучших практиках и совместимости.
Новые фреймворки, библиотеки и драйверы также попадают в курируемый лист Awesome Go на GitHub. В нем собраны сотни ресурсов для работы со звуком, аутентификацией, базами данных, изображениями и даже блокчейнами и ботами. Есть API для распознавания речи, разметки текстов и сериализации.