Code Review в Java: что проверять и как давать обратную связь на практике
Code Review (ревью кода) — это систематическая проверка чужого кода с целью выявления ошибок, улучшения качества и обмена знаниями. В Java-разработке это особенно важно из-за строгой типизации, особенностей многопоточности и требований к производительности. Однако многие разработчики сводят ревью к простой проверке стиля или, наоборот, превращают его в токсичную критику. В этой статье мы разберём, что именно нужно проверять в Java-коде и как давать обратную связь, чтобы она приносила пользу, а не боль.
1. Что проверять в Java-коде: чек-лист для ревьювера
Чтобы ревью было эффективным, нужно смотреть не только на синтаксис, но и на архитектуру, безопасность и производительность. Вот основные категории, которые стоит проверять.
1.1 Архитектура и дизайн
- Принципы SOLID: не нарушает ли класс принцип единственной ответственности? Не превращается ли интерфейс в «божественный объект»?
- Связность и связанность: классы должны быть слабо связаны (loose coupling) и иметь высокую внутреннюю связность (high cohesion).
- Использование паттернов: оправдано ли применение сложных паттернов? Иногда простой if-else лучше, чем фабрика с десятком классов.
// Плохо: класс делает всё сразу
public class ReportService {
public void generateReport() { /* генерация */ }
public void sendEmail() { /* отправка */ }
public void saveToDatabase() { /* сохранение */ }
}
// Хорошо: разделение ответственности
public class ReportGenerator { ... }
public class EmailSender { ... }
public class ReportRepository { ... }
1.2 Обработка исключений и ошибок
- Подавление исключений: нельзя писать пустой
catch (Exception e)— это скрывает ошибки. - Специфичность: ловите конкретные исключения, а не
ExceptionилиThrowable. - Логирование: исключения должны логироваться с достаточным контекстом (стек-трейс, входные данные).
// Плохо: проглатывание исключения
try {
processFile(file);
} catch (Exception e) {
// ничего не делаем
}
// Хорошо: логирование и проброс
try {
processFile(file);
} catch (IOException e) {
log.error("Ошибка при обработке файла: {}", file, e);
throw new ProcessingException("Не удалось обработать файл", e);
}
1.3 Производительность и память
- Избыточные операции: создание объектов в циклах, ненужные копии строк через
new String(). - Использование коллекций: правильно ли выбран тип (ArrayList vs LinkedList)? Есть ли лишние синхронизации?
- Stream API: не ухудшает ли стрим читаемость? Иногда обычный цикл понятнее.
// Плохо: создание строки в цикле
String result = "";
for (String s : list) {
result += s; // каждый раз новая строка
}
// Хорошо: StringBuilder
StringBuilder sb = new StringBuilder();
for (String s : list) {
sb.append(s);
}
1.4 Многопоточность и синхронизация
- Правильное использование synchronized: не заблокирован ли слишком большой участок кода?
- Concurrent collections: используете ли
ConcurrentHashMapвместо хэш-таблицы с внешней синхронизацией? - Deadlock-опасность: не блокируются ли ресурсы в разном порядке?
// Риск дедлока
synchronized (lockA) {
synchronized (lockB) { ... }
}
// В другом потоке:
synchronized (lockB) {
synchronized (lockA) { ... }
}
2. Как писать код для удобного ревью
Хороший ревью начинается с хорошего кода. Автор должен облегчить работу ревьюверу.
- Маленькие коммиты: один коммит — одно изменение. Не смешивайте рефакторинг с новой функциональностью.
- Понятные названия: метод
processData()— плохо.validateUserInput()— хорошо. - Комментарии к сложным местам: если код неочевиден, добавьте пояснение (но лучше упростите код).
- Добавьте описание к PR: что делает этот код, какие побочные эффекты, что тестировалось.
// Плохое название метода
public void doStuff(List<String> items) { ... }
// Хорошее название
public List<String> filterActiveUsers(List<String> userIds) { ... }
3. Как давать обратную связь: конструктивная критика
Самая частая ошибка — писать «этот код ужасен» или «всё переделать». Такая критика демотивирует и не даёт полезной информации.
3.1 Правило «Сэндвича»
Начните с позитива, затем укажите на проблемы, закончите поддержкой.
- Хорошо: «Отличная идея вынести логику в отдельный класс! Однако здесь есть потенциальная проблема с потоками. Давай обсудим, как это исправить. В остальном код чистый и понятный.»
- Плохо: «Этот код не работает. Всё плохо.»
3.2 Конкретика и примеры
Вместо «убери дублирование» напишите: «Этот блок повторяется в строках 45 и 78. Предлагаю вынести его в метод validateOrder().»
// Комментарий к ревью:
// ❌ "Плохой код"
// ✅ "Строка 23: использование '==' для сравнения строк может привести к ошибке.
// Замени на equals() или Objects.equals()."
3.3 Вопросы вместо утверждений
Вместо «это неправильно» спросите: «Почему ты выбрал именно этот подход?