kotlin-coding-standards
Master Kotlin coding standards with null safety, coroutines, and idiomatic patterns. Use when developing JVM/Android applications requiring type-safe async programming.
$ Installer
git clone https://github.com/williamzujkowski/standards /tmp/standards && cp -r /tmp/standards/skills/coding-standards/kotlin ~/.claude/skills/standards// tip: Run this command in your terminal to install the skill
SKILL.md
name: kotlin-coding-standards description: Master Kotlin coding standards with null safety, coroutines, and idiomatic patterns. Use when developing JVM/Android applications requiring type-safe async programming.
Kotlin Coding Standards
Level 1: Quick Reference
Null Safety Cheat Sheet
// Safe Call (?.) - Returns null if receiver is null
val length = user?.name?.length
// Elvis Operator (?:) - Provides default value
val name = user?.name ?: "Unknown"
// Not-Null Assertion (!!) - Throws NPE if null (avoid!)
val length = user!!.name!!.length
// Safe Cast (as?) - Returns null on cast failure
val employee = person as? Employee
Scope Functions
| Function | Context | Returns | Use Case |
|---|---|---|---|
let | it | Lambda result | Null checks, transforms |
apply | this | Receiver | Object configuration |
also | it | Receiver | Side effects, logging |
run | this | Lambda result | Object config + compute |
with | this | Lambda result | Grouping calls |
// let - transform or null check
user?.let { println("Name: ${it.name}") }
// apply - configure object
val user = User().apply {
name = "Alice"
email = "alice@example.com"
}
Core Patterns
// Data Classes - auto equals, hashCode, toString, copy
data class User(val id: String, val name: String, val email: String)
// Sealed Classes - restricted hierarchies
sealed class Result<out T> {
data class Success<T>(val data: T) : Result<T>()
data class Error(val message: String) : Result<Nothing>()
object Loading : Result<Nothing>()
}
// Extension Functions - add to existing classes
fun String.isValidEmail(): Boolean =
android.util.Patterns.EMAIL_ADDRESS.matcher(this).matches()
Essential Checklist
- Use nullable types (?) instead of !! operator
- Prefer immutable (val) over mutable (var)
- Use data classes for DTOs
- Sealed classes for state management
- Configure detekt + ktlint
- Avoid platform types from Java interop
Level 2: Implementation Guide
1. Null Safety Patterns
Smart Casts - Compiler tracks null checks:
fun processUser(user: User?) {
if (user != null) {
// Smart cast to User
println(user.name)
}
}
// Early return pattern
fun getUserName(user: User?): String {
user ?: return "Unknown"
return user.name // Smart cast after check
}
Initialization Patterns:
// lateinit - for non-nullable late init (Android views, DI)
private lateinit var binding: ActivityMainBinding
// Check if initialized
if (::binding.isInitialized) { /* use binding */ }
// lazy - thread-safe initialization on first access
private val database: AppDatabase by lazy {
Room.databaseBuilder(context, AppDatabase::class.java, "db").build()
}
2. Coroutines Essentials
Suspend Functions:
suspend fun fetchUser(id: String): User {
return withContext(Dispatchers.IO) {
apiService.getUser(id)
}
}
Coroutine Builders:
// launch - fire and forget
CoroutineScope(Dispatchers.IO).launch {
val users = apiService.getUsers()
database.insertAll(users)
}
// async - return deferred result
suspend fun getUserWithDetails(id: String): UserDetails = coroutineScope {
val user = async { apiService.getUser(id) }
val posts = async { apiService.getUserPosts(id) }
UserDetails(user.await(), posts.await())
}
Flow Basics:
// Cold flow - emits on collection
fun getUsers(): Flow<List<User>> = database.getUsersFlow()
// Transform flows
fun getActiveUsers(): Flow<List<User>> = database.getUsersFlow()
.map { users -> users.filter { it.isActive } }
.distinctUntilChanged()
// StateFlow - hot flow with current value
private val _uiState = MutableStateFlow<UiState>(UiState.Loading)
val uiState: StateFlow<UiState> = _uiState.asStateFlow()
3. Collections & Functional Programming
// Transformation
val names = users.map { it.name }
val pairs = users.flatMap { user -> user.emails.map { user to it } }
// Filtering
val active = users.filter { it.isActive }
val (admins, regular) = users.partition { it.isAdmin }
// Aggregation
val count = users.count { it.isActive }
val total = orders.sumOf { it.amount }
// Grouping
val byRole = users.groupBy { it.role }
// Sequences - lazy evaluation for large collections
val result = users.asSequence()
.filter { it.isActive }
.map { it.name.uppercase() }
.take(10)
.toList()
4. Delegation Patterns
// Property delegation - observable
var name: String by Delegates.observable("Unknown") { _, old, new ->
println("Changed from $old to $new")
}
// Custom delegate
class StringPreference(
private val prefs: SharedPreferences,
private val key: String,
private val default: String
) : ReadWriteProperty<Any?, String> {
override fun getValue(thisRef: Any?, property: KProperty<*>): String =
prefs.getString(key, default) ?: default
override fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
prefs.edit().putString(key, value).apply()
}
}
// Class delegation - composition over inheritance
class UserService(logger: Logger) : Logger by logger {
fun createUser(name: String) {
log("Creating user: $name")
}
}
5. Java Interoperability
// Platform types - make nullability explicit
val safeName: String = javaObject.getName() ?: "Unknown"
// JvmStatic - static methods for Java
companion object {
@JvmStatic
fun isBlank(value: String?): Boolean = value.isNullOrBlank()
}
// JvmOverloads - default parameters for Java
class User @JvmOverloads constructor(
val name: String,
val email: String = "",
val age: Int = 0
)
// Checked exceptions
@Throws(IOException::class)
fun readFile(path: String): String = File(path).readText()
6. Testing Quick Start
@Test
fun `getUser returns user from API`() = runTest {
// Given
val userId = "123"
val expectedUser = User(userId, "Alice")
coEvery { mockApi.getUser(userId) } returns expectedUser
// When
val result = repository.getUser(userId)
// Then
assertEquals(expectedUser, result)
coVerify(exactly = 1) { mockApi.getUser(userId) }
}
Level 3: Deep Dive Resources
Documentation
Tools
- Detekt - Static code analysis
- ktlint - Code formatter
- MockK - Mocking library
- Turbine - Flow testing
Extended Reference
See REFERENCE.md for:
- Complete coroutine patterns (StateFlow, SharedFlow, structured concurrency)
- Advanced delegation patterns
- Comprehensive testing examples (JUnit 5, MockK, Flow testing)
- Static analysis configuration
- Custom lint rules
- Spring Boot integration patterns
Last updated: 2025-01-01
Repository

williamzujkowski
Author
williamzujkowski/standards/skills/coding-standards/kotlin
11
Stars
0
Forks
Updated5d ago
Added1w ago