Kotlin
A concise multiplatform language developed by JetBrains
Développer l’adoption de Kotlin dans votre entreprise
Article de notre invité Urs Peter, Ingénieur logiciel senior et Formateur Kotlin certifié JetBrains. Pour les lecteurs qui souhaitent une approche plus structurée pour développer leurs compétences en Kotlin, Urs anime également le Kotlin Upskill Program à la Xebia Academy.
Ceci est le troisième article du Guide complet pour réussir l’adoption de Kotlin dans un environnement Java, qui explique concrètement comment l’adoption de Kotlin peut être progressivement déployée au sein d’une équipe, en partant de la curiosité d’un développeur pour aboutir à une transformation à l’échelle de l’entreprise.
Tous les articles de la série :
- Premiers pas avec Kotlin pour les développeurs Java
- Évaluer Kotlin dans des projets réels
- Développer l’adoption de Kotlin dans votre entreprise
Faire passer le message : convaincre vos collègues développeurs
À présent, vous avez un noyau dur de développeurs convaincus des avantages de Kotlin. Vient alors la phase critique : comment accroître l’adoption ?
Au cours de cette phase, la clé est de convaincre les développeurs Java sceptiques. Plusieurs facteurs techniques et culturels peuvent faire la différence :
Facteurs techniques : le code
- Laissez parler le code
Facteurs culturels : soutenir et connecter les développeurs
- Facilitez l’intégration des nouveaux membres
- Proposez des ressources d’autoformation
- Mettez en place une communauté Kotlin en interne
- Soyez patient…
Laissez parler le code
Capitalisez sur l’expérience acquise en (ré-)écrivant une application en Kotlin et démontrez-en les avantages de manière tangible et accessible :
- Montrer plutôt qu’expliquer : présentez la concision gagnée avec Kotlin en comparant des extraits de code Java et Kotlin.
- Se concentrer sur les paradigmes principaux : Kotlin n’est pas simplement différent de Java ; il repose sur des fondements de sécurité, de concision pour une lisibilité et une maintenabilité optimales, d’extensibilité et d’une importance capitale accordée aux fonctions. Ensemble, ces paradigmes pallient les limitations fondamentales de Java, tout en préservant une interopérabilité totale avec l’écosystème Java.
Voici quelques exemples concrets :
1. Sécurité contre les valeurs null : la fin des erreurs à un milliard de dollars
Java
//This is why we have the billion-dollar mistake (not only in Java…) Booking booking = null; //🤨 This is allowed but causes: booking.destination; //Runtime error 😱 Optional booking = null; //Optionals aren’t safe from null either: 🤨 booking.map(Destination::destination); //Runtime error 😱
Au fil du temps, Java a ajouté des fonctionnalités de sécurité contre les valeurs null, comme « Optional » et les Annotations (par exemple, @NotNull), mais cela n’a pas permis de résoudre ce problème fondamental. De plus, le projet Valhalla (types Null-Restricted et Nullables) n’introduira pas la sécurité contre les valeurs null en Java, mais offrira plutôt davantage d’options parmi lesquelles choisir.
Kotlin
//Important to realize that null is very restricted in Kotlin: val booking:Booking? = null //…null can only be assigned to Nullable types ✅ val booking:Booking = null //null assigned to a Non-nullable types yields a Compilation error 😃 booking.destination //unsafely accessing a nullable type directly causes a Compilation error 😃 booking?.destination //only safe access is possible ✅
L’un des grands avantages de la sécurité contre les valeurs null de Kotlin est qu’en plus d’être sûre, elle est très facile à utiliser. Voici exemple classique de la possibilité « d’avoir le beurre et l’argent du beurre » :
Supposons que nous ayons ce domaine :
Kotlin
data class Booking(val destination:Destination? = null) data class Destination(val hotel:Hotel? = null) data class Hotel(val name:String, val stars:Int? = null)
Java
public record Booking(Optional destination) {
public Booking() { this(Optional.empty()); }
public Booking(Destination destination) {
this(Optional.ofNullable(destination));
}
}
public record Destination(Optional hotel) {
public Destination() { this(Optional.empty()); }
public Destination(Hotel hotel) {
this(Optional.ofNullable(hotel));
}
}
public record Hotel(String name, Optional stars) {
public Hotel(String name) {
this(name, Optional.empty());
}
public Hotel(String name, Integer stars) {
this(name, Optional.ofNullable(stars));
}
}
Construction d’objets
Java
//Because Optional is a wrapper, the number of nested objects grows, which doesn’t help readability
final Optional booking = Optional.of(new Booking(
Optional.of(new Destination(Optional.of(
new Hotel("Sunset Paradise", 5))))));
Kotlin
//Since nullability is part of the type system, no wrapper is needed: The required type or null can be used.
val booking:Booking? = Booking(Destination(Hotel("Sunset Paradise", 5)))
Navigation entre objets imbriqués
Java
//traversing a graph of Optionals requires extensive unwrapping
final var stars = "*".repeat(booking
.flatMap(Booking::getDestination)
.flatMap(Destination::getHotel)
.map(Hotel::getStars).orElse(0)); //-> "*****"
Kotlin
//Easily traverse a graph of nullable types with: ‘?’, use ?: for the ‘else’ case. val stars = "*".repeat(booking?.destination?.hotel?.stars ?: 0) //-> "*****"
Déballage d’un objet imbriqué
Java
//extensive unwrapping is also needed for printing a leaf booking.getDestination() .flatMap(Destination::getHotel) .map(Hotel::getName) .map(String::toUpperCase) .ifPresent(System.out::println);
Kotlin
//In Kotlin we have two elegant options:
//1. we can again traverse the graph with ‘?’
booking?.destination?.hotel.?name?.uppercase()?.also(::println)
//2. We can make use of Kotlin’s smart-cast feature
if(booking?.destination?.hotel != null) {
//The compiler has checked that all the elements in the object graph are not null, so we can access the elements as if they were non-nullable types
println(booking.destination.hotel.uppercase())
}
Le manque de prise en charge de la sécurité contre les valeurs null en Java est un problème majeur pour les développeurs. Il entraîne une programmation défensive, différentes constructions de nullabilité (ou aucune), et augmente la verbosité. De plus, les « NullPointerException » sont responsables d’environ un tiers des plantages d’applications (Le blog JetBrains). La vérification au moment de la compilation de Kotlin empêche totalement ces échecs lors de l’exécution. C’est pourquoi, aujourd’hui encore, la sécurité contre les valeurs null est la principale raison de migrer vers Kotlin.
2. Les Collections sont vos alliées, pas vos ennemies
Le créateur de Spring, Rod Johnson, a déclaré dans une interview récente que ce n’étaient pas les types Nullable qui l’avaient poussé à utiliser Kotlin, mais la complexité excessive de l’API Java Streams : Creator of Spring: No desire to write Java.
L’exemple suivant illustre les diverses raisons pour lesquelles l’API Java Streams est si horriblement compliquée et montre comment Kotlin résout tous ces problèmes :
Java
public record Product(String name, int... ratings){}
List products = List.of(
new Product("gadget", 9, 8, 7),
new Product("goody", 10, 9)
);
Map maxRatingsPerProduct =
//🤨 1. Stream introduces indirection
products.stream()
//🤨 1. Always to and from Stream conversion
.collect(
//🤨 2. Lacks extension methods, so wrappers are required
Collectors.groupingBy(
Product::name,
//🤨 2. Again…
Collectors.mapping( groupedProducts ->
//🤨 3. (too) low-level types, arrays, and primitives cause extra complexity
//🤨 4. No API on Array, always wrap in stream
Arrays.stream(groupedProducts.ratings())
.max()
//🤨 5. Extra verbosity due to Optional
.orElse(0.0),
//🤨 6. No named arguments: what does this do?
Collectors.reducing(0, Integer::max)
)
));
Kotlin
//😃 rich and uniform Collection API - even on Java collections - due to extension methods
val maxRatingsPerProduct = products.
.groupBy { it.name }
.mapValues { (_, groupedProducts) -> //😃 destructuring for semantic precision
//😃 built-in nullability support, and the same API for
//arrays like other Collections
groupedProducts.flatMap { it.ratings }
.maxOrNull() ?: 0
}
}
Grâce au framework collection uniforme de Kotlin, la conversion entre plusieurs types de collections est très simple :
Java
int[] numbers = {1, 3, 3, 5, 2};
Set unique = Arrays.stream(numbers).boxed().collect(Collectors.toSet());
Map evenOrOdd = unique.stream()
.collect(Collectors.toMap(
n -> n,
n -> n % 2 == 0));
Kotlin
val numbers = arrayOf(1, 3, 3, 5, 2)
val unique: Set = numbers.toSet() //😃 simply call to to do the conversion
val evenOrOdd: Map = unique.associateWith { it % 2 == 0 }
Effet net :
- API Collection riche en fonctionnalités et intuitive : les pipelines se lisent de gauche à droite, comme en anglais, pas dans des appels de collecteur imbriqués.
- Moins de code réutilisable et de complexité : pas de Collectors.groupingBy, pas de Stream, pas d’Optional, pas d’Arrays.stream.
- Modèle mental unique : que vous partiez d’une
List, d’unSet, d’unArrayou d’un tableau primitif, vous recherchez les mêmes opérateurs de collection. - Performances sans douleur : le compilateur insère du boxing ou du unboxing uniquement là où c’est inévitable ; vous écrivez du code normal.
- Sécurité intégrée contre les valeurs null : l’API Collection prend entièrement en charge la nullabilité avec différentes méthodes utilitaires souvent suffixées avec
orNull (…). - Interopérabilité transparente avec Java grâce à des wrappers idiomatiques : grâce aux méthodes d’extension, vous bénéficiez du « meilleur des deux mondes » : des collections riches en fonctionnalités en plus des collections Java.
Pour le dire simplement, Kotlin élève les tâches routinières avec les collections (filtrage, mappage, regroupement, etc.) au rang de fonctions de première classe qui peuvent être composées, afin que vous puissiez exprimer ce que vous voulez, au lieu de comment y parvenir.
3. Avec Kotlin, fini les exceptions vérifiées, mais le code est plus sûr
Java est l’un des rares langages qui prend encore en charge les Exceptions vérifiées. Bien qu’initialement implémentées comme fonctionnalité de sécurité, elles n’ont pas tenu leur promesse. Leur verbosité, les blocs catch inutiles qui ne font rien ou relancent une Exception en tant que RuntimeException, et leur manque d’alignement avec les lambdas sont unes des quelques raisons pour lesquelles elles entravent davantage votre code qu’elles ne le sécurisent.
Kotlin suit le paradigme éprouvé utilisé par presque tous les autres langages de programmation (C#, Python, Scala, Rust et Go) qui consiste à n’utiliser les exceptions que pour des situations irrécupérables.
Les exemples suivants mettent en évidence les obstacles que les Exceptions vérifiées introduisent dans votre code, sans ajouter de sécurité :
Java
public String downloadAndGetLargestFile(List urls) {
List contents = urls.stream().map(urlStr -> {
Optional optional;
try {
optional = Optional.of(new URI(urlStr).toURL());
//🤨 Within lambdas checked exceptions are not supported and must always be caught...
} catch (URISyntaxException | MalformedURLException e) {
optional = Optional.empty();
}
return optional;
}).filter(Optional::isPresent) //Quite a mouthful to get rid of the Optional...
.map(Optional::get)
.map(url -> {
try (InputStream is = url.openStream()) {
return new String(is.readAllBytes(), StandardCharsets.UTF_8);
} catch (IOException e) {
//🤨… or re-thrown, which is annoying, I don’t really care about IOE
throw new IllegalArgumentException(e);
}
}).toList();
//🤨 An empty List results in a NoSuchElementException, so why is it not checked? The chance that the List is empty is as high as the other two cases above...
return Collections.max(contents);
}
Kotlin
//😃 safe return type
fun downloadAndGetLargestFile(urls: List): String? =
urls.mapNotNull { //😃 convenient utility methods to rid of null
//😃 try catch is possible, yet runCatching is an elegant way to convert an exception to null
runCatching { URI(it).toURL() }.getOrNull()
}.maxOfOrNull{ //😃 safe way to retrieve the max value
it.openStream().use{ it.reader().readText() } //😃 convenient extension methods to make java.io streams fluent
}
4. Les fonctions comme citoyens de première classe
Kotlin considère les fonctions comme des citoyens de première classe, ce qui peut soulever des questions pour les développeurs Java : qu’est-ce que cela signifie et pourquoi est-ce important ?
La différence essentielle réside dans l’approche limitée de Java : ses capacités fonctionnelles se concentrent principalement sur le site d’appel via les lambdas, tandis que le côté déclaration reste lié à des interfaces fonctionnelles verbeuses et moins intuitives. En Kotlin, vous pouvez définir, passer, retourner et composer des fonctions sans aucun code générique, ce qui rend la programmation fonctionnelle bien plus expressive et naturelle.
Java
public void doWithImage(
URL url,
//🤨 Function interfaces introduce an indirection: because we don’t see the signature of a Function we don’t know what a BiConsumer does, unless we look it up
BiConsumer f) throws IOException {
f.accept(url.getFile(), ImageIO.read(url));
}
//🤨 Same here
public void debug(Supplier f) {
if(isDebugEnabled()) {
logger.debug("Debug: " + f.get());
}
}
//🤨 calling no-argument lambdas is verbose
debug(() -> "expensive concat".repeat(1000));
Kotlin
fun doWithImage(
url: URL,
//😃 Kotlin has a syntax for declaring functions: from the signature, we see what goes in and what goes out
f:(String, BufferedImage) -> Unit) =
f(url.file, ImageIO.read(url))
//😃 same here: nothing goes in, a String goes out
fun debug(msg: () -> String) {
if(isDebugEnabled) {
logger.debug(msg())
}
}
//😃 convenient syntax to pass a lambda: {}
debug{"expensive concat".repeat(1000)}
Kotlin offre une syntaxe claire et concise pour déclarer des fonctions : rien qu’à partir de la signature, vous pouvez immédiatement voir ce qui entre et ce qui sort, sans avoir à naviguer vers une interface fonctionnelle externe.
Java « divulgue » ses fonctionnalités de programmation fonctionnelle via un large ensemble d’interfaces java.util.function.* aux signatures longues et complexes, ce qui rend souvent la programmation fonctionnelle fastidieuse. Kotlin, à l’inverse, traite les fonctions comme des citoyens de première classe : ces interfaces restent cachées aux yeux du développeur, tout en restant pleinement interopérables avec l’approche de Java :

Par conséquent, l’utilisation des fonctions en Kotlin est beaucoup plus simple, directe et intuitive, ce qui facilite grandement l’exploitation de ce puissant concept de programmation pour votre propre code.
5. Concurrence sans souci avec les coroutines
Si vous avez besoin d’un débit élevé, d’un traitement parallèle au sein d’une même requête ou de streaming, la seule option dont vous disposez en Java est une bibliothèque réactive, comme Reactor et RxJava, disponible dans des frameworks tels que Spring WebFlux, Vert.X, Quarkus, etc.
Le problème avec ces bibliothèques, c’est qu’elles sont notoirement compliquées, et vous obligent à utiliser la programmation fonctionnelle. Leur courbe d’apprentissage est donc assez rude, et pourtant il est très facile de commettre des erreurs qui peuvent avoir des conséquences désastreuses lorsque l’application est soumise à une forte charge. C’est très probablement la raison pour laquelle la programmation réactive ne s’est jamais généralisée.
Remarque : les VirtualThreads ne remplacent pas les bibliothèques réactives, même s’il existe un certain chevauchement. Les VirtualThreads offrent des entrées/sorties non bloquantes, mais ne fournissent pas de fonctionnalités telles que le traitement parallèle ou les flux réactifs. La concurrence structurée et les valeurs délimitées permettront également le traitement parallèle une fois que les principaux frameworks prendront en charge cette fonctionnalité. Pour les flux réactifs, vous devrez toujours vous appuyer sur une bibliothèque réactive.
Supposons donc que vous êtes un développeur Java utilisant Spring Boot et que vous souhaitez effectuer un appel parallèle au sein d’une même requête. Voici le résultat que vous obtenez :
@PostMapping("/users")
@ResponseBody
@Transactional
public Mono storeUser(@RequestBody User user) {
Mono avatarMono = avatarService.randomAvatar();
Mono validEmailMono = emailService.verifyEmail(user.getEmail());
//🤨 what does ‘zip’ do?
return Mono.zip(avatarMono, validEmailMono).flatMap(tuple ->
if(!tuple.getT2()) //what is getT2()? It’s the validEmail Boolean…
//🤨 why can I not just throw an exception?
Mono.error(new InvalidEmailException("Invalid Email"));
else personDao.save(UserBuilder.from(user)
.withAvatarUrl(tuple.getT1()));
);
}
Même si ce code fonctionne parfaitement du point de vue de l’exécution, la complexité accidentelle introduite est énorme :
- Le code est dominé par
Mono/Fluxtout au long de la chaîne d’appels, ce qui vous oblige à encapsuler tous les objets de domaine. - Il y a de nombreux opérateurs complexes partout, comme
zip,flatMap, etc. - Vous ne pouvez pas utiliser des constructions de programmation standard telles que la levée d’exceptions.
- L’intention initiale de votre code en souffre considérablement : le code se concentre sur les
MonosetflatMap, occultant ainsi ce qui se passe réellement d’un point de vue métier.
La bonne nouvelle, c’est qu’il existe un remède puissant : les Coroutines Kotlin. Les coroutines peuvent être considérées comme une implémentation réactive au niveau du langage. En tant que telles, elles combinent le meilleur des deux mondes :
- Vous écrivez du code séquentiel comme vous le faisiez auparavant.
- Le code s’exécute de manière asynchrone/en parallèle au moment de l’exécution.
Le code Java ci-dessus, converti en coroutines, ressemble à ceci :
@GetMapping("/users")
@ResponseBody
@Transactional
suspend fun storeUser(@RequestBody user:User):User = coroutineScope {
val avatarUrl = async { avatarService.randomAvatar() }
val validEmail = async { emailService.verifyEmail() }
if(!validEmail.await()) throw InvalidEmailException("Invalid email")
personRepo.save(user.copy(avatar = avatarUrl.await()))
}
Le mot-clé « suspend » de Kotlin permet une exécution structurée et non bloquante, de manière claire et concise. Combiné à async{} et await(), il facilite le traitement parallèle sans avoir besoin de rappels profondément imbriqués ou de constructions complexes telles que Mono ou CompletableFuture.
C’est pourquoi la complexité va diminuer, tandis que la satisfaction des développeurs et la maintenabilité vont augmenter, avec exactement les mêmes caractéristiques de performance.

Remarque : tous les frameworks web majeurs basés sur Java ne prennent pas aussi bien en charge les coroutines. Spring s’en sort très bien, tout comme Micronaut. Quarkus offre actuellement une prise en charge limitée des coroutines.
6. Mais bon, Java évolue aussi !
Java poursuit son évolution avec des fonctionnalités comme les enregistrements, la correspondance des schémas, et des projets à venir tels qu’Amber, Valhalla et Loom. Cette évolution constante renforce la JVM et bénéficie à l’ensemble de l’écosystème.
Mais il y a un hic : la plupart de ces « nouvelles » fonctionnalités Java sont des choses dont les développeurs Kotlin bénéficient depuis des années. La sécurité contre les valeurs null, les classes de valeurs, les fonctions de niveau supérieur, les arguments par défaut, les collections concises et la place prépondérante des fonctions sont tous intégrés dans la conception de Kotlin, livrés d’une manière plus unifiée et conviviale pour les développeurs. C’est pourquoi le code Kotlin paraît souvent plus propre, plus sûr et beaucoup plus productif.
Et ce n’est pas tout : Kotlin bénéficie également des innovations de Java. Les avancées au niveau de la JVM comme les Virtual Threads et Loom en général, ou les gains de performance de Valhalla, s’appliquent aussi de manière transparente à Kotlin.
En bref : Java évolue, mais Kotlin a été conçu dès le départ pour offrir aux développeurs les outils modernes dont ils ont besoin, ce qui en fait un choix sûr, moderne et pérenne.

7. L’avantage évolutif de Kotlin
Les langages de programmation plus anciens traînent inévitablement un certain bagage historique par rapport aux alternatives modernes. Mettre à jour un langage tout en prenant en charge des bases de code existantes massives présente des défis uniques pour les concepteurs du langage. Kotlin bénéficie de deux avantages cruciaux :
Références solides : plutôt que de réinventer la roue, l’équipe de conception initiale de Kotlin a rassemblé des paradigmes éprouvés issus des langages de programmation majeurs et les a unifiés dans un ensemble cohérent. Cette approche a maximisé l’apprentissage évolutif grâce à la taille élargie de la communauté de développement.
Apprendre des lacunes de Java : les concepteurs de Kotlin ont pu observer les défauts de Java et développer des solutions solides dès le départ.
Pour aller plus loin sur l’évolution de Kotlin, Andrey Breslav, membre de l’équipe de conception originale de Kotlin, a donné une excellente conférence au KotlinDevDay d’Amsterdam : Shoulders of Giants: Languages Kotlin Learned From – par Andrey Breslav
Facteurs culturels : soutenir et connecter les développeurs dans leur parcours d’adoption de Kotlin
1. Facilitez l’intégration des nouveaux membres
L’objectif des exemples de code expressifs Java vs Kotlin est de susciter l’intérêt pour Kotlin. Toutefois, le code seul n’est pas suffisant pour convaincre les développeurs Java. Pour accélérer l’adoption et assurer un bon démarrage, fournissez :
- Un exemple de projet : un projet prêt à exécuter avec du code Java et Kotlin côte à côte, offrant aux équipes une référence pratique pendant la migration.
- Des vérifications de qualité intégrées : préconfigurées avec des outils comme SonarQube, ktlint et detekt pour favoriser un code propre, cohérent et maintenable dès le premier jour. Cela vous permettra d’appliquer des règles de linting, des frameworks de tests, des bibliothèques et des pipelines de CI cohérents, afin de réduire les frictions entre les équipes.
- Un accompagnement et du soutien : des ingénieurs Kotlin expérimentés disponibles pour coacher les nouvelles équipes, répondre aux questions et fournir des conseils pratiques durant les premières étapes du développement.
- Ce point est particulièrement important : avec seulement quelques heures de conseils d’un développeur expérimenté d’une autre équipe qui a déjà franchi ces étapes, vous éviterez beaucoup de dégâts et de dette technique.
Quelques mesures de soutien et d’accompagnement sont le moyen le plus efficace de nourrir un enthousiasme durable pour Kotlin.
2. Proposez des ressources d’autoformation
Pour des développeurs Java, l’apprentissage des bases de Kotlin peut se faire de façon autonome. Fournir des ressources en amont facilite le parcours vers une utilisation productive de Kotlin et abaisse les barrières à l’entrée.
- Le « Tour of Kotlin » de JetBrains (Guide de démarrage)
Un court tutoriel basé sur un navigateur sur le site officiel de Kotlin. - Kotlin Koans
Un ensemble de petits défis de programmation maintenus par JetBrains. - Formation « Kotlin Bootcamp for Programmers » sur Udacity
Un cours entièrement en vidéos, créé en partenariat avec Google.
Remarque : bien que l’autoformation soit précieuse pour saisir les bases, elle présente aussi certains inconvénients. L’un de ces inconvénients est son caractère facultatif : pris dans la frénésie du quotidien, il est tentant de négliger l’autoformation. De plus, vous ne bénéficierez pas des retours d’un praticien aguerri, qui maîtrise les subtiles nuances d’un Kotlin idiomatique correctement appliqué. Il y a de fortes chances qu’après un cours d’autoformation, vous écriviez du Kotlin à la manière de Java, ce qui vous apporte certains avantages, mais ne permet pas d’exploiter tout le potentiel du langage.
À moins de bénéficier d’un bon encadrement, un cours classique peut être très bénéfique. Il est nécessaire d’y participer ; vous pourrez échanger avec des pairs de votre niveau et obtenir des réponses à vos questions de la part d’un professionnel expérimenté, ce qui vous permettra d’être opérationnel beaucoup plus rapidement, avec moins de Kotlin non idiomatique lors de la transition initiale.
3. Mettez en place une communauté Kotlin en interne
L’un des moyens les plus rapides d’améliorer l’expertise en Kotlin dans votre entreprise est de créer et, surtout, de faire vivre une communauté interne.
- Lancez une communauté Kotlin en interne
- Première étape : recherchez un noyau d’équipe d’au moins 3 à 6 développeurs désireux de s’investir dans une communauté Kotlin. Assurez-vous également qu’ils bénéficient de temps et de reconnaissance de la part de leurs responsables pour cette tâche.
- Une fois l’équipe constituée, organisez un lancement à l’échelle de l’entreprise avec des intervenants reconnus de la communauté Kotlin. Cela va susciter de l’intérêt pour Kotlin et lancer le mouvement.
- Organisez des rencontres régulières (mensuelles ou bimensuelles) pour maintenir la dynamique.
- Créez un canal de chat ou un wiki partagé pour les questions, les extraits de code et les notes d’événements.
- Invitez des conférenciers (externes)
- Faites venir des ingénieurs ayant déjà déployé Kotlin en production pour partager leurs récits de guerre en toute franchise.
- Alternez entre des présentations techniques approfondies (coroutines, KMP, programmation fonctionnelle) et des études de cas de plus haut niveau (stratégies de migration, astuces concernant les outils).
- Présentez les leçons tirées d’autres projets internes
- Demandez aux chefs de projet de présenter leurs retours d’expérience sur Kotlin : ce qui a fonctionné, ce qui n’a pas fonctionné, et les résultats mesurables.
- Ces informations peuvent être consignées dans un « Guide Kotlin » que les nouvelles équipes pourront consulter.
- Laissez le devant de la scène à vos propres développeurs
- Organisez des sessions courtes lors desquelles chacun peut présenter en 5 à 10 minutes une astuce, une bibliothèque ou une difficulté surmontée.
- Félicitez les contributeurs publiquement – les mentions spéciales lors des réunions générales ou dans les newsletters internes stimulent l’implication et le partage des connaissances.
- Maintenez des boucles de rétroaction courtes
- Après chaque session, organisez des sondages rapides sur leur clarté et leur utilité, puis ajustez les programmes à venir en conséquence.
- Faites tourner les responsabilités organisationnelles pour que la communauté ne dépende pas d’un seul expert et reste résiliente sur le long terme.
Remarque : beaucoup des suggestions ci-dessus semblent simples. Mais il ne faut pas sous-estimer l’effort nécessaire pour maintenir une communauté dynamique et vivante.
4. Soyez patient…
Un changement culturel prend du temps. Le risque, quand on s’enthousiasme à propos d’un outil qui fait une différence pour nous, c’est de pousser les choses, ce qui peut être contre-productif. Une approche efficace consiste à favoriser le processus d’adoption à l’aide de toutes les activités décrites ci-dessus, en gardant à l’esprit qu’une image vaut mieux que mille mots.
Suite de la série
Nous changeons de focus pour parler des moyens de convaincre les décideurs. Le prochain article montre comment construire une analyse de rentabilité convaincante pour l’adoption de Kotlin, à partir de données concrètes et de résultats mesurables. Vous apprendrez à traduire les réussites des développeurs en arguments à l’intention des décideurs, à relier les gains de productivité aux économies de coûts, et à démontrer pourquoi Kotlin est plus qu’une mise à niveau technique ; c’est une décision stratégique, pour les équipes comme pour les entreprises.
Auteurs de l’article original en anglais :

