Code Review в Go: что проверять и как давать обратную связь
Code review — это не просто формальность, а важнейший этап разработки. Особенно в Go, где простота и читаемость кода заложены в философию языка. Для начинающих разработчиков это может казаться пугающим: как критиковать чужой код, если сам ещё не уверен? На самом деле, code review — это лучший способ учиться. В этой статье мы разберём, на что обращать внимание при ревью Go-кода и как давать обратную связь, чтобы она была полезной, а не обидной.
1. Основные принципы: что искать в первую очередь
Перед тем как углубляться в детали, запомните главное правило: ревью — это про код, а не про человека. Ваша цель — найти потенциальные проблемы и улучшить качество продукта, а не доказать, что вы умнее. Начните с простых вещей:
- Логические ошибки: корректно ли обрабатываются граничные случаи? Например, что будет, если слайс пуст?
- Потенциальные паники: не забыли ли вы про
nil? Проверьте, что не вызываете методы на нулевом указателе. - Неиспользуемый код: в Go это приводит к ошибке компиляции, но иногда остаются мёртвые переменные или импорты.
Пример типичной ошибки новичка:
func getFirstElement(s []int) int {
return s[0] // Паника, если слайс пуст!
}
Что нужно предложить в ревью: добавить проверку длины слайса и вернуть ошибку.
func getFirstElement(s []int) (int, error) {
if len(s) == 0 {
return 0, fmt.Errorf("slice is empty")
}
return s[0], nil
}
2. Идиомы Go: как писать «по-гошному»
Go — не Java и не Python. У него свой стиль, который нужно уважать. На ревью обращайте внимание на следующие моменты:
- Именование: в Go приняты короткие имена (например,
rдля reader,wдля writer). Не нужно называть переменнуюmyReader— простоr. - Обработка ошибок: не игнорируйте ошибки! Если функция возвращает
error, её нужно проверить. Исключение —fmt.Printlnи подобные, но и их лучше логировать. - Интерфейсы: они должны быть маленькими. Один метод — хорошо, два — уже много. Не создавайте интерфейсы «на вырост».
Пример «не-гошного» кода:
func ProcessData(data []string) (bool, error) {
var result bool
for _, item := range data {
if item == "error" {
result = false
return result, errors.New("found error")
}
}
result = true
return result, nil
}
Здесь result не нужен — можно сразу возвращать true или false. Также стоит использовать fmt.Errorf для форматирования.
func ProcessData(data []string) (bool, error) {
for _, item := range data {
if item == "error" {
return false, fmt.Errorf("found error in item: %s", item)
}
}
return true, nil
}
3. Производительность и память: на что обратить внимание
Хотя Go достаточно быстр, плохой код может всё испортить. На ревью проверяйте:
- Избегайте лишних аллокаций: если вы знаете размер слайса, используйте
makeс указанием capacity. - Копирование структур: большие структуры лучше передавать по указателю, чтобы не копировать их каждый раз.
- Горутины: проверьте, не забыли ли вы закрыть канал или дождаться завершения горутины (используйте
sync.WaitGroup).
Пример плохой работы со слайсом:
func appendItems(items []int) []int {
var result []int
for _, v := range items {
result = append(result, v*2)
}
return result
}
Лучше так:
func appendItems(items []int) []int {
result := make([]int, 0, len(items))
for _, v := range items {
result = append(result, v*2)
}
return result
}
Это снижает количество переаллокаций памяти.
4. Как давать обратную связь: мягко и конструктивно
Даже если вы нашли 100 ошибок, не вываливайте их все сразу. Используйте правило «сэндвича»: начните с позитива, затем укажите на проблемы, закончите поддержкой. Вот несколько конкретных советов:
- Используйте вопросительную форму: вместо «Ты написал неправильно» скажите «А что, если здесь передать nil? Нужна ли проверка?»
- Предлагайте альтернативы: не просто указывайте на ошибку, а покажите, как её исправить. Пример: «Вместо цикла можно использовать
strings.Join, это упростит код». - Не спорьте о вкусовщине: если код рабочий и читаемый, не настаивайте на переименовании переменной с
iнаindex. Это не важно.
Пример хорошего комментария:
«Отличная реализация! Я заметил, что здесь может быть паника, если map не инициализирован. Предлагаю добавить проверку if m == nil в начале функции. Что думаешь?»
5. Чек-лист для начинающего ревьюера
Чтобы не забыть важное, держите под рукой этот список:
- Код компилируется? (
go build) - Проходят ли тесты? (
go test ./...) - Нет ли неиспользуемых переменных или импортов?
- Обрабатываются ли ошибки?
- Нет ли паник из-за
nil? - Соблюдены ли идиомы Go (именование, интерфейсы)?
- Нет ли утечки горутин? <