Code review in Kotlin: what to check and how to give feedback
\n\nCode review is not just a formality, but a powerful tool for improving project quality and team growth. For beginner Kotlin developers, the review process often causes fear: "What if I miss a bug?", "How do I tell a colleague their code is bad?". In this article, we'll break down what to look for when reviewing Kotlin code and how to phrase comments so they are helpful, not hurtful.
\n\nWe won't be teaching you basic syntax — it's assumed you already write in Kotlin. Instead, we'll focus on typical problems found in beginners' code and how to give feedback without breaking the karma.
\n\n1. Null safety and working with nullable types
\n\nKotlin prides itself on its type system, which eliminates most NullPointerExceptions at compile time. However, beginners often overuse the !! (not-null assertion) operator or handle nullable values incorrectly.
What to check:
\n- \n
- Is
!!used without a good reason? If you seesomething!!, ask the author: "Why are you sure there won't be null here? Maybe it's better to use?.letor?:?". \n - Are chains of calls via
?.handled correctly? For example,user?.address?.cityis safe, but if city is needed, it's better to use?:for a default value. \n - Is
lateinit varinitialized before use? Check that all lateinit fields will definitely be initialized before the first read. \n
// Bad\nfun getUserCity(user: User?): String {\n return user!!.address!!.city // Risk of NPE\n}\n\n// Good\nfun getUserCitySafe(user: User?): String {\n return user?.address?.city ?: "Unknown"\n}\n\n\nHow to give feedback: Instead of "You wrote bad code", say: "This could be null, let's replace !! with a safe call to avoid a runtime crash." Suggest an alternative — this teaches rather than criticizes.
\n\n2. Kotlin idiomaticity: collections, scope functions, and sealed classes
\n\nKotlin is not just "Java with different syntax". Many beginners write Kotlin as if they're still working in Java: they use for loops instead of collection functions, forget about apply, let, run, and don't use sealed class to represent states.
What to check:
\n- \n
- Are collection functions (
map,filter,firstOrNull) used instead of manual loops? This makes code more concise and readable. \n - Are there redundant temporary variables? For example,
val result = list.filter { ... }.map { ... }is better than breaking it into three steps with mutable lists. \n - Are
sealed classused for hierarchies where all variants need to be handled (e.g., Result, UiState)? This is a mandatory requirement in modern Kotlin projects. \n
// Bad (Java-style)\nfun getEvenSquares(list: List<Int>): List<Int> {\n val result = mutableListOf<Int>()\n for (i in list.indices) {\n if (list[i] % 2 == 0) {\n result.add(list[i] * list[i])\n }\n }\n return result\n}\n\n// Good (Kotlin-idiomatic)\nfun getEvenSquaresIdiomatic(list: List<Int>): List<Int> {\n return list.filter { it % 2 == 0 }.map { it * it }\n}\n\n\nHow to give feedback: Point to a specific idiom: "Instead of a for loop, you can use filter + map, it's shorter and clearer. Want me to show you an example?" Don't impose — suggest a discussion.
\n\n3. Architecture and testability
\n\nEven if the project is small, code review is a great time to check