Kotlin Production Best Practices
Kotlin's features eliminate entire categories of bugs when used correctly. Here are the practices that matter for production code.
Leverage Null Safety
// Don't fight the type system
fun processUser(user: User?): Result {
val name = user?.name ?: return Result.Error("User required")
val email = user.email ?: return Result.Error("Email required")
return Result.Success(process(name, email))
}
// Avoid !! — it defeats the purpose of null safety
// Bad: user!!.name
// Good: user?.name ?: throw IllegalStateException("User cannot be null here")Sealed Classes for Error Handling
sealed class Result<out T> {
data class Success<T>(val data: T) : Result<T>()
data class Error(val message: String, val cause: Throwable? = null) : Result<Nothing>()
}
fun getUser(id: String): Result<User> {
return try {
val user = repository.findById(id) ?: return Result.Error("User not found")
Result.Success(user)
} catch (e: Exception) {
Result.Error("Database error", e)
}
}
// Exhaustive when — compiler ensures all cases handled
when (val result = getUser("123")) {
is Result.Success -> render(result.data)
is Result.Error -> showError(result.message)
}Coroutine Best Practices
// Use structured concurrency
coroutineScope {
val user = async { userService.getUser(id) }
val orders = async { orderService.getOrders(id) }
ProfileResponse(user.await(), orders.await())
}
// Handle cancellation properly
suspend fun longRunningTask() {
while (isActive) { // Check for cancellation
processNextBatch()
yield() // Cooperative cancellation point
}
}Data Classes for DTOs
data class CreateOrderRequest(
val productId: String,
val quantity: Int,
) {
init {
require(quantity > 0) { "Quantity must be positive" }
require(productId.isNotBlank()) { "Product ID required" }
}
}Extension Functions for Clean APIs
Keep extension functions focused and discoverable. Avoid creating extensions on common types like String or Int that might conflict.
Monitoring
Kotlin's coroutines can swallow exceptions silently in fire-and-forget launches. Use Bugsly to catch these hidden failures and ensure your CoroutineExceptionHandler actually reports errors rather than just logging them.
Try Bugsly Free
AI-powered error tracking that explains your bugs. Set up in 2 minutes, free forever for small projects.
Get Started FreeRelated Articles
FastAPI Logging Best Practices
Set up production-ready logging in FastAPI with structured output, request tracing, middleware integration, and performance monitoring.
Read moreNuxt Production Best Practices
Essential Nuxt best practices for production covering SSR configuration, caching strategies, security headers, and deployment optimization.
Read moreSwift Performance Monitoring Best Practices
Monitor Swift application performance with Instruments profiling, memory tracking, network performance, and real-time crash reporting.
Read moreWhy Your Team Ignores Error Alerts (And How to Fix Alert Fatigue)
Error alerts should drive action, not eye-rolls. A practical guide to designing alerts your team will actually respond to.
Read more