Kotlin
A concise multiplatform language developed by JetBrains
Como aumentar a adoção do Kotlin na sua empresa
Postagem convidada de Urs Peter, Engenheiro de Software Sênior e Instrutor de Kotlin certificado pela JetBrains. Para leitores que preferirem uma maneira mais estruturada de adquirir conhecimentos sobre Kotlin, Urs também dirige o Programa de Qualificação em Kotlin da Xebia Academy.
Esta é a terceira postagem da série O guia definitivo para a adoção bem-sucedida do Kotlin em um ambiente dominado pelo Java, que acompanha o processo de adoção do Kotlin por equipes reais, desde a curiosidade de um só desenvolvedor até uma transformação geral da empresa.
Todas as partes da série:
- Como iniciar a adoção do Kotlin por desenvolvedores em Java
- Avaliação do Kotlin em projetos reais
- Como aumentar a adoção do Kotlin na sua empresa
Pregando a palavra: ganhe os corações e mentes dos seus colegas desenvolvedores
A esta altura, você já deve ter o núcleo de uma equipe que está convencida dos benefícios do Kotlin. Agora vem a fase crítica: como expandir a adoção?
Nesta fase, o essencial é ganhar os corações e mentes dos desenvolvedores Java céticos. Tanto fatores objetivos quanto subjetivos podem fazer diferença aqui:
Fator objetivo: o código
- Deixe o código falar por si só
Fatores subjetivos: apoie e conecte os desenvolvedores
- Facilite a assimilação
- Ofereça material de autoestudo
- Estabeleça uma comunidade interna de Kotlin
- Tenha paciência…
Deixe o código falar por si só
Dobre a aposta na experiência que você ganhou ao (re)escrever um aplicativo em Kotlin e mostre os benefícios de forma tangível e acessível:
- Não fale, mostre: apresente os ganhos de concisão do Kotlin, comparando trechos de código em Java e em Kotlin.
- Afaste a perspectiva para os paradigmas gerais: o Kotlin não é só diferente do Java; ele foi criado sobre uma base de segurança, concisão visando máxima legibilidade e facilidade de manutenção, extensibilidade e funções tratadas como tendo a mais alta importância. Juntos, esses paradigmas resolvem limitações fundamentais do Java, mas ainda mantêm total interoperabilidade com o ecossistema do Java.
Veja alguns exemplos tangíveis:
1. Segurança contra valores nulos: o fim dos erros de bilhões de dólares
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 😱
Com o tempo, o Java adicionou alguns recursos de segurança contra valores nulos, como “Optional” e “Annotations” (@NotNull, etc.), mas falhou em resolver este problema fundamental. Além disso, o projeto Valhalla (tipos “Null-Restricted” e “Nullable”) não trará segurança contra valores nulos para o Java; apenas dará mais opções de escolha.
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 ✅
A grande coisa a respeito da proteção do Kotlin contra valores nulos é que ela não traz apenas segurança, mas também excelente usabilidade. Veja um exemplo clássico de poder ter tudo ao mesmo tempo:
Vamos supor que temos este domínio:
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));
}
}
Construção de objetos
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)))
Travessia de objetos aninhados
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) //-> "*****"
Desempacotamento de objeto aninhado
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())
}
A falta de proteção contra valores nulos no Java é um dos pontos mais problemáticos para os desenvolvedores e leva a programação defensiva e mais prolixa e a construtos diferentes (ou nenhum) para a possibilidade de valores nulos. Além disso, as “NullPointerExceptions” respondem por cerca de um terço das falhas de aplicativos (blog da JetBrains). No Kotlin, a verificação de valores nulos em tempo de compilação evita completamente essas falhas em tempo de execução. É por isso que até hoje, a segurança contra valores nulos é o principal estímulo para a migração para o Kotlin.
2. Coleções são suas amigas, não suas inimigas
O criador do Spring, Rod Johnson, disse em uma entrevista recente que não foram os tipos “Nullable” que o fizeram experimentar o Kotlin e sim a API complicada demais das Java Streams: Criador do Spring: Nenhuma vontade de programar em Java.
O exemplo a seguir ilustra os vários motivos pelos quais a API das Java Streams é tão horrivelmente complicada e como o Kotlin resolve todos os problemas:
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
}
}
Graças ao framework uniforme de coleções do Kotlin, é muito simples e direto converter entre diferentes tipos de coleções:
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 }
Efeito final:
- API intuitiva e rica em recursos para coleções: os pipelines são lidos da esquerda para a direita, como no inglês, e não dentro de chamadas coletoras aninhadas.
- Menos código repetitivo e menos complexidade: sem Collectors.groupingBy, nem Stream, nem Optional, nem Arrays.stream.
- Um só modelo mental: quer você comece com
List,Set,Arrayou um array primitivo, você sempre procura os mesmos operadores de coleções. - Desempenho sem dor: o compilador insere boxing ou unboxing apenas onde for inevitável; você escreve código normal.
- Segurança integrada contra valores nulos: a API de coleções oferece suporte total a valores nulos, com vários helpers, comumente com o sufixo
orNull(...). - Interoperabilidade transparente com Java, através de wrappers idiomáticos: graças aos métodos de extensão, você fica com “o melhor de dois mundos” — coleções ricas em recursos, além das coleções do Java.
Em termos simples, o Kotlin eleva as tarefas rotineiras com coleções — filtragem, mapeamento, agrupamento, etc. — a funções de primeira categoria que podem ser compostas, para que você expresse o que você quer, em vez da cerimônia de como chegar lá.
3. O Kotlin não tem exceções verificadas, mas o código é mais seguro
O Java é uma das únicas linguagens ainda com suporte a exceções verificadas. Embora essas exceções tenham sido implementadas inicialmente como um recurso de segurança, não corresponderam às expectativas. Sua prolixidade, seus blocos de captura sem sentido, que ou não fazem nada, ou relançam a exceção como uma RuntimeException, e sua falta de alinhamento com lambdas são algumas das razões pelas quais elas atrapalham, em vez de tornar o seu código mais seguro.
O Kotlin segue o paradigma comprovado que é usado por quase todas as outras linguagens de programação — C#, Python, Scala, Rust e Go, de usar exceções apenas em situações sem recuperação.
Os exemplos a seguir destacam os obstáculos que as exceções verificadas introduzem no seu código, sem acrescentar nenhuma segurança:
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. Funções como cidadãs de primeira categoria
O Kotlin trata funções como cidadãs de primeira categoria, o que pode provocar dúvidas para quem vem do Java: o que isso significa e por que isso importa?
A principal diferença está na abordagem limitada do Java: seus recursos funcionais concentram-se, em sua maioria, no local da chamada, através de lambdas, enquanto o lado da declaração fica atado a interfaces funcionais prolixas e menos intuitivas. No Kotlin, é possível definir, passar, retornar e compor funções sem nenhum código repetitivo, tornando a programação funcional muito mais expressiva e natural.
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)}
O Kotlin fornece uma sintaxe clara e concisa para declarar funções: só a partir da assinatura, é possível ver imediatamente o que entra e o que sai, sem ter que navegar até uma interface funcional externa.
O Java “vaza” seus recursos de programação funcional por uma grande quantidade de interfaces java.util.function.* com assinaturas prolixas e complexas. Isso costuma tornar a programação funcional desajeitada de usar. Já o Kotlin trata funções como cidadãs de primeira categoria: essas interfaces ficam ocultas para o desenvolvedor, mas continuam totalmente interoperáveis com a abordagem do Java:

Como resultado, é muito mais simples, direto e intuitivo usar funções no Kotlin. Isso reduz consideravelmente os requisitos para aproveitar esse poderoso conceito de programação no seu próprio código.
5. Concorrência sem dores de cabeça, usando corrotinas
Se você precisar de um alto fluxo de dados, de processamento paralelo em uma só solicitação ou de streaming, a única opção que você tem em Java é usar uma biblioteca reativa, como a Reactor e a RxJava, disponíveis em frameworks como o Spring WebFlux, Vert.X, Quarkus, etc.
O problema dessas bibliotecas é que elas são notoriamente complicadas e forçam você a usar programação funcional. Assim, elas têm uma curva íngreme de aprendizado, mas é muito fácil cometer erros que podem ter consequências graves quando o aplicativo está sobrecarregado. Muito provavelmente, foi por isso que a programação reativa nunca ficou muito popular.
Observação: VirtualThreads não substituem bibliotecas reativas, embora haja alguma sobreposição. VirtualThreads oferecem entrada e saída sem bloqueio, mas não oferecem recursos como processamento paralelo ou streams reativas. Concorrência estruturada e valores com escopo também permitirão processamento paralelo assim que os principais frameworks tiverem suporte a esse recurso. Para streams reativas, você sempre terá que usar uma biblioteca reativa.
Então, vamos supor que você seja um desenvolvedor em Java que usa o Spring Boot e quer fazer uma chamada paralela em uma só solicitação. Você acabará tendo algo assim:
@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()));
);
}
Embora do ponto de vista do tempo de execução esse código funcione perfeitamente, a complexidade acidental introduzida é enorme:
- O código é dominado por
Mono/Fluxem toda a cadeia de chamadas, o que força você a empacotar todos os objetos do domínio. - Por toda parte, há muitos operadores complexos, como
zip,flatMap, etc. - Você não pode usar construtos-padrão de programação, como gerar exceções.
- A intenção de negócios do seu código é significativamente prejudicada: o código concentra-se em
MonoseflatMap, e assim obscurece o que realmente está acontecendo do ponto de vista de negócios.
A boa notícia é que há uma poderosa solução para isso, na forma das corrotinas do Kotlin. Elas podem ser consideradas uma implementação reativa no nível da linguagem. Assim, combinam o melhor de dois mundos:
- Você escreve código sequencial, como fazia antes.
- No momento da execução, o código é executado de forma assíncrona ou em paralelo.
É assim que se parece o código em Java acima, depois de convertido em corrotinas:
@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()))
}
A palavra-chave “suspend”, do Kotlin, permite execução estruturada e sem bloqueios de forma clara e concisa. Juntamente com async{} e await(), ela possibilita o processamento paralelo sem precisar de callbacks profundamente aninhados, nem de construtos complexos, como Mono ou CompletableFuture.
É por isso que a complexidade diminui e a satisfação dos desenvolvedores e a facilidade de manutenção aumentam, com exatamente as mesmas características de desempenho.

Observação: o suporte a corrotinas não é igualmente bom em todos os principais frameworks de Web baseados em Java. O Spring é excelente para isso, assim como o Micronaut, mas no momento, o Quarkus oferece apenas suporte limitado a corrotinas.
6. Mas ei, o Java também está evoluindo!
O Java continua evoluindo, com recursos como records, correspondência de padrões e projetos futuros como Amber, Valhalla e Loom. Essa evolução firme fortalece a JVM e beneficia todo o ecossistema.
Mas o problema é que a maioria desses “novos” recursos do Java são coisas de que os desenvolvedores em Kotlin já vêm desfrutando há anos. Segurança contra valores nulos, classes de valores, funções de nível superior, argumentos-padrão, coleções concisas, funções de primeira linha, tudo isso está incorporado ao projeto do Kotlin e está disponível de uma forma mais unificada e amigável para os desenvolvedores. É por isso que código em Kotlin costuma parecer mais limpo, mais seguro e muito mais produtivo.
E não é só isso: o Kotlin também se beneficia das inovações no Java. Avanços em nível da JVM, como threads virtuais, o Loom em geral ou os aumentos de desempenho do Valhalla, também se aplicam de forma transparente ao Kotlin.
Em resumo: o Java evolui, mas o Kotlin foi projetado desde o primeiro dia para dar aos desenvolvedores as ferramentas modernas de que eles precisam, tornando-o uma escolha segura, moderna e progressista para construir o futuro.

7. A vantagem evolucionária do Kotlin
É inevitável que as linguagens de programação mais antigas carreguem uma bagagem herdada do seu tempo, em comparação com as alternativas modernas. Atualizar uma linguagem e ao mesmo tempo dar suporte a imensas bases de código já existentes traz desafios únicos aos projetistas de linguagens. O Kotlin tem duas vantagens cruciais:
Referências sólidas: em vez de reinventar a roda, a equipe do projeto inicial do Kotlin reuniu paradigmas comprovados de importantes linguagens de programação e os unificou em um todo coeso. Essa abordagem aproveitou ao máximo o aprendizado evolucionário a partir da comunidade mais ampla de programação.
Aprendizado com as limitações do Java: os projetistas do Kotlin puderam observar as armadilhas do Java e desenvolver soluções sólidas do zero.
Para ter insights mais profundos sobre a evolução do Kotlin, veja a excelente palestra que Andrey Breslav, da equipe original de projeto do Kotlin, deu no KotlinDevDay Amsterdam: Shoulders of Giants: Languages Kotlin Learned From (“Sobre os ombros de gigantes: as linguagens das quais o Kotlin aprendeu”).
Fatores subjetivos: apoie e conecte os desenvolvedores em sua jornada de adoção do Kotlin
1. Facilite a assimilação
O objetivo da comparação entre trechos expressivos de código em Java e em Kotlin é abrir o apetite pelo Kotlin. Porém, só o código não é suficiente para ganhar os corações e mentes dos desenvolvedores em Java. Para acelerar a adoção e garantir um início suave, forneça:
- Um projeto de amostra: um projeto pronto para ser executado, com código tanto em Java quanto em Kotlin lado a lado, para dar às equipes uma referência prática durante a migração.
- Verificações de qualidade incorporadas: pré-configuradas com ferramentas como SonarQube, ktlint e detekt, para promover um código limpo, consistente e fácil de manter desde o primeiro dia. Isso permitirá que você aplique regras de lint, frameworks de testes, bibliotecas e pipelines de CI com consistência, para reduzir a fricção em todas as equipes.
- Mentoria e suporte: engenheiros de Kotlin experientes e disponíveis para orientar novas equipes, responder perguntas e dar conselhos práticos nos estágios iniciais do desenvolvimento.
- Este ponto é especialmente importante: com apenas algumas horas de orientação de um desenvolvedor experiente de outra equipe que já tenha passado por esses estágios, pode-se evitar muitos danos e muita dívida técnica.
Um pouco de suporte e mentoria é a maneira mais poderosa de incentivar um entusiasmo duradouro pelo Kotlin.
2. Ofereça material de (auto)estudo
Especialmente para quem vem do Java, é possível aprender o básico do Kotlin por conta própria. Fornecer alguns recursos logo de início facilita o caminho e reduz os requisitos para se tornar produtivo com o Kotlin.
- O “Tour do Kotlin” da JetBrains (guia de introdução)
Um tutorial curto, baseado em navegador, no site oficial do Kotlin. - Kotlin Koans
Um conjunto de pequenos desafios de programação, mantido pela JetBrains. - Udacity “Kotlin Bootcamp for Programmers”
Um curso completo, baseado em vídeo e criado em parceria com o Google.
Observação: Embora o autoestudo seja valioso para aprender o básico, ele também tem algumas desvantagens. Uma delas é sua natureza opcional: ao ficar atarefado na loucura diária, é tentador pular o autoestudo. Além disso, o aprendiz não terá o feedback de um profissional que conheça as nuances sutis do Kotlin idiomático e corretamente aplicado. Há uma grande chance de que, após algum autoestudo, essa pessoa escreva em Kotlin ao estilo do Java, o que trará alguns benefícios, mas não aproveitará todo o potencial da linguagem.
A menos que uma boa mentoria não seja possível, um curso clássico pode ser muito benéfico. Há uma obrigação de comparecer; os alunos podem trocar ideias com colegas do mesmo nível e ter suas perguntas respondidas por um profissional experiente, que desenvolverá suas habilidades com muito mais rapidez e com menos Kotlin não idiomático, durante a transição.
3. Estabeleça uma comunidade interna de Kotlin
Uma das maneiras mais rápidas de aumentar o nível de conhecimento sobre Kotlin em toda a sua empresa é criar e principalmente incentivar uma comunidade interna.
- Crie uma comunidade interna de Kotlin
- Primeiro, procure uma equipe inicial de pelo menos 3–6 desenvolvedores que estejam dispostos a investir em uma comunidade de Kotlin. Também se certifique de que eles tenham tempo e crédito de seus gerentes para essa tarefa.
- Depois que a equipe estiver formada, organize um evento de lançamento para toda a empresa, com palestrantes bem conhecidos na comunidade de Kotlin. Isso acenderá a chama do Kotlin e lhe dará impulso.
- Agende encontros regulares (mensais ou quinzenais), para o impulso nunca arrefecer.
- Crie um canal de chat ou wiki compartilhada, que possa conter perguntas, trechos de código e notas de eventos.
- Convide palestrantes (externos)
- Traga engenheiros que já tenham entregado aplicativos em Kotlin em produção para contar suas histórias de batalha com franqueza.
- Alterne entre conversas profundamente técnicas (corrotinas, KMP, programação funcional) e estudos de casos de nível mais genérico (estratégias de migração, dicas sobre ferramentas).
- Apresente as lições aprendidas de outros projetos da empresa
- Peça a líderes de projetos que apresentem o que aprenderam sobre o Kotlin: o que funcionou ou não e quais foram os desfechos mensuráveis.
- Esses insights podem ser capturados em “regras do jogo com o Kotlin”, que novas equipes podem aproveitar.
- Ponha os seus próprios desenvolvedores no palco
- Faça sessões-relâmpago de conversas, de 5–10 minutos, nas quais qualquer pessoa possa demonstrar um truque interessante, uma biblioteca ou uma falha que ela resolveu.
- Celebre os colaboradores publicamente — menções em reuniões gerais ou boletins internos aumentam o engajamento e o compartilhamento de conhecimentos.
- Tenha pulso firme com os loops de feedback
- Após cada sessão, faça enquetes rápidas sobre a clareza e a utilidade. Depois, ajuste as agendas futuras conforme os resultados.
- Faça um rodízio dos encargos na organização, para que a comunidade não dependa de um só defensor e seja resiliente no longo prazo.
Observação: Muitas das sugestões acima parecem simples e diretas. Porém, não se deve subestimar o esforço necessário para manter uma comunidade vibrante e viva.
4. Tenha paciência…
Mudanças de cultura são demoradas. O perigo de ficar tão entusiasmado com uma ferramenta que faz diferença para você é forçar as coisas, o que pode ser contraproducente. Uma abordagem eficaz é incentivar o processo de adoção com todas as atividades discutidas acima, usando “mostre, não fale” como princípio fundamental.
Em seguida nesta série
Mudaremos o foco de convencer desenvolvedores para persuadir tomadores de decisões. A próxima postagem mostrará como criar um caso convincente de negócios a favor da adoção do Kotlin, baseado em dados reais e desfechos mensuráveis. Você aprenderá como traduzir ganhos para os desenvolvedores em argumentos para a administração, como associar ganhos de produtividade com economia de custos e como demonstrar por que o Kotlin é mais que uma atualização técnica — é uma jogada estratégica tanto para as equipes quanto para as empresas.
Artigo original em inglês por:
