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. Для глобальных переменных — более длинные имена. - Избегайте «магических чисел». Используйте константы.