La matinée ne commence pas par un café, mais par une Merge Request
\n\n7h45 du matin. Le téléphone vibre — ce n'est pas le réveil, c'est GitLab qui a envoyé une notification : votre Merge Request d'hier a passé le pipeline CI/CD. Pendant que la bouilloire chauffe, j'ouvre mon ordinateur portable et je vois une coche verte. Première victoire de la journée. Bonjour, Kotlin.
\n\nJe m'appelle Alexeï, je suis développeur Kotlin dans une entreprise de produits. Ces trois dernières années, j'ai écrit du Kotlin pour Android et un peu pour le backend avec Ktor. Si vous pensez que le travail d'un programmeur est un "Hello World" sans fin, je vais dissiper ce mythe aujourd'hui. Bienvenue dans ma journée de travail réelle.
\n\n8h30 — Daily Standup : synchronisation et contexte
\n\nLa première chose qui se produit est le stand-up quotidien. Nous nous réunissons sur Zoom, mais sans les "hier-aujourd'hui-problèmes" superflus. Chez nous, c'est concis : ce qui a été fait, ce qui est prévu, s'il y a des blocages. Aujourd'hui, je travaille sur la fonctionnalité des Notifications Push pour les utilisateurs.
\n\n— Hier, j'ai terminé le refactoring de NotificationService, réécrit avec des coroutines. Aujourd'hui, je connecte Firebase Cloud Messaging et je teste Flow. Pas de blocages.
D'ailleurs, c'est souvent lors des stand-ups que naissent les meilleures idées d'architecture. Par exemple, la semaine dernière, un collègue a suggéré de remplacer RxJava par Kotlin Flow — et nous avons réduit la quantité de code boilerplate de 40%. Voici à quoi cela ressemble maintenant :
\n\n// Au lieu de l'ancien RxJava :\n// Observable.just(data).subscribeOn(Schedulers.io())\n\n// Nous utilisons Kotlin Flow :\nfun observeNotifications(): Flow<Notification> = flow {\n val service = NotificationService()\n while (true) {\n emit(service.getNextNotification())\n delay(5000) // interrogation toutes les 5 secondes\n }\n}.flowOn(Dispatchers.IO)\n\nLa différence est évidente : lisibilité, sécurité des types et pas d'enfer des callbacks.
\n\n9h15 — Développement : écrire du code en Kotlin
\n\nAprès le stand-up, je plonge dans le code. Aujourd'hui, la tâche consiste à implémenter le traitement des notifications push entrantes. J'utilise Kotlin Coroutines et StateFlow pour gérer l'état de l'interface utilisateur. Voici à quoi ressemble mon ViewModel :
\n\nclass PushViewModel(\n private val repository: NotificationRepository\n) : ViewModel() {\n\n private val _uiState = MutableStateFlow<PushUiState>(PushUiState.Loading)\n val uiState: StateFlow<PushUiState> = _uiState.asStateFlow()\n\n fun loadNotifications() {\n viewModelScope.launch {\n repository.getNotifications()\n .catch { e ->\n _uiState.value = PushUiState.Error(e.message ?: "Erreur inconnue")\n }\n .collect { notifications ->\n _uiState.value = PushUiState.Success(notifications)\n }\n }\n }\n}\n\nsealed class PushUiState {\n object Loading : PushUiState()\n data class Success(val data: List<Notification>) : PushUiState()\n data class Error(val message: String) : PushUiState()\n}\n\nRemarquez : j'utilise sealed class pour l'état de l'interface utilisateur. C'est une pratique standard dans le développement Android moderne avec Kotlin. Pas de chaînes if-else — uniquement une typisation propre.
\n\nD'ailleurs, si vous êtes débutant en Kotlin, je vous conseille de vous intéresser aux Scope functions : let, apply, also. Elles rendent le code plus concis. Par exemple :
// Sans scope functions\nval user = User()\nuser.name = "Alex"\nuser.age = 30\nsaveUser(user)\n\n// Avec apply\nval user = User().apply {\n name = "Alex"\n age = 30\n}\nsaveUser(user)\n\n11h00 — Code Review : apprendre des collègues
\n\nAprès le déjeuner (oui, je déjeune à 11h — une habitude du télétravail), j'ouvre une Merge Request d'un collègue. Il réécrit le module d'authentification en Kotlin Multiplatform. Je lis le code et je remarque un point intéressant :
\n\n// C'était (