
Kotlin Expert
- 189 installs
- 41 repo stars
- Updated March 30, 2026
- personamanagmentlayer/pcl
Build and review Kotlin for Android apps and JVM backend services with coroutines, null-safety, Gradle setup, and API layers while keeping code testable and production ready.
About
The kotlin-expert skill from personamanagmentlayer/pcl provides specialized Kotlin guidance for Android and JVM backend development. It covers coroutines, type-safe modeling, build configuration, and service architecture so teams write concise, testable Kotlin that scales from mobile clients to server APIs without common interop pitfalls.
- Kotlin coroutines and concurrency patterns
- Null-safety and idiomatic type design
- Android and JVM service implementation tips
- Gradle and dependency configuration guidance
- Testable architecture and API layering advice
Kotlin Expert by the numbers
- 189 all-time installs (skills.sh)
- Ranked #463 of 1,039 Mobile Development skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/personamanagmentlayer/pcl --skill kotlin-expertAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 189 |
|---|---|
| repo stars | ★ 41 |
| Last updated | March 30, 2026 |
| Repository | personamanagmentlayer/pcl ↗ |
What it does
Build and review Kotlin for Android apps and JVM backend services with coroutines, null-safety, Gradle setup, and API layers while keeping code testable and production ready.
Files
Kotlin Expert
Expert guidance for Kotlin development, Android, coroutines, Kotlin Multiplatform, and modern JVM development.
Core Concepts
Kotlin Fundamentals
- Null safety
- Extension functions
- Data classes
- Sealed classes
- Coroutines and Flow
- Higher-order functions
Android Development
- Jetpack Compose
- ViewModel and LiveData
- Room database
- Retrofit networking
- Dependency injection (Hilt)
- Android lifecycle
Kotlin Multiplatform
- Shared business logic
- Platform-specific implementations
- iOS and Android targets
- Common module architecture
Modern Kotlin Syntax
// Data classes
data class User(
val id: String,
val name: String,
val email: String,
val createdAt: LocalDateTime = LocalDateTime.now()
)
// Sealed classes for type-safe states
sealed class Result<out T> {
data class Success<T>(val data: T) : Result<T>()
data class Error(val exception: Exception) : Result<Nothing>()
object Loading : Result<Nothing>()
}
// Extension functions
fun String.isValidEmail(): Boolean {
return this.contains("@") && this.contains(".")
}
// Scope functions
fun processUser(user: User) {
user.run {
println("Processing user: $name")
// 'this' refers to user
}
user.let { u ->
// 'it' or custom name refers to user
println(u.email)
}
user.apply {
// Modify properties
// Returns the object
}
}
// Null safety
fun findUser(id: String): User? {
return database.find(id)
}
val user = findUser("123")
val name = user?.name ?: "Unknown" // Elvis operator
user?.let { println(it.name) } // Safe call with let
// When expression
fun getUserStatus(user: User): String = when {
user.isActive && user.isPremium -> "Premium Active"
user.isActive -> "Active"
else -> "Inactive"
}Coroutines and Flow
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
class UserRepository {
private val api: UserApi
// Suspend function
suspend fun fetchUser(id: String): User {
return withContext(Dispatchers.IO) {
api.getUser(id)
}
}
// Flow for reactive streams
fun observeUsers(): Flow<List<User>> = flow {
while (true) {
val users = fetchUsers()
emit(users)
delay(5000) // Refresh every 5 seconds
}
}.flowOn(Dispatchers.IO)
// StateFlow for state management
private val _users = MutableStateFlow<List<User>>(emptyList())
val users: StateFlow<List<User>> = _users.asStateFlow()
suspend fun refreshUsers() {
_users.value = fetchUsers()
}
}
// Coroutine scopes
class UserViewModel : ViewModel() {
private val repository = UserRepository()
fun loadUsers() {
viewModelScope.launch {
try {
val users = repository.fetchUser("123")
// Update UI
} catch (e: Exception) {
// Handle error
}
}
}
// Parallel execution
suspend fun loadMultipleUsers(ids: List<String>): List<User> {
return coroutineScope {
ids.map { id ->
async { repository.fetchUser(id) }
}.awaitAll()
}
}
// Flow transformation
fun searchUsers(query: String): Flow<List<User>> {
return repository.observeUsers()
.map { users -> users.filter { it.name.contains(query, ignoreCase = true) } }
.distinctUntilChanged()
.debounce(300)
}
}Android Jetpack Compose
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
@Composable
fun UserListScreen(viewModel: UserViewModel = viewModel()) {
val users by viewModel.users.collectAsState()
val isLoading by viewModel.isLoading.collectAsState()
Scaffold(
topBar = { TopAppBar(title = { Text("Users") }) }
) { padding ->
if (isLoading) {
CircularProgressIndicator(
modifier = Modifier.fillMaxSize()
)
} else {
LazyColumn(
modifier = Modifier.padding(padding)
) {
items(users) { user ->
UserCard(user = user)
}
}
}
}
}
@Composable
fun UserCard(user: User) {
Card(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
) {
Column(modifier = Modifier.padding(16.dp)) {
Text(
text = user.name,
style = MaterialTheme.typography.headlineSmall
)
Text(
text = user.email,
style = MaterialTheme.typography.bodyMedium
)
}
}
}Room Database
import androidx.room.*
import kotlinx.coroutines.flow.Flow
@Entity(tableName = "users")
data class UserEntity(
@PrimaryKey val id: String,
@ColumnInfo(name = "name") val name: String,
@ColumnInfo(name = "email") val email: String,
@ColumnInfo(name = "created_at") val createdAt: Long
)
@Dao
interface UserDao {
@Query("SELECT * FROM users")
fun getAllUsers(): Flow<List<UserEntity>>
@Query("SELECT * FROM users WHERE id = :userId")
suspend fun getUserById(userId: String): UserEntity?
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertUser(user: UserEntity)
@Update
suspend fun updateUser(user: UserEntity)
@Delete
suspend fun deleteUser(user: UserEntity)
@Query("DELETE FROM users WHERE id = :userId")
suspend fun deleteUserById(userId: String)
}
@Database(entities = [UserEntity::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
companion object {
@Volatile
private var INSTANCE: AppDatabase? = null
fun getDatabase(context: Context): AppDatabase {
return INSTANCE ?: synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
AppDatabase::class.java,
"app_database"
).build()
INSTANCE = instance
instance
}
}
}
}Dependency Injection with Hilt
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
@Provides
@Singleton
fun provideRetrofit(): Retrofit {
return Retrofit.Builder()
.baseUrl("https://api.example.com")
.addConverterFactory(GsonConverterFactory.create())
.build()
}
@Provides
@Singleton
fun provideUserApi(retrofit: Retrofit): UserApi {
return retrofit.create(UserApi::class.java)
}
}
@HiltAndroidApp
class MyApplication : Application()
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
@Inject lateinit var repository: UserRepository
}Kotlin Multiplatform
// commonMain
expect class Platform() {
val name: String
}
expect fun platformSpecificFunction(): String
// androidMain
actual class Platform actual constructor() {
actual val name: String = "Android ${android.os.Build.VERSION.SDK_INT}"
}
actual fun platformSpecificFunction(): String = "Android implementation"
// iosMain
actual class Platform actual constructor() {
actual val name: String = UIDevice.currentDevice.systemName()
}
actual fun platformSpecificFunction(): String = "iOS implementation"
// Shared business logic
class UserService {
suspend fun fetchUser(id: String): User {
// Shared logic works on all platforms
return api.getUser(id)
}
}Best Practices
Kotlin Style
- Use val over var when possible
- Leverage null safety features
- Use data classes for DTOs
- Prefer extension functions
- Use sealed classes for type-safe states
- Follow naming conventions
Coroutines
- Use appropriate dispatchers (IO, Main, Default)
- Handle cancellation properly
- Avoid GlobalScope
- Use structured concurrency
- Prefer Flow over LiveData
- Use StateFlow for state
Android
- Follow MVVM architecture
- Use Jetpack Compose for UI
- Implement proper lifecycle handling
- Use dependency injection
- Handle configuration changes
- Implement proper error handling
Anti-Patterns
❌ Using !! (non-null assertion) ❌ GlobalScope.launch ❌ Blocking main thread ❌ Not handling coroutine cancellation ❌ Tight coupling ❌ God classes ❌ Ignoring memory leaks
Resources
- Kotlin Docs: https://kotlinlang.org/docs/
- Android Developers: https://developer.android.com/kotlin
- Kotlin Coroutines: https://kotlinlang.org/docs/coroutines-overview.html
- Jetpack Compose: https://developer.android.com/jetpack/compose