Kotlin Best Practices
In this page:
Design for Safety First
Preferring non-null types, val, and sealed classes wherever the domain allows it turns many entire categories of bugs into compile-time errors instead of runtime crashes.
Example: Design for Safety First
sealed class PaymentResult
data class Approved(val transactionId: String) : PaymentResult()
data class Declined(val reason: String) : PaymentResult()
fun describe(result: PaymentResult): String = when (result) {
is Approved -> "Approved: ${result.transactionId}"
is Declined -> "Declined: ${result.reason}"
}
fun main() {
println(describe(Approved("tx_123")))
}
Login to try C/C++/Java/PHP code in the editor
Keep Functions Small and Focused
Breaking logic into small, well-named functions (including local and extension functions) makes each piece easy to understand, test, and reuse on its own.
Example: Keep Functions Small and Focused
fun Int.isPrime(): Boolean {
if (this < 2) return false
for (i in 2 until this) {
if (this % i == 0) return false
}
return true
}
fun main() {
val primes = (2..20).filter { it.isPrime() }
println(primes)
}
Login to try C/C++/Java/PHP code in the editor
Don't Ignore Compiler Warnings
Warnings about unreachable code, unnecessary safe calls, or unchecked casts often point directly at a real bug or a design that can be made safer -- treating them seriously pays off.
Example: Don't Ignore Compiler Warnings
fun describeNumber(n: Int): String {
return if (n % 2 == 0) "even" else "odd"
// Any code placed here would be unreachable, and the compiler would warn about it
}
fun main() {
println(describeNumber(7))
}
Login to try C/C++/Java/PHP code in the editor
Write Code for the Next Reader
Choosing clear names, favoring well-known idioms over clever tricks, and keeping functions short all serve the same goal: making the code easy for someone else (or future you) to safely understand and change.
Example: Write Code for the Next Reader
fun calculateShippingCost(weightKg: Double, isExpress: Boolean): Double {
val baseCost = weightKg * 2.0
return if (isExpress) baseCost * 1.5 else baseCost
}
fun main() {
println("Shipping cost: ${calculateShippingCost(5.0, true)}")
}
Login to try C/C++/Java/PHP code in the editor
- Reaching for
!!or unsafe casts as a quick fix instead of addressing the underlying design that made a value's type or nullability uncertain. - Writing large, do-everything classes and functions instead of composing small, well-named, single-purpose pieces.
- Ignoring compiler warnings, which often point to genuine risks like unreachable code, unused variables, or unsafe casts.
- Prefer immutability (
val, read-only collections) and null safety operators over defensive, manual workarounds. - Keep functions small and focused, with descriptive names that make comments about *what* the code does mostly unnecessary.
- Use sealed classes and exhaustive
whenexpressions to make invalid states unrepresentable wherever practical. - Pay attention to compiler warnings -- they frequently highlight real, fixable risks in the code.
Chapter Quiz — Complete all 7 topics to unlock
0/7 topics done
Complete these topics first: