Code review в Kotlin: что проверять и как давать обратную связь новичкам

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Code review в Kotlin: что проверять и как давать обратную связь для начинающих

Code review (ревью кода) — это один из ключевых процессов в современной разработке. Для новичков на Kotlin он часто кажется пугающим: как найти ошибки? Что именно смотреть? Как не обидеть автора кода? В этой статье мы разберём, на что обращать внимание при code review проектов на Kotlin, и как давать обратную связь, чтобы она была полезной, а не обидной. Материал подойдёт как тем, кто только учится ревьюить, так и тем, кто хочет улучшить свои навыки.

Зачем нужен code review в Kotlin?

Kotlin — современный, лаконичный и безопасный язык, но он даёт разработчику много свободы. Без code review легко допустить ошибки, связанные с null-безопасностью, неправильным использованием корутин или излишней сложностью. Ревью помогает:

  • Найти баги на ранних этапах.
  • Улучшить читаемость и поддерживаемость кода.
  • Распространить знания внутри команды.
  • Соблюсти единый стиль кода.

Для начинающих это ещё и отличный способ учиться на чужих примерах. Давайте перейдём к конкретике.

Что проверять при code review кода на Kotlin

Вот чек-лист из ключевых пунктов, которые стоит проверять в каждом pull request. Разделим их на логические блоки.

1. Null-безопасность и типы

Kotlin гордится своей null-безопасностью, но её можно нарушить. Проверяйте:

  • Используются ли nullable типы (например, String?) только там, где это действительно нужно?
  • Нет ли ненужных !! (non-null assertion)? В идеале их вообще не должно быть в production-коде.
  • Используются ли безопасные вызовы (?.let { ... }) и элвис-оператор (?:) вместо if (x != null)?

Плохой пример:

val name: String? = getName()
val length = name!!.length // Опасно: вызовет NPE, если name == null

Хороший пример:

val name: String? = getName()
val length = name?.length ?: 0 // Безопасно: если null, то 0

2. Функции и их сигнатуры

Kotlin поддерживает именованные аргументы и значения по умолчанию. Проверьте:

  • Является ли функция слишком длинной (больше 20–30 строк)? Возможно, её стоит разбить.
  • Используются ли параметры по умолчанию для упрощения вызова?
  • Нет ли функций с более чем 3–4 параметрами? Это усложняет чтение.
  • Уместно ли использование extension-функций? Они не должны менять состояние объекта.

Пример:

// Вместо этого:
fun processUserData(name: String, age: Int, email: String, city: String, phone: String) { ... }

// Лучше так:
data class UserData(val name: String, val age: Int, val email: String, val city: String, val phone: String)
fun processUserData(user: UserData) { ... }

3. Работа с корутинами (Coroutines)

Корутины — мощный инструмент Kotlin, но их легко использовать неправильно. Обратите внимание:

  • Не заблокирован ли поток внутри корутины (вызов Thread.sleep() или блокирующий ввод-вывод)?
  • Используется ли правильный диспетчер (Dispatchers.IO для сетевых запросов, Dispatchers.Main для UI)?
  • Нет ли утечек корутин (например, запущенных в Activity без отмены)?
  • Используется ли withContext для смены диспетчера, а не launch внутри launch?

Плохой пример:

fun fetchData() {
    GlobalScope.launch { // Утечка: не отменяется при уничтожении компонента
        Thread.sleep(1000) // Блокирует поток!
    }
}

Хороший пример:

fun fetchData(scope: CoroutineScope) {
    scope.launch {
        withContext(Dispatchers.IO) {
            // Сетевой запрос
        }
    }
}

4. Использование коллекций и функционального стиля

Kotlin поощряет функциональный подход с map, filter, fold и т.д. Проверьте:

  • Не заменён ли простой цикл сложной цепочкой вызовов? Иногда for читается лучше.
  • Нет ли ненужных промежуточных коллекций (например, .toList().filter { ... }.toList())?
  • Используются ли sequence для ленивых вычислений, если коллекция большая?

Пример:

// Плохо: две промежуточные коллекции
val result = list.filter { it > 5 }.map { it * 2 }

// Хорошо: одна цепочка с sequence для больших списков
val result = list.asSequence().filter { it > 5 }.map { it * 2 }.toList()

Как давать обратную связь: советы для начинающих

Теперь, когда вы знаете, что проверять, важно правильно донести свои замечания. Вот несколько принципов.

1. Будьте конкретны и объясняйте "почему"

Вместо "это плохо" напишите "это может вызвать NullPointerException, потому что...". Приводите примеры кода. Например:

Плохой комментарий: "Тут всё неправильно."

Хороший комментарий: "Здесь используется !!, что опасно. Если user будет null, приложение упадёт. Предлагаю заменить на user?.let { ... } или ?:."

2. Начинайте с позитива

Найдите что-то хорошее в коде: "Отлично, что

Блоги

Рекомендаций по книгам