SkillByAIOpen interactive version →

Lesson 25 / 25

A Kotlin Production Checklist

Review before shipping.

Questions to ask

Are nullable types explicit at boundaries, with few or no !!? Are values val and collections read-only where possible? Are states and results modelled with sealed types and exhaustive when without else? Are coroutines launched in lifecycle-bound scopes, with no GlobalScope, blocking work on Dispatchers.IO and CancellationException never swallowed? Are Java boundaries typed explicitly and annotated for Java callers? Are tests written with kotlin.test or JUnit 5, using runTest for coroutines? Do ktlint and detekt run in CI, and are Kotlin and library versions kept current?

The checklist

Use it in code review.

# [ ] prefer val and read-only List/Set/Map; data classes for values
# [ ] nullability explicit at boundaries; avoid !!; requireNotNull with messages
# [ ] sealed types + exhaustive when (no else) for states and results
# [ ] coroutines in structured scopes; no GlobalScope; runBlocking only at the edges
# [ ] Dispatchers.IO for blocking calls; rethrow CancellationException
# [ ] platform types pinned; @JvmStatic / @JvmOverloads for Java callers
# [ ] tests with kotlin.test / JUnit 5, MockK, runTest
# [ ] style and static analysis in CI
./gradlew ktlintCheck detekt test     # task names depend on the plugins you apply

Let the compiler work for you

Turn on allWarningsAsErrors in CI once warnings are under control; Kotlin warnings often point at real nullability or deprecation problems.

Quick check: Which practice belongs on a Kotlin production checklist?

  • Add else to every when over a sealed type
  • Use !! wherever the compiler complains
  • Launch coroutines in lifecycle-bound scopes instead of GlobalScope
  • Call runBlocking inside suspend functions
Answer

Launch coroutines in lifecycle-bound scopes instead of GlobalScope — Structured scopes prevent leaked work.