Code Review: эффективная практика для улучшения качества кода и командной работы
Код ревью можно воспринимать по-разному, но если относиться к нему неправильно, то оно может стать тратой времени и причиной обид и недопониманий. А если корректно — то путем для обмена опытом и повышения надежности кодовой базы и продукта в целом.
В рамках этой статьи я буду называть запросы на слияния как MR (merge request), в GitHub они называются PR (pull request).
Зачем нужен Code Review
Начнем с того, что код ревью может дать вашей команде.
Улучшение качества кода
Code Review — это последняя линия обороны перед тем, как код попадет в продакшен или как минимум в дев ветку. Ведь никто не застрахован от ошибок или ошибок невнимательности.
Опытный ревьюер может заметить:
- Потенциальные баги и кейсы, которые автор мог пропустить
- Проблемы производительности, например, неоптимальные запросы к базе данных или избыточные вычисления
- Проблемы безопасности, такие как незащищенные эндпоинты или некорректные права доступа
- Нарушения архитектурных подходов проекта
- Неправильно реализованную задачу
Примеров из практики может быть просто бесконечно много — забытые тесты, написание бизнес-логики на уровне представления (View), ошибка в логике, упущенные требования из задачи.
Распространение знаний в команде
Code Review — это не просто проверка кода, но это еще и процесс обмена знаниями:
- Новые члены команды учатся лучшим практикам и подходам конкретного проекта
- Знания о различных частях системы распространяются между разработчиками
- Повышение вовлеченности в задачи других людей и понимания проекта
Улучшение документации и тестирования
Процесс ревью естественным образом подталкивает к:
- Написанию более понятных комментариев и документации
- Улучшению покрытия тестами
- Созданию более говорящих названий переменных и функций
- Добавлению примеров использования кода
Когда ты понимаешь, что на твой код будет кто-то смотреть, то невольно начинаешь писать его более понятным, красивым и поддерживаемым.
Польза для "бизнеса"
Хотя Code Review требует времени, его преимущества перевешивают затраты:
- Уменьшение количества багов в продакшене (по статистике Google, правильно организованный процесс ревью уменьшает количество багов на 60-90%)
- Ускорение онбординга новых разработчиков
- Повышение качества и поддерживаемости кода
- Уменьшение затрат на исправление ошибок в долгосрочной перспективе
Важно понимать, что Code Review — это не инструмент контроля или критики, а способ сделать код и команду лучше. При правильной организации процесса разработчики начинают воспринимать ревью как возможность учиться и делиться знаниями, а не как формальную процедуру или критику их работы.
Подготовка MR к ревью
Эффективный Code Review начинается задолго до того, как код попадает на проверку. Правильная подготовка MR экономит время как автора, так и ревьюера.
Что должно быть готово перед отправкой на ревью
1. Описание изменений
- Четкая формулировка, что именно было изменено и зачем
- Ссылка на задачу в жире (может быть в названии МР-а, в GitLab есть настройка, что иначе не создать МР без задачи в названии)
- Возможное влияние на существующий код
Добавлен кэш для API запросов к внешнему сервису платежей - Реализовано кэширование успешных запросов на 15 минут - Добавлены метрики для отслеживания hit/miss ratio - Добавлены тесты для проверки работы кэша - Настроен fallback на случай проблем с Redis
2. Декомпозиция изменений
- МР должен решать одну конкретную задачу
- Изменения должны быть логически сгруппированы по коммитам (это позволяет просматривать изменения по коммитам, подробнее в моем видео)
- Рефакторинг лучше выделять в отдельный PR
commit: "Большой рефакторинг, новая фича и фиксы" - Изменена структура БД - Добавлен новый API эндпоинт - Исправлены баги в старом коде - Обновлены зависимости
commit 1: "Обновление схемы БД для поддержки новых полей" commit 2: "Добавлен эндпоинт /api/v1/payments/status" commit 3: "Добавлены тесты для нового эндпоинта"
Оптимальный размер PR
Исследования показывают, что эффективность ревью резко падает при увеличении размера PR:
- До 200 строк: ревьюеры находят до 70-90% проблем
- 200-400 строк: эффективность падает до 50-70%
- Более 400 строк: находится менее 50% проблем
Поэтому важно стараться разбивать большие задачи на подзадачи на уровне планирования.
Самопроверка
Перед отправкой кода на ревью крайне важно провести самопроверку вашего MR. Часто после небольшого перерыва, когда вы возвращаетесь к коду со "свежим взглядом", можно заметить очевидные проблемы, которые были упущены в процессе разработки.
- В процессе написания кода мы находимся в состоянии глубокого погружения и можем не замечать очевидных ошибок
- После выполнения остальных частей ритуала (создание МР, его описание) мозг переключается и может посмотреть на код более объективно
- Просмотр диффа в интерфейсе Git позволяет увидеть код так, как его будет видеть ревьюер
А на что обращать внимание при самопроверке вы всегда найдете в моей книге "От кода до прода".
Процесс ревью
В этом разделе разберем, как сделать процесс ревью максимально эффективным. Многие разработчики тратят слишком много времени на проверку кода из-за неправильно выстроенного процесса.
Порядок проверки кода
Первичный обзор (5-10 минут)
- Прочитать описание МР и связанную задачу
- Просмотреть общую структуру изменений
- Оценить размер и сложность МР
- Определить, достаточно ли у вас контекста
Высокоуровневый анализ (10-15 минут)
- Соответствует ли решение требованиям задачи
- Правильно ли выбрана архитектура
- Нет ли более простых решений
- Влияние на существующую архитектуру
Детальный анализ (основное время)
Приоритизация замечаний
Интересную систему маркировки комментариев я подглядел у коллег из МТС, когда мы работали в смешанной команде. Они использовали "светофор" для обозначения важности замечаний:
🔴 Красные (обязательны к исправлению)
- Серьезные баги или проблемы безопасности
- Критические проблемы производительности
- Нарушения архитектуры
# 🔴 Возможна race condition при параллельных запросах @app.route('/api/order/process') async def process_order(order_id: int): order = await Order.get(id=order_id) order.status = 'processing' await order.save()
🟡 Желтые (желательно исправить)
# 🟡 Нет обработки случая недоступности API def get_user_data(user_id): response = requests.get(f'/api/users/{user_id}') return response.json()
🟢 Зеленые (на усмотрение автора)
После того, как вы оставили комментарии не будет лишним уведомить автора MR-a о том, что были оставлены комментарии. Это явно ускорит реакцию и команда станет на шаг ближе к готовому функционалу. На уведомления в почте/телеграмме лучше не рассчитывать.
Завершение ревью
- Исправление блокирующих замечаний
- Ответы на все комментарии
- Прохождение тестов и CI/CD
- Обновление документации
Не забудьте отметить удачные решения и поблагодарить за качественные исправления, похвала приятна всем!
Коммуникация в ревью
Важная часть код ревью — это общение и умение адекватно реагировать на критику (и критиковать так, чтобы никто не обижался). Можно быть отличным разработчиком, но без навыков общения ревью будет приносить больше проблем, чем пользы.
Как формулировать замечания
Основное правило — всегда фокусируемся на коде, а не на авторе. Сравните два подхода:
- ❌ "Ты опять забыл про обработку ошибок"
- ✅ "В этом view не хватает обработки случая, когда сервис платежей недоступен"
Просто изменив формулировку, мы превращаем потенциально конфликтную ситуацию в конструктивное обсуждение.
Второй важный момент — всегда объясняйте причину замечания:
# ❌ "Надо использовать enum вместо строк" # ✅ "Предлагаю перейти на enum для статусов заказа: from django.db import models class Order(models.Model): class Status(models.TextChoices): NEW = 'NEW', 'Новый' PROCESSING = 'PROCESSING', 'В обработке' COMPLETED = 'COMPLETED', 'Завершен' status = models.CharField( max_length=20, choices=Status.choices, default=Status.NEW ) # Это даст нам: # - Защиту от опечаток # - Автодополнение в IDE # - Более удобный рефакторинг"
Когда видите проблемы с производительностью, всегда предлагайте конкретное решение:
# ❌ "Тут будет N+1 проблема" # ✅ "Сейчас для каждого заказа делается отдельный запрос. # Можно оптимизировать через select_related: orders = Order.objects.select_related('user', 'payment').filter( status=Order.Status.NEW ) # Это уменьшит количество запросов с N+1 до 1"
Как отвечать на замечания
Если вы не согласны, объясните свою логику:
💬 "Я специально не использовал select_related потому что: - В 90% случаев нам не нужны данные пользователя - Текущий запрос уже закэширован - Профилирование показало прирост всего в 50мс Что думаете?"
Решение конфликтов
Системно избежать холиваров на спорные темы, если авторитарного мнения не хватает, проще всего решить автоматизацией. Злиться на скрипты гораздо сложнее, например можно:
Если конфликт все-таки возник, переводим обсуждение в звонок. Личное общение творит чудеса — часто оказывается, что мы просто по-разному поняли задачу.
Заключение
Code Review — это мощный инструмент для повышения качества кода и обмена знаниями в команде. Правильно организованный процесс ревью позволяет находить и исправлять ошибки до того, как они попадут в продакшен, ускоряет онбординг новых разработчиков и способствует созданию более поддерживаемого кода.
Помните, что ключевыми элементами успешного ревью являются:
- Тщательная подготовка MR
- Структурированный процесс проверки
- Грамотная приоритизация замечаний
- Правильная коммуникация
А подробнее про все аспекты разработки вы всегда найдете в моей книге "От кода до прода".