Code review в Go: что проверять и как давать обратную связь
Code review (ревью кода) — это не просто формальность, а один из самых эффективных инструментов для повышения качества кода, обмена знаниями в команде и предотвращения багов. В сообществе Go (Golang) code review имеет особое значение, так как язык поощряет простоту, читаемость и идиоматичность. В этой статье мы разберем, на что обращать внимание при ревью Go-кода и как давать обратную связь, чтобы она была полезной, а не обидной.
1. Общие принципы code review в Go
Прежде чем переходить к техническим деталям, важно помнить о культуре ревью. Ваша цель — улучшить код и помочь коллеге, а не доказать свою правоту. Вот несколько золотых правил:
- Будьте конструктивны. Вместо «это плохо» напишите «здесь может быть утечка горутины, давай добавим контекст».
- Спрашивайте, а не утверждайте. «Почему ты выбрал
sync.Mutex, а не канал?» — хороший вопрос. «Ты дурак, надо было канал» — плохой. - Не задерживайте ревью. Стремитесь дать ответ в течение 24 часов (или по договоренности в команде).
- Фокусируйтесь на логике и архитектуре. Стилистические правки (пробелы, отступы) лучше доверить
gofmt.
2. Что проверять в первую очередь: чек-лист для Go
Вот структурированный список того, на что стоит обращать внимание при ревью Go-кода. Разделим его на логические блоки.
2.1. Обработка ошибок
В Go нет исключений, ошибки — это значения. Это одна из ключевых идиом языка.
- Проверяйте все возвращаемые ошибки. Игнорирование ошибки с помощью
_допустимо только в очень редких случаях (например, при записи вio.Discard). - Не используйте
panicдля обычных ошибок.panic— это для невосстановимых состояний (например, ошибка инициализации сервера). - Оборачивайте ошибки. Используйте
fmt.Errorf("что-то пошло не так: %w", err)для добавления контекста. Это позволяет использоватьerrors.Is()иerrors.As().
// Плохо: потеря контекста
if err != nil {
return err
}
// Хорошо: оборачиваем ошибку
if err != nil {
return fmt.Errorf("не удалось открыть файл %s: %w", filename, err)
}
2.2. Горутины и конкурентность
Go славится своей легковесной конкурентностью, но она же является источником многих багов.
- Утечки горутин. Убедитесь, что каждая запущенная горутина когда-нибудь завершится. Используйте контекст (
context.Context) для отмены. - Правильное использование каналов. Кто создает канал, тот и закрывает его. Закрытие канала — это ответственность отправителя.
- Гонка данных (data race). Избегайте одновременной записи в одну переменную без синхронизации. Используйте мьютексы (
sync.Mutex) или атомики (sync/atomic).
// Пример с контекстом для отмены горутины
func process(ctx context.Context, dataCh chan int) {
for {
select {
case <-ctx.Done():
log.Println("Завершаем работу")
return
case val, ok := <-dataCh:
if !ok {
return // канал закрыт
}
fmt.Println(val)
}
}
}
2.3. Идиомы и стиль Go
Go — это язык, где читаемость кода ценится превыше всего.
- Имена переменных. Короткие имена для коротких областей видимости.
iдля цикла,rдля reader. Для глобальных переменных — более длинные имена. - Избегайте «магических чисел». Используйте константы.
- Zero value. Используйте нулевое значение структуры (
var s MyStruct) вместо явной инициализации пустыми полями, если это логично. - Методы и функции. Если функция возвращает булево значение, называйте её
IsValid(),HasAccess().
2.4. Производительность и память
На ревью не обязательно гнаться за каждой наносекундой, но явные "красные флаги" стоит подсветить.
- Избегайте лишних аллокаций. Например, при конкатенации строк в цикле используйте
strings.Builder. - Утечки памяти. Например, если вы храните срез в глобальной переменной, а потом добавляете в него элементы, старый массив не будет собран сборщиком мусора.
- Правильный размер буфера. При чтении из
io.Readerиспользуйте буфер разумного размера (например, 32KB).
3. Как давать обратную связь: от мягкой до критической
Не все комментарии одинаково важны. Чтобы не перегружать автора, используйте градацию важности.
- Must fix (блокирующие). Ошибки, которые приведут к падению прода или некорректной работе. Например: гонка данных, игнорирование ошибки, утечка горутины.
- Should fix (важные). Нарушение идиом Go, плохая читаемость, потенциальные проблемы с производительностью. Например: неиспользование
context.Contextтам, где он нужен. - Nice to have (предложения). Улучшения стиля, альтернативные подходы. Например: «А что если вынести эту логику в отдельную функцию?».
Пример хорошего комментария: «Здесь стоит добавить defer resp.Body.Close(), иначе произойдет уте