Apply idiomatic Kotlin patterns to build robust, efficient, maintainable applications.
Copy the install command and let the AI configure it · recommended for beginners
Please install the "kotlin-patterns" skill from askskill: 1. Download https://raw.githubusercontent.com/affaan-m/ECC/main/skills/kotlin-patterns/SKILL.md 2. Save it as ~/.claude/skills/kotlin-patterns/SKILL.md 3. Reload skills and tell me it's ready
Review this Kotlin coroutine code for best practices and refactor it into a safer, more maintainable version, including structured concurrency, exception handling, cancellation propagation, and dispatcher guidance.
Returns improved Kotlin code with step-by-step explanations of optimizations and potential risks.
Help me design a more idiomatic null-safe Kotlin API for a data layer, minimizing !! usage and using nullable types, sealed classes, and the Result pattern, with example code.
Provides an API design, sample implementation, and explanations of why it is safer and easier to maintain.
Design a Kotlin DSL for a configuration system using idiomatic Kotlin style, with builders, scope functions, and type-safe builders, and show a complete example.
Outputs the DSL design, core code examples, usage patterns, and advice on readability and extensibility.
Idiomatic Kotlin patterns and best practices for building robust, efficient, and maintainable applications.
This skill enforces idiomatic Kotlin conventions across seven key areas: null safety using the type system and safe-call operators, immutability via val and copy() on data classes, sealed classes and interfaces for exhaustive type hierarchies, structured concurrency with coroutines and Flow, extension functions for adding behaviour without inheritance, type-safe DSL builders using @DslMarker and lambda receivers, and Gradle Kotlin DSL for build configuration.
Null safety with Elvis operator:
fun getUserEmail(userId: String): String {
val user = userRepository.findById(userId)
return user?.email ?: "[email protected]"
}
Sealed class for exhaustive results:
sealed class Result<out T> {
data class Success<T>(val data: T) : Result<T>()
data class Failure(val error: AppError) : Result<Nothing>()
data object Loading : Result<Nothing>()
}
Structured concurrency with async/await:
suspend fun fetchUserWithPosts(userId: String): UserProfile =
coroutineScope {
val user = async { userService.getUser(userId) }
val posts = async { postService.getUserPosts(userId) }
UserProfile(user = user.await(), posts = posts.await())
}
Kotlin's type system distinguishes nullable and non-nullable types. Leverage it fully.
// Good: Use non-nullable types by default
fun getUser(id: String): User {
return userRepository.findById(id)
?: throw UserNotFoundException("User $id not found")
}
// Good: Safe calls and Elvis operator
fun getUserEmail(userId: String): String {
val user = userRepository.findById(userId)
return user?.email ?: "[email protected]"
}
// Bad: Force-unwrapping nullable types
fun getUserEmail(userId: String): String {
val user = userRepository.findById(userId)
return user!!.email // Throws NPE if null
}
Prefer val over var, immutable collections over mutable ones.
// Good: Immutable data
data class User(
val id: String,
val name: String,
val email: String,
)
// Good: Transform with copy()
fun updateEmail(user: User, newEmail: String): User =
user.copy(email = newEmail)
// Good: Immutable collections
val users: List<User> = listOf(user1, user2)
val filtered = users.filter { it.email.isNotBlank() }
// Bad: Mutable state
var currentUser: User? = null // Avoid mutable global state
val mutableUsers = mutableListOf<User>() // Avoid unless truly needed
Use expression bodies for concise, readable functions.
// Good: Expression body
fun isAdult(age: Int): Boolean = age >= 18
fun formatFullName(first: String, last: String): String =
"$first $last".trim()
fun User.displayName(): String =
name.ifBlank { email.substringBefore('@') }
// Good: When as expression
fun statusMessage(code: Int): String = when (code) {
200 -> "OK"
404 -> "Not Found"
500 -> "Internal Server Error"
else -> "Unknown status: $code"
}
// Bad: Unnecessary block body
fun isAdult(age: Int): Boolean {
return age >= 18
}
Use data classes for types that primarily hold data.
// Good: Data class with copy, equals, hashCode, toString
data class CreateUserRequest(
val name: String,
val email: String,
val role: Role = Role.USER,
)
// Good: Value class for type safety (zero overhead at runtime)
@JvmInline
value class UserId(val value: String) {
init {
…
Plan demand forecasts, safety stock, and replenishment for multi-location retail inventory.
Automatically format, lint, and fix code issues on every edit.
Apply NestJS architecture patterns to build maintainable production-ready TypeScript backends.
Learn robust error-handling patterns across TypeScript, Python, and Go applications.
Audit Claude skills and commands with quick scans or full stocktakes.
Create iOS liquid glass interfaces with dynamic visuals and interactive morphing.
Learn idiomatic Go patterns and best practices for robust, maintainable applications.
Learn practical Kotlin Ktor server patterns for building and testing backend apps.
Learn idiomatic Rust patterns, ownership, concurrency, and robust error handling practices.
Get idiomatic C# and .NET guidance for architecture, async, and dependency injection.
Build high-quality Kotlin tests with Kotest, MockK, coroutines, and coverage.
Learn practical Kotlin Coroutines and Flow patterns for Android and KMP.