💻 Développement

dev-kotlin-advanced

Kotlin avancé pour Android fintech. Coroutines, Flows, Sealed classes, inline functions, delegates, reified types.

⚡ Installation & lancement en 1 commande

Copiez-collez dans votre terminal : le skill s'installe dans ~/.claude/skills et Claude Code se lance directement dessus.

macOS / Linux
curl -fsSL https://raw.githubusercontent.com/khalilbenaz/claude-skills-collection/main/install.sh | sh -s -- dev-kotlin-advanced --launch
Windows (PowerShell)
iex "& { $(iwr -useb https://raw.githubusercontent.com/khalilbenaz/claude-skills-collection/main/install.ps1) } dev-kotlin-advanced -Launch"

🚀 Déjà installé ?

claude "/dev-kotlin-advanced"

Ou tapez /dev-kotlin-advanced dans une session Claude Code, ou décrivez simplement votre besoin — le skill se déclenche automatiquement via le skill-router.

🔑 Déclencheurs automatiques

Le skill s'active automatiquement quand votre demande contient :

Kotlin avancécoroutinesFlowsealedextension

📦 Installation manuelle

git clone https://github.com/khalilbenaz/claude-skills-collection.git cp -r claude-skills-collection/skills/dev-kotlin-advanced ~/.claude/skills/

Payload du plugin : skills/dev-kotlin-advanced · source éditable : dev-skills/kotlin-advanced

📖 Manuel

Kotlin Advanced (Android Fintech)

Workflow

1. Structurer la concurrence avec les Coroutines

// Pattern sûr : error handling + timeout
viewModelScope.launch {
    val result = withContext(Dispatchers.IO) {
        withTimeout(5_000L) { api.fetchTransaction(id) }
    }
    _state.value = result.fold(::UiState.Success, ::UiState.Error)
}

// Parallel avec SupervisorJob
viewModelScope.launch {
    val (balance, history) = supervisorScope {
        async { repo.getBalance() } to async { repo.getHistory() }
    }
    // chaque deferred peut échouer indépendamment
}

2. State Management avec Flow

Critères de choix :

BesoinSolution
État UI courant (1 valeur)StateFlow
Événements one-shot (nav, toast)SharedFlow(replay=0)
Stream de données froidflow {}
Combiner plusieurs sourcescombine()
// StateFlow exposition dans ViewModel
private val _uiState = MutableStateFlow<UiState>(UiState.Loading)
val uiState: StateFlow<UiState> = _uiState.asStateFlow()

// Collect avec lifecycle-awareness dans Fragment
viewLifecycleOwner.lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.STARTED) {
        viewModel.uiState.collect { render(it) }
    }
}

// Operators utiles
repo.transactions()
    .filter { it.amount > 0 }
    .map { it.toUiModel() }
    .catch { emit(emptyList()) }
    .flowOn(Dispatchers.IO)
    .collectLatest { adapter.submit(it) }

3. Modéliser les états avec Sealed Classes

sealed class UiState<out T> {
    data object Loading : UiState<Nothing>()
    data class Success<T>(val data: T) : UiState<T>()
    data class Error(val code: Int, val message: String) : UiState<Nothing>()
}

// when exhaustif — le compilateur garantit l'exhaustivité
when (state) {
    is UiState.Loading -> showSpinner()
    is UiState.Success -> render(state.data)
    is UiState.Error   -> showError(state.message)
}

Erreurs métier fintech :

sealed class PaymentError {
    data object InsufficientFunds : PaymentError()
    data class NetworkTimeout(val retryAfterMs: Long) : PaymentError()
    data class FraudBlock(val caseId: String) : PaymentError()
}

4. Extension Functions et DSLs

// Extension utilitaire sur Context
fun Context.toast(msg: String) = Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()

// DSL type-safe pour configurer une transaction
class TransactionBuilder {
    var amount: Long = 0
    var currency: String = "TND"
    var recipient: String = ""
    fun build() = Transaction(amount, currency, recipient)
}
fun transaction(block: TransactionBuilder.() -> Unit) =
    TransactionBuilder().apply(block).build()

// Usage lisible
val tx = transaction {
    amount = 15_000
    currency = "TND"
    recipient = "CLIENT_007"
}

5. Delegates et Property Delegation

// Chiffrement transparent via delegate
class EncryptedPrefsDelegate(private val prefs: SharedPreferences, private val key: String) :
    ReadWriteProperty<Any?, String?> {
    override fun getValue(thisRef: Any?, property: KProperty<*>) =
        prefs.getString(key, null)?.decrypt()
    override fun setValue(thisRef: Any?, property: KProperty<*>, value: String?) {
        prefs.edit { putString(key, value?.encrypt()) }
    }
}

class UserSession(prefs: SharedPreferences) {
    var token: String? by EncryptedPrefsDelegate(prefs, "auth_token")
}

// Delegates Android courants
val viewModel: MyViewModel by viewModels()
val args: MyFragmentArgs by navArgs()
val binding by viewBinding(FragmentPaymentBinding::bind)

6. Inline Functions et Reified Types

// Parsing générique type-safe (évite Class<T> explicite)
inline fun <reified T> String.fromJson(): T =
    Moshi.Builder().build().adapter(T::class.java).fromJson(this)!!

val response: PaymentResponse = jsonString.fromJson()

// Mesure de performance sans overhead lambda
inline fun <T> measureMs(label: String, block: () -> T): T {
    val start = System.currentTimeMillis()
    return block().also { Log.d("PERF", "$label: ${System.currentTimeMillis() - start}ms") }
}

// Logging conditionnel sans allocation si désactivé
inline fun logDebug(tag: String, msg: () -> String) {
    if (BuildConfig.DEBUG) Log.d(tag, msg())
}

7. Jetpack Compose — Performance

// derivedStateOf pour éviter les recompositions inutiles
val isFormValid by remember {
    derivedStateOf { amount > 0 && recipient.isNotBlank() }
}

// LaunchedEffect pour effets side-effect UI
LaunchedEffect(Unit) {
    viewModel.events.collect { event ->
        when (event) {
            is Event.Navigate -> navController.navigate(event.route)
            is Event.ShowError -> scaffoldState.snackbarHostState.showSnackbar(event.msg)
        }
    }
}

// Stable keys pour les listes
LazyColumn {
    items(transactions, key = { it.id }) { tx ->
        TransactionRow(tx)
    }
}

8. Patterns Kotlin-natifs

// Strategy via function types (plus simple que classe abstraite)
fun processPayment(amount: Long, strategy: (Long) -> Result<Unit>) = strategy(amount)
val cardStrategy: (Long) -> Result<Unit> = { amount -> cardService.charge(amount) }

// Factory avec reified
inline fun <reified T : ViewModel> viewModelFactory(crossinline create: () -> T) =
    object : ViewModelProvider.Factory {
        override fun <VM : ViewModel> create(cls: Class<VM>): VM = create() as VM
    }

Garde-fous et anti-patterns

Anti-patternProblèmeCorrectif
GlobalScope.launchMemory leak, pas de cancellationviewModelScope ou scope custom
.collect {} sans repeatOnLifecycleCollect en background, crash config changerepeatOnLifecycle(STARTED)
!! sur nullableNullPointerException en prod?: return, let {}, requireNotNull()
var + mutableListOf dans ViewModelRace condition, état incohérentval + StateFlow immuable
LiveData en nouvelle featureAPI obsolète, moins composableStateFlow + asLiveData() si legacy
runBlocking dans coroutineDeadlock si Dispatchers.MainwithContext à la place
flow {} avec emit depuis thread non-coroutineException IllegalStateExceptioncallbackFlow {} pour callbacks async
copy() data class non utiliséMutation directe d'état partagéToujours créer un nouvel objet

Bonnes pratiques 2026